예제 #1
0
def activate_channel_with_cb(channel, cb_addr, do_start=True):
    if channel < 0 or channel > 15:
        raise Exception("Invalid channel index: {}".format(channel))

    if channel < 15:
        ch_base = DMA_BASE_PHYS
    else:
        ch_base = DMA_BASE_CH15_PHYS

    ch_dma_cs = 0x100 * channel + DMA_CS
    ch_dma_debug = 0x100 * channel + DMA_DEBUG
    ch_dma_cb_ad = 0x100 * channel + DMA_CB_AD

    with mu.mmap_dev_mem(ch_base) as dma_mem:
        mu.write_word_to_byte_array(dma_mem, ch_dma_cs, DMA_CS_RESET)
        mu.write_word_to_byte_array(dma_mem, ch_dma_cs,
                                    DMA_CS_INT | DMA_CS_END)
        mu.write_word_to_byte_array(dma_mem, ch_dma_debug,
                                    DMA_DEBUG_CLR_ERRORS)
        mu.write_word_to_byte_array(
            dma_mem, ch_dma_cs, DMA_CS_WAIT_FOR_OUTSTANDING_WRITES
            | DMA_CS_PANIC_PRIORITY | DMA_CS_PRIORITY)
        mu.write_word_to_byte_array(dma_mem, ch_dma_cb_ad, cb_addr)
        if do_start:
            mu.write_word_to_byte_array(dma_mem, ch_dma_cs, DMA_CS_ACTIVE)

    time.sleep(0.1)
예제 #2
0
 def test_activate_channel_with_cb_writes_cb_address_to_cb_address_register(
         self):
     channel = 2
     dma.activate_channel_with_cb(channel, self.cb.addr, False)
     with mu.mmap_dev_mem(dma.DMA_BASE_PHYS) as m:
         channel_offset = 0x100 * channel
         cb_addr_register_offset = channel_offset + dma.DMA_CB_AD
         cb_addr_register = struct.unpack(
             '<L',
             m[cb_addr_register_offset:cb_addr_register_offset + 4])[0]
         self.assertEqual(self.cb.addr, cb_addr_register)
예제 #3
0
    def test_virtual_to_physical_addr(self):
        initial_value = 0
        dummy_item = ctypes.c_int(initial_value)
        virtual_address = ctypes.addressof(dummy_item)
        p_addr_info = mu.virtual_to_physical_addr(virtual_address)
        self.assertEqual(p_addr_info.frame_start + p_addr_info.offset,
                         p_addr_info.p_addr)
        self.assertEqual(initial_value, dummy_item.value)

        new_value = 123
        with mu.mmap_dev_mem(p_addr_info.frame_start) as m:
            m[p_addr_info.offset] = new_value
        self.assertEqual(new_value, dummy_item.value)
예제 #4
0
def set_pins_to_output(gpio_info_list):
    reg_offset_to_value_map = {}
    for gpio_info in gpio_info_list:
        reg_offset = gpio_info.gp_fsel_reg_offset
        current_value = reg_offset_to_value_map.get(reg_offset, 0)
        new_value = current_value | 1 << gpio_info.gp_fsel_bit_shift
        reg_offset_to_value_map[reg_offset] = new_value

    with mu.mmap_dev_mem(GPIO_BASE_PHYS) as m:
        for reg_offset in reg_offset_to_value_map.keys():
            value = reg_offset_to_value_map[reg_offset]
            mu.write_word_to_byte_array(m, reg_offset, value)

    time.sleep(0.1)
예제 #5
0
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)
예제 #6
0
    def test_set_pins_to_output_sets_correct_bits_of_correct_registers(self):
        with mu.mmap_dev_mem(gpio.GPIO_BASE_PHYS) as m:

            # Set all pins in GPFSEL1 register to input (000) and check that the write was successful
            gpfsel1_reg_offset = 0x4
            mu.write_word_to_byte_array(m, gpfsel1_reg_offset, 0)
            gpfsel1_reg_value = struct.unpack(
                '<L', m[gpfsel1_reg_offset:gpfsel1_reg_offset + 4])[0]
            self.assertEqual(0, gpfsel1_reg_value)

            # Set pins 15 and 18 to output and check that the register bits are set as expected
            gpio_info15 = gpio.GpioInfo(15)
            gpio_info18 = gpio.GpioInfo(18)
            gpio.set_pins_to_output([gpio_info15, gpio_info18])
            expected_gpfsel1_reg_value = 1 << 15 | 1 << 24
            gpfsel1_reg_value = struct.unpack(
                '<L', m[gpfsel1_reg_offset:gpfsel1_reg_offset + 4])[0]
            self.assertEqual(expected_gpfsel1_reg_value, gpfsel1_reg_value)
예제 #7
0
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)
예제 #8
0
    def test_activate_channel_with_cb_resets_debug_register_and_clears_errors(
            self):
        channel = 2
        dma.activate_channel_with_cb(channel, self.cb.addr, False)
        with mu.mmap_dev_mem(dma.DMA_BASE_PHYS) as m:
            channel_offset = 0x100 * channel
            debug_register_offset = channel_offset + dma.DMA_DEBUG
            debug_register = struct.unpack(
                '<L', m[debug_register_offset:debug_register_offset + 4])[0]
            self.assertFalse(is_nth_bit_set(debug_register,
                                            0))  # No read last not set error
            self.assertFalse(is_nth_bit_set(debug_register,
                                            1))  # No FIFO error
            self.assertFalse(is_nth_bit_set(debug_register,
                                            2))  # No slave response error

            # Zero outstanding writes
            self.assertFalse(is_nth_bit_set(debug_register, 4))
            self.assertFalse(is_nth_bit_set(debug_register, 5))
            self.assertFalse(is_nth_bit_set(debug_register, 6))
            self.assertFalse(is_nth_bit_set(debug_register, 7))
예제 #9
0
    def test_activate_channel_with_cb_resets_cs_register_and_sets_defaults(
            self):
        channel = 2
        dma.activate_channel_with_cb(channel, self.cb.addr, False)
        with mu.mmap_dev_mem(dma.DMA_BASE_PHYS) as m:
            channel_offset = 0x100 * channel
            cs_register_offset = channel_offset + dma.DMA_CS
            cs_register = struct.unpack(
                '<L', m[cs_register_offset:cs_register_offset + 4])[0]
            self.assertFalse(is_nth_bit_set(cs_register, 0))  # Not active
            self.assertFalse(is_nth_bit_set(
                cs_register, 1))  # No control block has been completed
            self.assertFalse(is_nth_bit_set(
                cs_register, 2))  # Channel has not produced an interrupt
            self.assertFalse(is_nth_bit_set(
                cs_register, 4))  # Not paused, because it hasn't started yet
            self.assertFalse(is_nth_bit_set(cs_register,
                                            5))  # Not paused by DREQ
            self.assertFalse(is_nth_bit_set(
                cs_register, 6))  # Not waiting for any writes to complete
            self.assertFalse(is_nth_bit_set(cs_register,
                                            8))  # No errors detected

            # AXI Priority is 8
            self.assertFalse(is_nth_bit_set(cs_register, 16))
            self.assertFalse(is_nth_bit_set(cs_register, 17))
            self.assertFalse(is_nth_bit_set(cs_register, 18))
            self.assertTrue(is_nth_bit_set(cs_register, 19))

            # AXI Panic Priority is 8
            self.assertFalse(is_nth_bit_set(cs_register, 20))
            self.assertFalse(is_nth_bit_set(cs_register, 21))
            self.assertFalse(is_nth_bit_set(cs_register, 22))
            self.assertTrue(is_nth_bit_set(cs_register, 23))

            self.assertTrue(is_nth_bit_set(
                cs_register,
                28))  # Channel configured to wait for outstanding writes
            self.assertFalse(is_nth_bit_set(
                cs_register, 29))  # Debug pause signal is honored
예제 #10
0
    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