Wiznet makers

Aimee0

Published April 23, 2024 ©

17 UCC

12 WCC

8 VAR

0 Contests

0 Followers

0 Following

RP2040 PIO QSPI

This is about the QSPI driver using the PIO program of RP2040.

COMPONENTS
PROJECT DESCRIPTION

This content is about implementing and testing a QSPI driver using the versatile hardware interface, PIO, on the RP2040 microcontroller.

PIO?

PIO (Pulse-Width Modulator) is a versatile I/O programming interface built into the RP2040 chip on the Raspberry Pi Pico. It allows users to define and control various protocols and interfaces through software. PIO supports complex serial and parallel communication with high-speed and precise timing control.


Quad SPI?


Quad SPI (QSPI) is an extended version of the Serial Peripheral Interface (SPI) that uses four data lines to transmit data simultaneously. This enables high-speed data transfer and is commonly used for communication with external devices such as flash memory.

Quad SPI using PIO

  • *.pio file

  • write func
void wizchip_pio_spi_write_byte(uint8_t op_code, uint16_t AddrSel, uint8_t *tx, uint16_t tx_length)  
{
  uint32_t command = ( (uint32_t)op_code & 0x000000FF ) | ( ((uint32_t)AddrSel << 8) & 0x00ffff00 ) ;
  uint8_t command_buf[16] = {0,};
  tx_length = tx_length + 16;

  ex_command_buf((uint8_t *)&command, command_buf);

  pio_sm_set_enabled(active_state->pio, active_state->pio_sm, false);
  pio_sm_set_wrap(active_state->pio, active_state->pio_sm, active_state->pio_offset, active_state->pio_offset + PIO_SPI_OFFSET_WRITE_BITS_END - 1);
  pio_sm_clear_fifos(active_state->pio, active_state->pio_sm);

  pio_sm_set_pindirs_with_mask(active_state->pio,
                                active_state->pio_sm,
                                (1u << active_state->pio_spi_config->data_io0_pin) | (1u << active_state->pio_spi_config->data_io1_pin) | (1u << active_state->pio_spi_config->data_io2_pin) | (1u << active_state->pio_spi_config->data_io3_pin),
                                (1u << active_state->pio_spi_config->data_io0_pin) | (1u << active_state->pio_spi_config->data_io1_pin) | (1u << active_state->pio_spi_config->data_io2_pin) | (1u << active_state->pio_spi_config->data_io3_pin));

  pio_sm_restart(active_state->pio, active_state->pio_sm);
  pio_sm_clkdiv_restart(active_state->pio, active_state->pio_sm);
  pio_sm_put(active_state->pio, active_state->pio_sm, tx_length * 2 - 1);
  pio_sm_exec(active_state->pio, active_state->pio_sm, pio_encode_out(pio_x, 32));
  pio_sm_put(active_state->pio, active_state->pio_sm, 0);
  pio_sm_exec(active_state->pio, active_state->pio_sm, pio_encode_out(pio_y, 32));
  pio_sm_exec(active_state->pio, active_state->pio_sm, pio_encode_jmp(active_state->pio_offset));
  dma_channel_abort(active_state->dma_out);

  out_config = dma_channel_get_default_config(active_state->dma_out);
  channel_config_set_transfer_data_size(&out_config, DMA_SIZE_8);
  channel_config_set_bswap(&out_config, true);
  channel_config_set_dreq(&out_config, pio_get_dreq(active_state->pio, active_state->pio_sm, true));

  wizchip_pio_spi_frame_start();

  pio_sm_set_enabled(active_state->pio, active_state->pio_sm, true);

  dma_channel_configure(active_state->dma_out, &out_config, &active_state->pio->txf[active_state->pio_sm], command_buf, 16, true);
  dma_channel_wait_for_finish_blocking(active_state->dma_out);

  dma_channel_configure(active_state->dma_out, &out_config, &active_state->pio->txf[active_state->pio_sm], tx, tx_length - 16, true);
  
  uint32_t fdebug_tx_stall = 1u << (PIO_FDEBUG_TXSTALL_LSB + active_state->pio_sm);
  active_state->pio->fdebug = fdebug_tx_stall;
  
  while (!(active_state->pio->fdebug & fdebug_tx_stall))
  {
    tight_loop_contents(); // todo timeout
  }
  __compiler_memory_barrier();

  pio_sm_set_enabled(active_state->pio, active_state->pio_sm, false);
  pio_sm_set_consecutive_pindirs(active_state->pio, active_state->pio_sm, active_state->pio_spi_config->data_io0_pin, 4, false);
  pio_sm_exec(active_state->pio, active_state->pio_sm, pio_encode_mov(pio_pins, pio_null)); 
  wizchip_pio_spi_frame_end();
}
  • read func
void wizchip_pio_spi_read_byte(uint8_t op_code, uint16_t AddrSel, uint8_t *rx, uint16_t rx_length) 
{
  uint32_t command = ( (uint32_t)op_code & 0x000000FF ) | ( ((uint32_t)AddrSel << 8) & 0x00ffff00 ) ;
  uint8_t command_buf[16] = {0,};
  uint16_t tx_length = 16;

  ex_command_buf((uint8_t *)&command, command_buf);

  pio_sm_set_enabled(active_state->pio, active_state->pio_sm, false);
  pio_sm_set_wrap(active_state->pio, active_state->pio_sm, active_state->pio_offset, active_state->pio_offset + PIO_SPI_OFFSET_READ_BITS_END - 1);
  pio_sm_clear_fifos(active_state->pio, active_state->pio_sm);

  pio_sm_set_pindirs_with_mask(active_state->pio,
                                active_state->pio_sm,
                                (1u << active_state->pio_spi_config->data_io0_pin) | (1u << active_state->pio_spi_config->data_io1_pin) | (1u << active_state->pio_spi_config->data_io2_pin) | (1u << active_state->pio_spi_config->data_io3_pin),
                                (1u << active_state->pio_spi_config->data_io0_pin) | (1u << active_state->pio_spi_config->data_io1_pin) | (1u << active_state->pio_spi_config->data_io2_pin) | (1u << active_state->pio_spi_config->data_io3_pin));

  pio_sm_restart(active_state->pio, active_state->pio_sm);
  pio_sm_clkdiv_restart(active_state->pio, active_state->pio_sm);

  pio_sm_put(active_state->pio, active_state->pio_sm, tx_length * 2 - 1);  
  pio_sm_exec(active_state->pio, active_state->pio_sm, pio_encode_out(pio_x, 32));

  pio_sm_put(active_state->pio, active_state->pio_sm, rx_length * 2 - 1);
  pio_sm_exec(active_state->pio, active_state->pio_sm, pio_encode_out(pio_y, 32));

  pio_sm_exec(active_state->pio, active_state->pio_sm, pio_encode_jmp(active_state->pio_offset));

  dma_channel_abort(active_state->dma_out);
  dma_channel_abort(active_state->dma_in);

  dma_channel_config out_config = dma_channel_get_default_config(active_state->dma_out);
  channel_config_set_transfer_data_size(&out_config, DMA_SIZE_8);
  channel_config_set_bswap(&out_config, true);
  channel_config_set_dreq(&out_config, pio_get_dreq(active_state->pio, active_state->pio_sm, true));

  dma_channel_config in_config = dma_channel_get_default_config(active_state->dma_in);
  channel_config_set_transfer_data_size(&in_config, DMA_SIZE_8);
  channel_config_set_bswap(&in_config, true);
  channel_config_set_dreq(&in_config, pio_get_dreq(active_state->pio, active_state->pio_sm, false));
  channel_config_set_write_increment(&in_config, true);
  channel_config_set_read_increment(&in_config, false);

  wizchip_pio_spi_frame_start();

  dma_channel_configure(active_state->dma_out, &out_config, &active_state->pio->txf[active_state->pio_sm], command_buf, tx_length, true); 
  dma_channel_configure(active_state->dma_in, &in_config, rx, &active_state->pio->rxf[active_state->pio_sm], rx_length, true);

  pio_sm_set_enabled(active_state->pio, active_state->pio_sm, true);

  __compiler_memory_barrier();

  dma_channel_wait_for_finish_blocking(active_state->dma_out);
  dma_channel_wait_for_finish_blocking(active_state->dma_in);

  __compiler_memory_barrier();

  pio_sm_set_enabled(active_state->pio, active_state->pio_sm, false);
  pio_sm_exec(active_state->pio, active_state->pio_sm, pio_encode_mov(pio_pins, pio_null)); 
  wizchip_pio_spi_frame_end();
}

 

 

 

Documents
Comments Write