def test_set_transfer_length(self): cb_word_offset = 16 target = dma.ControlBlock(self.mv, cb_word_offset) transfer_length = random.randint(0, 0xFFFFFFFF) target.set_transfer_length(transfer_length) self.assertEqual(transfer_length, self.mv[cb_word_offset + self.OFFSET_WORDS_TXFR_LEN])
def test_set_source_addr(self): cb_word_offset = 16 target = dma.ControlBlock(self.mv, cb_word_offset) source_addr = random.randint(0, 0xFFFFFFFF) target.set_source_addr(source_addr) self.assertEqual(source_addr, self.mv[cb_word_offset + self.OFFSET_WORDS_SRC_ADDR])
def test_set_destination_addr(self): cb_word_offset = 16 target = dma.ControlBlock(self.mv, cb_word_offset) destination_addr = random.randint(0, 0xFFFFFFFF) target.set_destination_addr(destination_addr) self.assertEqual(destination_addr, self.mv[cb_word_offset + self.OFFSET_WORDS_DEST_ADDR])
def test_set_transfer_information(self): cb_word_offset = 16 target = dma.ControlBlock(self.mv, cb_word_offset) transfer_information = random.randint(0, 0xFFFFFFFF) target.set_transfer_information(transfer_information) self.assertEqual(transfer_information, self.mv[cb_word_offset + self.OFFSET_WORDS_TI])
def test_constructor_sets_src_addr_to_an_address_in_shared_memory_of_cb( self): cb_word_offset = 16 dma.ControlBlock(self.mv, cb_word_offset) expected_src_addr = mu.get_mem_view_phys_addr_info( self.mv[cb_word_offset + self.OFFSET_WORDS_DATA_DEFAULT:]).p_addr self.assertEqual(expected_src_addr, self.mv[cb_word_offset + self.OFFSET_WORDS_SRC_ADDR])
def test_set_next_cb_addr(self): cb_word_offset = 16 target = dma.ControlBlock(self.mv, cb_word_offset) next_cb_addr = random.randint(0, 0xFFFFFFFF) target.set_next_cb_addr(next_cb_addr) self.assertEqual( next_cb_addr, self.mv[cb_word_offset + self.OFFSET_WORDS_NEXT_CB_ADDR])
def test_set_stride(self): cb_word_offset = 16 target = dma.ControlBlock(self.mv, cb_word_offset) stride_src = random.randint(0, 0xFFFF) stride_dest = random.randint(0, 0xFFFF) stride = stride_src | stride_dest << 16 target.set_stride(stride_src, stride_dest) self.assertEqual(stride, self.mv[cb_word_offset + self.OFFSET_WORDS_STRIDE])
def test_set_transfer_length_stride(self): cb_word_offset = 16 target = dma.ControlBlock(self.mv, cb_word_offset) transfer_length_x = random.randint(0, 0xFFFF) transfer_length_y = random.randint(0, 0xFFFF) transfer_length = transfer_length_x | (transfer_length_y - 1) << 16 target.set_transfer_length_stride(transfer_length_x, transfer_length_y) self.assertEqual(transfer_length, self.mv[cb_word_offset + self.OFFSET_WORDS_TXFR_LEN])
def test_write_word_to_source_data(self): cb_word_offset = 16 target = dma.ControlBlock(self.mv, cb_word_offset) word = random.randint(0, 0xFFFFFFFF) write_offset_bytes = 3 target.write_word_to_source_data(write_offset_bytes, word) self.assertEqual( word, self.mv[cb_word_offset + int(write_offset_bytes / 4) + self.OFFSET_WORDS_DATA_DEFAULT])
def configure_and_start_pwm(dma_ch, pwm_clk_src, pwm_clk_div_int, pwm_clk_div_frac, pwm_cycles): if pwm_clk_src not in __allowed_clk_src_list: raise Exception("{} is not a valid clock source.".format(pwm_clk_src)) if pwm_clk_div_int < 2: raise Exception("Clock integer divider must be 2 or greater.") if pwm_clk_div_frac < 0 or pwm_clk_div_frac > 4095: raise Exception( "Clock fractional divider must be between 0 (inclusive) and 4095 (inclusive)." ) pwm_period_ns = 1000000000 / CLK_SRC_RATES[pwm_clk_src] * ( (pwm_clk_div_int + pwm_clk_div_frac / 4096) * pwm_cycles) print("Starting PWM with a period of " + str(pwm_period_ns) + " ns.") clk_cb = dma.ControlBlock() clk_cb.set_destination_addr(PWM_CLK_BASE_BUS) clk_cb.set_transfer_information(dma.DMA_TI_NO_WIDE_BURSTS | dma.DMA_TI_WAIT_RESP | dma.DMA_TI_SRC_INC | dma.DMA_TI_DEST_INC) # Stop and configure PWM clock clk_cb.set_transfer_length(8) clk_cb.write_word_to_source_data(PWM_CLK_CTL, PWM_CLK_PWD | pwm_clk_src) clk_cb.write_word_to_source_data( PWM_CLK_DIV, PWM_CLK_PWD | pwm_clk_div_frac | pwm_clk_div_int << 12) dma.activate_channel_with_cb(dma_ch, clk_cb.addr) time.sleep(0.1) # Start PWM clock clk_cb.write_word_to_source_data(PWM_CLK_CTL, PWM_CLK_PWD | pwm_clk_src | PWM_CLK_ENAB) dma.activate_channel_with_cb(dma_ch, clk_cb.addr) time.sleep(0.1) # Configure and start PWM with mu.mmap_dev_mem(PWM_BASE_PHYS) as m: mu.write_word_to_byte_array(m, PWM_CTL, 0) # Reset PWM mu.write_word_to_byte_array(m, PWM_RNG1, pwm_cycles) mu.write_word_to_byte_array(m, PWM_DMAC, PWM_DMAC_ENAB | PWM_DMAC_THRSHLD) mu.write_word_to_byte_array(m, PWM_CTL, PWM_CTL_CLRF) # Clear FIFO mu.write_word_to_byte_array( m, PWM_CTL, PWM_CTL_USEF1 | PWM_CTL_RPTL1 | PWM_CTL_PWEN1) time.sleep(0.1)
def stop_pwm(dma_ch, pwm_clk_src): if pwm_clk_src not in __allowed_clk_src_list: raise Exception("{} is not a valid clock source.".format(pwm_clk_src)) # Reset PWM with mu.mmap_dev_mem(PWM_BASE_PHYS) as m: mu.write_word_to_byte_array(m, PWM_CTL, PWM_CTL_CLRF) # Clear FIFO mu.write_word_to_byte_array(m, PWM_CTL, 0) # Reset PWM time.sleep(0.1) # Stop PWM Clock clk_cb = dma.ControlBlock() clk_cb.set_destination_addr(PWM_CLK_BASE_BUS) clk_cb.set_transfer_information(dma.DMA_TI_NO_WIDE_BURSTS | dma.DMA_TI_WAIT_RESP | dma.DMA_TI_SRC_INC | dma.DMA_TI_DEST_INC) clk_cb.write_word_to_source_data(PWM_CLK_CTL, PWM_CLK_PWD | pwm_clk_src) dma.activate_channel_with_cb(dma_ch, clk_cb.addr) time.sleep(0.1)
def test_constructor_sets_transfer_length_to_one_word_by_default(self): cb_word_offset = 16 dma.ControlBlock(self.mv, cb_word_offset) expected_transfer_length = 4 self.assertEqual(expected_transfer_length, self.mv[cb_word_offset + self.OFFSET_WORDS_TXFR_LEN])
def test_constructor_calculate_correct_cb_address(self): cb_word_offset = 16 target = dma.ControlBlock(self.mv, cb_word_offset) expected_address = mu.get_mem_view_phys_addr_info( self.mv).p_addr + 4 * cb_word_offset self.assertEqual(expected_address, target.addr)
def test_constructor_defaults(self): target = dma.ControlBlock() self.assertEqual(0, target.word_offset) self.assertEqual(16, len(target.shared_mem))
def __init__(self, num_leds, gpio_pins: [gpio.GpioInfo]): self.dma_data = fd.LedDmaFrameData(num_leds) # SET and CLR registers are spaced as follows, spanning 5 registers: # SET SET -- CLR CLR # 1C 20 24 28 2C # MS_MBOX_0 - MS_MBOX_7 are peripheral registers usable for storing this data. # We will only need MS_MBOX_0 - MS_MBOX_4. # The first two registers will be used to always set / clear gpio pins, so the appropriate bits in MS_MBOX_0 and # MS_MBOX_1 should just statically be set for this purpose. MS_MBOX_3 and MS_MBOX_4 will be used for optionally # clearing the GPIO pins. with mu.mmap_dev_mem(MS_BASE) as m: mu.write_word_to_byte_array( m, MS_MBOX_REG_OFFSET + GPIO_INFO_PIN18.set_clr_register_index, 1 << GPIO_INFO_PIN18.pin_flip_bit_shift | 1 << GPIO_INFO_PIN15.pin_flip_bit_shift) # Allocate enough memory for all the CBs. self.shared_mem = mu.create_aligned_phys_contig_int_view(32, 32) # CBs self.cb_idle_wait = dma.ControlBlock() self.cb_idle_clr = dma.ControlBlock() self.cb_data_advance = dma.ControlBlock( self.shared_mem, 0) # Advances own SRC_ADDR and cb_data_upd's SRC_ADDR self.cb_data_upd = dma.ControlBlock( self.shared_mem, 24) # Writes next bit to be copied to GPIO into MS_MBOX self.cb_data_wait1 = dma.ControlBlock() self.cb_data_set_clr = dma.ControlBlock() self.cb_data_wait2 = dma.ControlBlock() self.cb_data_clr = dma.ControlBlock( self.shared_mem, 8) # Clears GPIO pins. Goes to cb_data_advance or cb_pause self.cb_pause = dma.ControlBlock( ) # Resets cb_idle_clr's NEXT_CB_ADDR to get into the idle CB loop # Configure idle loop self.cb_idle_wait.set_transfer_information(DMA_FLAGS_PWM) self.cb_idle_wait.set_destination_addr(pwm.PWM_BASE_BUS + pwm.PWM_FIFO) self.cb_idle_wait.set_next_cb_addr(self.cb_idle_clr.addr) self.cb_idle_clr.set_transfer_information(dma.DMA_TI_SRC_INC | dma.DMA_TI_DEST_INC) self.cb_idle_clr.set_transfer_length(8) self.cb_idle_clr.set_source_addr(MS_BASE_BUS + MS_MBOX_REG_OFFSET) self.cb_idle_clr.set_destination_addr(gpio.GPIO_BASE_BUS + gpio.GPCLR0) self.cb_idle_clr.set_next_cb_addr(self.cb_idle_wait.addr) # Configure data loop cb_data_advance_src_addr = self.cb_data_advance.addr + 0x4 src_stride = 4 dest_stride = 48 self.cb_data_advance.set_transfer_information(dma.DMA_TI_TD_MODE) self.cb_data_advance.set_source_addr(self.dma_data.start_address) self.cb_data_advance.set_destination_addr(cb_data_advance_src_addr) self.cb_data_advance.set_transfer_length_stride(4, 3) self.cb_data_advance.set_stride(src_stride, dest_stride) self.cb_data_advance.set_next_cb_addr(self.cb_data_upd.addr) # writes GPIO CLR data to MS_MBOX_3,4 self.cb_data_upd.set_transfer_information(dma.DMA_TI_SRC_INC | dma.DMA_TI_DEST_INC) self.cb_data_upd.set_transfer_length(8) self.cb_data_upd.set_destination_addr(MS_BASE_BUS + MS_MBOX_REG_OFFSET + 12) self.cb_data_upd.set_next_cb_addr(self.cb_data_wait1.addr) self.cb_data_wait1.set_transfer_information(DMA_FLAGS_PWM) self.cb_data_wait1.set_destination_addr(pwm.PWM_BASE_BUS + pwm.PWM_FIFO) self.cb_data_wait1.set_next_cb_addr(self.cb_data_set_clr.addr) self.cb_data_set_clr.set_transfer_information(dma.DMA_TI_NO_WIDE_BURSTS | dma.DMA_TI_DEST_INC | dma.DMA_TI_SRC_INC | DMA_WAITS) self.cb_data_set_clr.set_transfer_length(20) self.cb_data_set_clr.set_source_addr(MS_BASE_BUS + MS_MBOX_REG_OFFSET) self.cb_data_set_clr.set_destination_addr(gpio.GPIO_BASE_BUS + gpio.GPSET0) self.cb_data_set_clr.set_next_cb_addr(self.cb_data_wait2.addr) self.cb_data_wait2.set_transfer_information(DMA_FLAGS_PWM) self.cb_data_wait2.set_destination_addr(pwm.PWM_BASE_BUS + pwm.PWM_FIFO) self.cb_data_wait2.set_next_cb_addr(self.cb_data_clr.addr) self.cb_data_clr.set_transfer_information(dma.DMA_TI_NO_WIDE_BURSTS | dma.DMA_TI_SRC_INC | dma.DMA_TI_DEST_INC) self.cb_data_clr.set_transfer_length(8) self.cb_data_clr.set_source_addr(MS_BASE_BUS + MS_MBOX_REG_OFFSET) self.cb_data_clr.set_destination_addr(gpio.GPIO_BASE_BUS + gpio.GPCLR0) self.cb_pause.set_transfer_length(4) self.cb_pause.write_word_to_source_data(0, self.cb_idle_wait.addr) self.cb_pause.set_destination_addr(self.cb_idle_clr.addr + 0x14) self.cb_pause.set_next_cb_addr(self.cb_idle_clr.addr) self.dma_data.set_cb_addrs(self.cb_data_advance.addr, self.cb_pause.addr) self.gpio_pins = gpio_pins
def setUp(self): self.cb = dma.ControlBlock()