def __init__(self, pin, cfreq, asize, duty, verbose): if ESP32: self._rmt = RMT(0, pin=pin, clock_div=80, carrier_freq=cfreq, carrier_duty_percent=duty) # 1μs resolution elif RP2: # PIO-based RMT-like device self._rmt = RP2_RMT(pin_pulse=None, carrier=(pin, cfreq, duty)) # 1μs resolution else: # Pyboard if not IR._active_high: duty = 100 - duty tim = Timer(2, freq=cfreq) # Timer 2/pin produces 36/38/40KHz carrier self._ch = tim.channel(1, Timer.PWM, pin=pin) self._ch.pulse_width_percent(self._space) # Turn off IR LED # Pyboard: 0 <= pulse_width_percent <= 100 self._duty = duty self._tim = Timer(5) # Timer 5 controls carrier on/off times self._tcb = self._cb # Pre-allocate self._arr = array('H', 0 for _ in range(asize)) # on/off times (μs) self._mva = memoryview(self._arr) # Subclass interface self.verbose = verbose self.carrier = False # Notional carrier state while encoding biphase self.aptr = 0 # Index into array
class Pixels: def __init__(self, pin, pixel_count, rmt_channel=1): self.rmt = RMT(rmt_channel, pin, clock_div=4) # pixels stores the data sent out via RMT self.pixels = [self.encode_pixel(0, 0, 0)] * pixel_count # colors is only used for __getitem__ self.colors = [(0, 0, 0)] * pixel_count def encode_pixel(self, r, g, b): i_24 = (g & 0xFF) << 16 | (r & 0xFF) << 8 | (b & 0xFF) # This can probably be faster or better or something. #VersionZeroPointZero. bits = '{0:024b}'.format(i_24) bits = map(lambda i: D_ZERO if i == '0' else D_ONE, bits) return tuple(clocks for bit in bits for clocks in bit) def set(self, pixel, r, g, b): self.colors[pixel] = (r, g, b) self.pixels[pixel] = self.encode_pixel(r, g, b) def write(self): # The bus should be idle low ( I think... ) # So we finish low and start high. pulses = tuple() for pixel in self.pixels: pulses += pixel pulses = pulses[:-1] + (T_RST,) # The last low should be long. self.rmt.write_pulses(pulses, start=1) # pixels[0] = (r, g, b) def __setitem__(self, pixel_index, pixel_set): self.set(pixel_index, *pixel_set) def __getitem__(self, pixel_index): return self.colors[pixel_index]
def __init__(self, pin, fname, reps=5): self._pin = pin self._reps = reps with open(fname, 'r') as f: self._data = ujson.load(f) # Time to wait between nonblocking transmissions. A conservative value in ms. self._latency = (reps + 2) * max( (sum(x) for x in self._data.values())) // 1000 gc.collect() if ESP32: self._rmt = RMT(0, pin=pin, clock_div=80) # 1μs resolution elif RP2: # PIO-based RMT-like device self._rmt = RP2_RMT(pin_pulse=pin) # 1μs resolution # Array size: length of longest entry + 1 for STOP asize = max([len(x) for x in self._data.values()]) + 1 self._arr = array('H', (0 for _ in range(asize))) # on/off times (μs) else: # Pyboard self._tim = Timer(5) # Timer 5 controls carrier on/off times self._tcb = self._cb # Pre-allocate asize = reps * max([len(x) for x in self._data.values() ]) + 1 # Array size self._arr = array('H', (0 for _ in range(asize))) # on/off times (μs) self._aptr = 0 # Index into array
def __init__(self, pin, pixel_count, rmt_channel=1, pixel_channels=3): self.rmt = RMT(rmt_channel, pin=pin, clock_div=4) # pixels stores the data sent out via RMT self.channels = pixel_channels single_pixel = (0, ) * pixel_channels self.pixels = [D_ZERO * (pixel_channels * CHANNEL_WIDTH)] * pixel_count # colors is only used for __getitem__ self.colors = [single_pixel] * pixel_count
def __init__(self, pwm_pin, freq=5000, duty=512): for idx in range(len(PWM.RMT_channels)): if not PWM.RMT_channels[idx]: # find free channel PWM.RMT_channels[idx] = True # mark used cnannel self.RMT_channel = idx # keep the channel number self.RMT_obj = RMT(idx, pin=pwm_pin, clock_div=80) self.pwm_duty = 512 self.pwm_freq = 5000 self.init(freq, duty) break else: raise RuntimeError('No RMT channel available.')
def send_command(add, com, comn=None): ''' Sends command on IR input is address and command ''' # RMT(channel=0, pin=4, source_freq=80000000, clock_div=24, carrier_freq=38222, carrier_duty_percent=50) remote = RMT(0, pin=Pin(4), clock_div=24, carrier_freq=38222) lst = list() add_leadpulse(lst) send_byte(add, lst) send_byte(~add, lst) send_byte(com, lst) # I identified some keys on Yamaha remote did not send exact invert of command, instead some bits were peculiar. # This deviated from NEC protocol, but work around was simple. # If peculiar code is present that's sent, otherwise inverted code is sent. if comn is None: send_byte(~com, lst) else: send_byte(comn, lst) add_endpulse(lst) remote.write_pulses(lst, start=1) remote.wait_done() del lst # Without deinit and reinitializing remote after every use, second use of remote will hang it. # This issue may have been resolved in MicroPython 1.13 or later. Not tested. # However using below command is a workaround that works :) remote.deinit()
class PWM(): # free RMT channel table RMT_channels = [False, False, False, False, False, False, False, False] def __init__(self, pwm_pin, freq=5000, duty=512): for idx in range(len(PWM.RMT_channels)): if not PWM.RMT_channels[idx]: # find free channel PWM.RMT_channels[idx] = True # mark used cnannel self.RMT_channel = idx # keep the channel number self.RMT_obj = RMT(idx, pin=pwm_pin, clock_div=80) self.pwm_duty = 512 self.pwm_freq = 5000 self.init(freq, duty) break else: raise RuntimeError('No RMT channel available.') def run(self): period = 1000000 / (self.pwm_freq) up_time = round(period * (self.pwm_duty / 1023)) down_time = round(period) - up_time self.RMT_obj.loop(False) self.RMT_obj.write_pulses((up_time, down_time), start=1) self.RMT_obj.loop(True) # MicroPython 1.13 requires loop() running before write_pulses() # MicroPython 1.12 would report error if loop() runs before any write_pulses() self.RMT_obj.write_pulses((up_time, down_time), start=1) def freq(self, new_freq): self.pwm_freq = new_freq if new_freq > 15 else 16 self.run() def duty(self, new_duty): self.pwm_duty = new_duty if new_duty < 1023 else 1023 self.run() def deinit(self): self.RMT_obj.deinit() PWM.RMT_channels[self.RMT_channel] = False def init(self, freq=5000, duty=512): self.freq(freq) self.duty(duty)
def __init__(self, pin, fname, reps=5): self._pin = pin self._reps = reps try: with open(fname, 'r') as f: self._data = ujson.load(f) except OSError: print("Can't open file '{}' for reading.".format(fname)) return gc.collect() if ESP32: self._rmt = RMT(0, pin=pin, clock_div=80) # 1μs resolution else: # Pyboard self._tim = Timer(5) # Timer 5 controls carrier on/off times self._tcb = self._cb # Pre-allocate asize = reps * max([len(x) for x in self._data.values() ]) + 1 # Array size self._arr = array('H', 0 for _ in range(asize)) # on/off times (μs) self._aptr = 0 # Index into array
def __init__(self, pin, freq=50, duty=0, verbose=False, channel=-1): if channel in [i for i in range(RMT_MAX_CHAN)]: self._chanRMT = channel self._pin = RMT(channel, pin=Pin(pin), clock_div=RMT_CLOCK_DIV) self.__setRMTDuty(duty) self._pin.loop(True) else: self._chanRMT = -1 self._pin = PWM(Pin(pin)) self._pin.init(freq=freq, duty=duty) self._verbose = verbose if self._verbose: self.__logFrequency()
def __init__(self, pin, cfreq, asize, duty, verbose): if ESP32: self._pwm = PWM(pin[0]) # Continuous 36/38/40KHz carrier self._pwm.deinit() # ESP32: 0 <= duty <= 1023 self._pwm.init(freq=cfreq, duty=round(duty * 10.23)) self._rmt = RMT(0, pin=pin[1], clock_div=80) # 1μs resolution else: # Pyboard if not IR._active_high: duty = 100 - duty tim = Timer(2, freq=cfreq) # Timer 2/pin produces 36/38/40KHz carrier self._ch = tim.channel(1, Timer.PWM, pin=pin) self._ch.pulse_width_percent(self._space) # Turn off IR LED # Pyboard: 0 <= pulse_width_percent <= 100 self._duty = duty self._tim = Timer(5) # Timer 5 controls carrier on/off times self._tcb = self._cb # Pre-allocate self._arr = array('H', 0 for _ in range(asize)) # on/off times (μs) self._mva = memoryview(self._arr) # Subclass interface self.verbose = verbose self.carrier = False # Notional carrier state while encoding biphase self.aptr = 0 # Index into array
def __init__(self, pin: Pin, rmt: RMT = None, rmt_number: int = 0, carrier_freq: int = 38000) -> None: self.pin = pin if rmt is None: rmt = RMT(rmt_number, pin=self.pin, clock_div=80, carrier_freq=carrier_freq) self.rmt = rmt self.reset()
def __init__(self, pin, pixel_count, rmt_channel=1): self.rmt = RMT(rmt_channel, pin, clock_div=4) # pixels stores the data sent out via RMT self.pixels = [self.encode_pixel(0, 0, 0)] * pixel_count # colors is only used for __getitem__ self.colors = [(0, 0, 0)] * pixel_count
def STCP_puls(): stcp.off() sleep_us(20) stcp.on() def refresh(): return r.write_pulses((1, ), start=1) spi = SPI(2, baudrate=115200, polarity=1, phase=1, bits=8, firstbit=1, sck=Pin(18), mosi=Pin(23), miso=Pin(19)) spi.init(baudrate=115200) en = Pin(22, Pin.OUT, 0) stcp = Pin(21, Pin.OUT, 0) r = RMT(0, pin=Pin(17), clock_div=8) while True: print("write") spi.write(bytes([0b10000000])) # STCP_puls() refresh() sleep_ms(500) break
class IR: _active_high = True # Hardware turns IRLED on if pin goes high. _space = 0 # Duty ratio that causes IRLED to be off timeit = False # Print timing info @classmethod def active_low(cls): if ESP32: raise ValueError('Cannot set active low on ESP32') cls._active_high = False cls._space = 100 def __init__(self, pin, cfreq, asize, duty, verbose): if ESP32: self._rmt = RMT(0, pin=pin, clock_div=80, carrier_freq=cfreq, carrier_duty_percent=duty) # 1μs resolution elif RP2: # PIO-based RMT-like device self._rmt = RP2_RMT(pin_pulse=None, carrier=(pin, cfreq, duty)) # 1μs resolution else: # Pyboard if not IR._active_high: duty = 100 - duty tim = Timer(2, freq=cfreq) # Timer 2/pin produces 36/38/40KHz carrier self._ch = tim.channel(1, Timer.PWM, pin=pin) self._ch.pulse_width_percent(self._space) # Turn off IR LED # Pyboard: 0 <= pulse_width_percent <= 100 self._duty = duty self._tim = Timer(5) # Timer 5 controls carrier on/off times self._tcb = self._cb # Pre-allocate self._arr = array('H', 0 for _ in range(asize)) # on/off times (μs) self._mva = memoryview(self._arr) # Subclass interface self.verbose = verbose self.carrier = False # Notional carrier state while encoding biphase self.aptr = 0 # Index into array def _cb(self, t): # T5 callback, generate a carrier mark or space t.deinit() p = self.aptr v = self._arr[p] if v == STOP: self._ch.pulse_width_percent(self._space) # Turn off IR LED. return self._ch.pulse_width_percent(self._space if p & 1 else self._duty) self._tim.init(prescaler=84, period=v, callback=self._tcb) self.aptr += 1 # Public interface # Before populating array, zero pointer, set notional carrier state (off). def transmit(self, addr, data, toggle=0, validate=False): # NEC: toggle is unused t = ticks_us() if validate: if addr > self.valid[0] or addr < 0: raise ValueError('Address out of range', addr) if data > self.valid[1] or data < 0: raise ValueError('Data out of range', data) if toggle > self.valid[2] or toggle < 0: raise ValueError('Toggle out of range', toggle) self.aptr = 0 # Inital conditions for tx: index into array self.carrier = False self.tx(addr, data, toggle) # Subclass populates ._arr self.trigger() # Initiate transmission if self.timeit: dt = ticks_diff(ticks_us(), t) print('Time = {}μs'.format(dt)) # Subclass interface def trigger(self): # Used by NEC to initiate a repeat frame if ESP32: self._rmt.write_pulses(tuple(self._mva[0:self.aptr]), start=1) elif RP2: self.append(STOP) self._rmt.send(self._arr) else: self.append(STOP) self.aptr = 0 # Reset pointer self._cb(self._tim) # Initiate physical transmission. def append(self, *times): # Append one or more time peiods to ._arr for t in times: self._arr[self.aptr] = t self.aptr += 1 self.carrier = not self.carrier # Keep track of carrier state self.verbose and print('append', t, 'carrier', self.carrier) def add(self, t): # Increase last time value (for biphase) assert t > 0 self.verbose and print('add', t) # .carrier unaffected self._arr[self.aptr - 1] += t
def __init__(self, pin, pixel_count, rmt_channel=1, pixel_channels=3): self.rmt = RMT(rmt_channel, pin=pin, clock_div=4) self.pixelPulseLen = CHANNEL_WIDTH * pixel_channels * 2 # pixels stores the data sent out via RMT self.pixels = D_ZERO * (pixel_channels * CHANNEL_WIDTH * pixel_count) + (T_RST, )
class Pixels: @micropython.native def __init__(self, pin, pixel_count, rmt_channel=1, pixel_channels=3): self.rmt = RMT(rmt_channel, pin=pin, clock_div=4) self.pixelPulseLen = CHANNEL_WIDTH * pixel_channels * 2 # pixels stores the data sent out via RMT self.pixels = D_ZERO * (pixel_channels * CHANNEL_WIDTH * pixel_count) + (T_RST, ) # colors is only used for __getitem__ @micropython.viper def write(self): # The bus should be idle low ( I think... ) # So we finish low and start high. #pulses = tuple() #print("Before write: ") #print(self.pixels) #startTime=time.ticks_us() self.rmt.write_pulses(self.pixels, start=1) #self.rmt.write_pulses(self.pixelByteArr, start=1) #stopTime=time.ticks_us() #print ("RMT write took: " + str(stopTime-startTime)) #print("after write; ") #print(self.pixels) #@micropython.viper def __setitem__(self, pixel_index, colors): #startTime=time.ticks_us() # pixels[0] = (r, g, b) pulseIndex = int(0) pxl = bytearray(self.pixelPulseLen) #print("comparing") for color in colors: #print("Color: " + str(color)) colorInt = int(color) for bits in range(CHANNEL_WIDTH): #print(bin(colorInt)) bit = colorInt & 128 #print("Bit" + str(bit)) if bit: #print("1", end="") pxl[pulseIndex] = T_1H pxl[pulseIndex + 1] = T_1L else: #print("0", end="") pxl[pulseIndex] = T_0H pxl[pulseIndex + 1] = T_0L colorInt = colorInt << 1 pulseIndex += 2 #print("") pxlTup = tuple(pxl) pulseIndex = int(pixel_index * self.pixelPulseLen) #self.insertPxl(pulseIndex, pxlTup) #print(pxlTup) #ref_pixel = tuple(clocks for bit in (D_ONE if ((channel >> bit) & 1) else D_ZERO for channel in colors for bit in range(CHANNEL_WIDTH - 1, -1, -1)) for clocks in bit) #cnt=0 #while(cnt < len(ref_pixel)): #if ref_pixel[cnt] == 16 and ref_pixel[cnt+1] == 9 : print("1", end="") #elif ref_pixel[cnt] == 8 and ref_pixel[cnt+1] == 17 : print("0", end="") #else: print("x") #cnt +=2 #print("") #clocks for bit in ( #D_ONE if ((channel >> bit) & 1) #else D_ZERO #for channel in colors # for bit in range(CHANNEL_WIDTH - 1, -1, -1)): # for clocks in bit: #for color in colors: # colorInt=int(color) # for bits in range(CHANNEL_WIDTH): # bit = colorInt & 1 # if bit == 1: # pxl = pxl + D_ONE # else: # pxl = pxl + D_ZERO # colorInt = colorInt >> 1 #self.insertPxl(pulseIndex, pxl) #self.pixels = self.pixels[:pulseIndex] + pxl + self.pixels[(pulseIndex+self.pixelPulseLen):] #self_pixels = self_pixels[:pulseIndex] + tuple(clocks for bit in (D_ONE if ((channel >> bit) & 1) else D_ZERO for channel in colors for bit in range(CHANNEL_WIDTH - 1, -1, -1)) for clocks in bit) + self_pixels[(pulseIndex+self.pixelPulseLen):] self.pixels = self.pixels[:pulseIndex] + tuple( clocks for bit in (D_ONE if ((channel >> bit) & 1) else D_ZERO for channel in colors for bit in range(CHANNEL_WIDTH - 1, -1, -1)) for clocks in bit) + self.pixels[(pulseIndex + self.pixelPulseLen):] #self.pixels = self_pixels #pixelLst = list(self.pixels) #pixelLst[pulseIndex:(pulseIndex+self.pixelPulseLen)] = list(clocks for bit in (D_ONE if ((channel >> bit) & 1) else D_ZERO for channel in colors for bit in range(CHANNEL_WIDTH - 1, -1, -1)) for clocks in bit) #self.pixels = tuple(pixelLst) #stopTime=time.ticks_us() #print ("__setitem__ took: " + str(stopTime-startTime)) #print("after ´__setitems__") #print(self.pixels) @micropython.native def insertPxl(self, index, pxl): self.pixels = self.pixels[:index] + pxl + self.pixels[ (index + self.pixelPulseLen):]
class Pixels: def __init__(self, pin, pixel_count, rmt_channel=1, pixel_channels=3): self.rmt = RMT(rmt_channel, pin=pin, clock_div=4) # pixels stores the data sent out via RMT self.channels = pixel_channels single_pixel = (0, ) * pixel_channels self.pixels = [D_ZERO * (pixel_channels * CHANNEL_WIDTH)] * pixel_count # colors is only used for __getitem__ self.colors = [single_pixel] * pixel_count def write(self): # The bus should be idle low ( I think... ) # So we finish low and start high. pulses = tuple() for pixel in self.pixels: pulses += pixel pulses = pulses[:-1] + (T_RST, ) # The last low should be long. self.rmt.write_pulses(pulses, start=1) def __setitem__(self, pixel_index, colors): self_colors = self.colors self_pixels = self.pixels if isinstance(pixel_index, int): # pixels[0] = (r, g, b) self_colors[pixel_index] = tuple(colors) self_pixels[pixel_index] = tuple( clocks for bit in (D_ONE if ((channel >> bit) & 1) else D_ZERO for channel in colors for bit in range(CHANNEL_WIDTH - 1, -1, -1)) for clocks in bit) elif isinstance(pixel_index, slice): start = 0 if pixel_index.start is None else pixel_index.start stop = len( self.pixels) if pixel_index.stop is None else pixel_index.stop step = 1 if pixel_index.step is None else pixel_index.step # Assume that if the first colors element is an int, then its not a sequence # Otherwise always assume its a sequence of colors if isinstance(colors[0], int): # pixels[:] = (r,g,b) for index in range(start, stop, step): self_colors[index] = tuple(colors) self_pixels[index] = tuple( clocks for bit in (D_ONE if ((channel >> bit) & 1) else D_ZERO for channel in colors for bit in range(CHANNEL_WIDTH - 1, -1, -1)) for clocks in bit) else: # pixels[:] = [(r,g,b), ...] # Assume its a sequence, make it a list so we know the length if not isinstance(colors, list): colors = list(colors) color_length = len(colors) for index in range(start, stop, step): color = colors[(index - start) % color_length] self_colors[index] = tuple(color) self_pixels[index] = tuple( clocks for bit in (D_ONE if ((channel >> bit) & 1) else D_ZERO for channel in color for bit in range(CHANNEL_WIDTH - 1, -1, -1)) for clocks in bit) else: raise TypeError('Unsupported pixel_index {} ({})'.format( pixel_index, type(pixel_index))) def __getitem__(self, pixel_index): # slice instances are passed through return self.colors[pixel_index]
sendtime=bytearray(8) # second counter 0-59 second=bytearray(1) # TX bits for one minute minute=bytearray(59) # index for writing to minute[] index=bytearray(1) # 1-second timer timer=Timer(3) # last day NTP was set ntpday=0 led=Pin(2,Pin.OUT) antena=Pin(15,Pin.OUT) ask=RMT(0,pin=antena,carrier_freq=0,clock_div=1) # 80 MHz ask.loop(True) if disp: import ssd1306 i2c = I2C(scl=Pin(4), sda=Pin(5)) oled = ssd1306.SSD1306_I2C(128, 64, i2c, 0x3c) oled.fill(0) oled.text("DCF77", 0, 0) oled.show() weekdaystr = ["MO","TU","WE","TH","FR","SA","SU"] # desired carrier frequency freq=77500 # tuning paramters - adjust with scope
class TX: timeit = False # Print timing info _active_high = True @classmethod def active_low(cls): if ESP32: raise ValueError('Cannot set active low on ESP32') cls._active_high = False def __init__(self, pin, fname, reps=5): self._pin = pin self._reps = reps try: with open(fname, 'r') as f: self._data = ujson.load(f) except OSError: print("Can't open file '{}' for reading.".format(fname)) return gc.collect() if ESP32: self._rmt = RMT(0, pin=pin, clock_div=80) # 1μs resolution else: # Pyboard self._tim = Timer(5) # Timer 5 controls carrier on/off times self._tcb = self._cb # Pre-allocate asize = reps * max([len(x) for x in self._data.values() ]) + 1 # Array size self._arr = array('H', 0 for _ in range(asize)) # on/off times (μs) self._aptr = 0 # Index into array def _cb(self, t): # T5 callback, generate a carrier mark or space t.deinit() p = self._aptr v = self._arr[p] if v == STOP: self._pin(self._active_high ^ 1) return self._pin(p & 1 ^ self._active_high) self._tim.init(prescaler=84, period=v, callback=self._tcb) self._aptr += 1 def __getitem__(self, key): if key in self._data: return self._data[key] print('Key "{}" does not exist'.format(key)) def keys(self): return self._data.keys() def show(self, key): res = self[key] if res is not None: for x, t in enumerate(res): print('{:3d} {:6d}'.format(x, t)) # Nonblocking transmit def __call__(self, key): gc.collect() lst = self[key] if lst is not None: lst = lst * self._reps if ESP32: self._rmt.write_pulses(lst, start=1) # Active high else: for x, t in enumerate(lst): self._arr[x] = t x += 1 self._arr[x] = STOP self._aptr = 0 # Reset pointer self._cb(self._tim) # Initiate physical transmission. # Blocking transmit: proved necessary on Pyboard Lite @micropython.native def send(self, key): gc.collect() pin = self._pin q = self._active_high ^ 1 # Pin inactive state lst = self[key] if lst is not None: for _ in range(self._reps): pin(q) for t in lst: pin(pin() ^ 1) sleep_us(t) pin(q)
class TX: _active_high = True @classmethod def active_low(cls): if ESP32: raise ValueError('Cannot set active low on ESP32') cls._active_high = False def __init__(self, pin, fname, reps=5): self._pin = pin self._reps = reps with open(fname, 'r') as f: self._data = ujson.load(f) # Time to wait between nonblocking transmissions. A conservative value in ms. self._latency = (reps + 2) * max( (sum(x) for x in self._data.values())) // 1000 gc.collect() if ESP32: self._rmt = RMT(0, pin=pin, clock_div=80) # 1μs resolution elif RP2: # PIO-based RMT-like device self._rmt = RP2_RMT(pin_pulse=pin) # 1μs resolution # Array size: length of longest entry + 1 for STOP asize = max([len(x) for x in self._data.values()]) + 1 self._arr = array('H', (0 for _ in range(asize))) # on/off times (μs) else: # Pyboard self._tim = Timer(5) # Timer 5 controls carrier on/off times self._tcb = self._cb # Pre-allocate asize = reps * max([len(x) for x in self._data.values() ]) + 1 # Array size self._arr = array('H', (0 for _ in range(asize))) # on/off times (μs) self._aptr = 0 # Index into array def _cb(self, t): # T5 callback, generate a carrier mark or space t.deinit() p = self._aptr v = self._arr[p] if v == STOP: self._pin(self._active_high ^ 1) return self._pin(p & 1 ^ self._active_high) self._tim.init(prescaler=84, period=v, callback=self._tcb) self._aptr += 1 def __getitem__(self, key): return self._data[key] def keys(self): return self._data.keys() def show(self, key): res = self[key] if res is not None: for x, t in enumerate(res): print('{:3d} {:6d}'.format(x, t)) def latency(self): return self._latency # Nonblocking transmit def __call__(self, key): gc.collect() lst = self[key] if lst is not None: if ESP32: # TODO use RMT.loop() cancelled by a soft timer to do reps. # This would save RAM. RMT.loop() is now fixed. I remain # unconvinced because of the huge latency of soft timers on # boards with SPIRAM. It would save ram if a half-word array # could be passed. But it can't (as of 9th March 2021). self._rmt.write_pulses(lst * self._reps, start=1) # Active high elif RP2: for x, t in enumerate(lst): self._arr[x] = t self._arr[x + 1] = STOP self._rmt.send(self._arr, self._reps) else: x = 0 for _ in range(self._reps): for t in lst: self._arr[x] = t x += 1 self._arr[x] = STOP self._aptr = 0 # Reset pointer self._cb(self._tim) # Initiate physical transmission. # Blocking transmit: proved necessary on Pyboard Lite @micropython.native def send(self, key): gc.collect() pin = self._pin q = self._active_high ^ 1 # Pin inactive state lst = self[key] if lst is not None: for _ in range(self._reps): pin(q) for t in lst: pin(pin() ^ 1) sleep_us(t) pin(q)