【雅特力AT-START-F437评测】4. SPI2 + DMA 读写测试
[复制链接]
本帖最后由 caizhiwei 于 2023-6-23 08:57 编辑
捣鼓了几个星期,没有Cube MX修改驱动还是难度挺大的,今天终于把外设SPI 调试好了。
AT32 SPI特点:
可编程配置的全双工或半双工通信
--全双工同步通信--半双工同步通信(可以根据软件编程配置选择传输方向:发送或接收)
可编程配置主/从模式
可编程配置的CS模式:硬件/软件CS模式
可编程配置的时钟极性和相位
可编程配置的数据传输顺序(MSB/LSB)
可编程配置的错误中断标志(CS脉冲异常,接收溢出错误,主模式错误,CRC校验错误)
数据接收/发送均支持DMA
兼容TI的SSP协议(即TI模式)。
这里暂时不研究SPIM,先用通用的SPI接口来连接 外置的 SPI Flash.
硬件连接好之后:第一步,初始化SPI2:
/**
* [url=home.php?mod=space&uid=159083]@brief[/url] spi configuration.
* @param none
* @retval none
*/
void BSP_spiflash_init(void)
{
gpio_init_type gpio_initstructure;
spi_init_type spi_init_struct;
crm_periph_clock_enable(CRM_GPIOC_PERIPH_CLOCK, TRUE);
crm_periph_clock_enable(CRM_GPIOD_PERIPH_CLOCK, TRUE);
crm_periph_clock_enable(CRM_DMA1_PERIPH_CLOCK, TRUE);
/* software cs, pd0 as a general io to control flash cs */
gpio_initstructure.gpio_out_type = GPIO_OUTPUT_PUSH_PULL;
gpio_initstructure.gpio_pull = GPIO_PULL_UP;
gpio_initstructure.gpio_mode = GPIO_MODE_OUTPUT;
gpio_initstructure.gpio_drive_strength = GPIO_DRIVE_STRENGTH_STRONGER;
gpio_initstructure.gpio_pins = GPIO_PINS_0;
gpio_init(GPIOD, &gpio_initstructure);
/* sck */
gpio_initstructure.gpio_pull = GPIO_PULL_UP;
gpio_initstructure.gpio_mode = GPIO_MODE_MUX;
gpio_initstructure.gpio_pins = GPIO_PINS_1;
gpio_init(GPIOD, &gpio_initstructure);
gpio_pin_mux_config(GPIOD, GPIO_PINS_SOURCE1, GPIO_MUX_6);
/* miso */
gpio_initstructure.gpio_pull = GPIO_PULL_UP;
gpio_initstructure.gpio_pins = GPIO_PINS_2;
gpio_init(GPIOC, &gpio_initstructure);
gpio_pin_mux_config(GPIOC, GPIO_PINS_SOURCE2, GPIO_MUX_5);
/* mosi */
gpio_initstructure.gpio_pull = GPIO_PULL_UP;
gpio_initstructure.gpio_pins = GPIO_PINS_4;
gpio_init(GPIOD, &gpio_initstructure);
gpio_pin_mux_config(GPIOD, GPIO_PINS_SOURCE4, GPIO_MUX_6);
FLASH_CS_HIGH();
crm_periph_clock_enable(CRM_SPI2_PERIPH_CLOCK, TRUE);
spi_default_para_init(&spi_init_struct);
spi_init_struct.transmission_mode = SPI_TRANSMIT_FULL_DUPLEX;
spi_init_struct.master_slave_mode = SPI_MODE_MASTER;
spi_init_struct.mclk_freq_division = SPI_MCLK_DIV_32;
spi_init_struct.first_bit_transmission = SPI_FIRST_BIT_MSB;
spi_init_struct.frame_bit_num = SPI_FRAME_8BIT;
spi_init_struct.clock_polarity = SPI_CLOCK_POLARITY_HIGH;
spi_init_struct.clock_phase = SPI_CLOCK_PHASE_2EDGE;
spi_init_struct.cs_mode_selection = SPI_CS_SOFTWARE_MODE;
spi_init(SPI2, &spi_init_struct);
spi_enable(SPI2, TRUE);
}
第二部,读写接口:
/**
* @brief write data to flash
* @param pbuffer: the pointer for data buffer
* @param write_addr: the address where the data is written
* @param length: buffer length
* @retval none
*/
void spiflash_write(uint8_t *pbuffer, uint32_t write_addr, uint32_t length)
{
uint32_t sector_pos;
uint16_t sector_offset;
uint16_t sector_remain;
uint16_t index;
uint8_t *spiflash_buf;
uint8_t spiflash_sector_buf[SPIF_SECTOR_SIZE]; //4kb 缓存
spiflash_buf = spiflash_sector_buf;
/* sector address */
sector_pos = write_addr / SPIF_SECTOR_SIZE;
/* address offset in a sector */
sector_offset = write_addr % SPIF_SECTOR_SIZE;
/* the remain in a sector */
sector_remain = SPIF_SECTOR_SIZE - sector_offset;
if(length <= sector_remain)
{
/* smaller than a sector size */
sector_remain = length;
}
while(1)
{
/* read a sector */
spiflash_read(spiflash_buf, sector_pos * SPIF_SECTOR_SIZE, SPIF_SECTOR_SIZE);
/* validate the read erea */
for(index = 0; index < sector_remain; index++)
{
if(spiflash_buf[sector_offset + index] != 0xFF)
{
/* there are some data not equal 0xff, so this secotr needs erased */
break;
}
}
if(index < sector_remain)
{
/* erase the sector */
spiflash_sector_erase(sector_pos);
/* copy the write data */
for(index = 0; index < sector_remain; index++)
{
spiflash_buf[index + sector_offset] = pbuffer[index];
}
spiflash_write_nocheck(spiflash_buf, sector_pos * SPIF_SECTOR_SIZE, SPIF_SECTOR_SIZE); /* program the sector */
}
else
{
/* write directly in the erased area */
spiflash_write_nocheck(pbuffer, write_addr, sector_remain);
}
if(length == sector_remain)
{
/* write end */
break;
}
else
{
/* go on writing */
sector_pos++;
sector_offset = 0;
pbuffer += sector_remain;
write_addr += sector_remain;
length -= sector_remain;
if(length > SPIF_SECTOR_SIZE)
{
/* could not write the remain data in the next sector */
sector_remain = SPIF_SECTOR_SIZE;
}
else
{
/* could write the remain data in the next sector */
sector_remain = length;
}
}
}
}
/**
* @brief read data from flash
* @param pbuffer: the pointer for data buffer
* @param read_addr: the address where the data is read
* @param length: buffer length
* @retval none
*/
void spiflash_read(uint8_t *pbuffer, uint32_t read_addr, uint32_t length)
{
FLASH_CS_LOW();
spi_byte_write(SPIF_READDATA); /* send instruction */
spi_byte_write((uint8_t)((read_addr) >> 16)); /* send 24-bit address */
spi_byte_write((uint8_t)((read_addr) >> 8));
spi_byte_write((uint8_t)read_addr);
spi_bytes_read(pbuffer, length);
FLASH_CS_HIGH();
}
/**
* @brief erase a sector data
* @param erase_addr: sector address to erase
* @retval none
*/
void spiflash_sector_erase(uint32_t erase_addr)
{
erase_addr *= SPIF_SECTOR_SIZE; /* translate sector address to byte address */
spiflash_write_enable();
spiflash_wait_busy();
FLASH_CS_LOW();
spi_byte_write(SPIF_SECTORERASE);
spi_byte_write((uint8_t)((erase_addr) >> 16));
spi_byte_write((uint8_t)((erase_addr) >> 8));
spi_byte_write((uint8_t)erase_addr);
FLASH_CS_HIGH();
spiflash_wait_busy();
}
/**
* @brief write data without check
* @param pbuffer: the pointer for data buffer
* @param write_addr: the address where the data is written
* @param length: buffer length
* @retval none
*/
void spiflash_write_nocheck(uint8_t *pbuffer, uint32_t write_addr, uint32_t length)
{
uint16_t page_remain;
/* remain bytes in a page */
page_remain = SPIF_PAGE_SIZE - write_addr % SPIF_PAGE_SIZE;
if(length <= page_remain)
{
/* smaller than a page size */
page_remain = length;
}
while(1)
{
spiflash_page_write(pbuffer, write_addr, page_remain);
if(length == page_remain)
{
/* all data are programmed */
break;
}
else
{
/* length > page_remain */
pbuffer += page_remain;
write_addr += page_remain;
/* the remain bytes to be prorammed */
length -= page_remain;
if(length > SPIF_PAGE_SIZE)
{
/* can be progrmmed a page at a time */
page_remain = SPIF_PAGE_SIZE;
}
else
{
/* smaller than a page size */
page_remain = length;
}
}
}
}
/**
* @brief write a page data
* @param pbuffer: the pointer for data buffer
* @param write_addr: the address where the data is written
* @param length: buffer length
* @retval none
*/
void spiflash_page_write(uint8_t *pbuffer, uint32_t write_addr, uint32_t length)
{
if((0 < length) && (length <= SPIF_PAGE_SIZE))
{
/* set write enable */
spiflash_write_enable();
FLASH_CS_LOW();
/* send instruction */
spi_byte_write(SPIF_PAGEPROGRAM);
/* send 24-bit address */
spi_byte_write((uint8_t)((write_addr) >> 16));
spi_byte_write((uint8_t)((write_addr) >> 8));
spi_byte_write((uint8_t)write_addr);
spi_bytes_write(pbuffer,length);
FLASH_CS_HIGH();
/* wait for program end */
spiflash_wait_busy();
}
}
/**
* @brief write data continuously
* @param pbuffer: the pointer for data buffer
* @param length: buffer length
* @retval none
*/
void spi_bytes_write(uint8_t *pbuffer, uint32_t length)
{
volatile uint8_t dummy_data;
#if defined(SPI_TRANS_DMA)
dma_init_type dma_init_struct;
dma_reset(DMA1_CHANNEL2);
dma_reset(DMA1_CHANNEL3);
dma_default_para_init(&dma_init_struct);
dma_init_struct.buffer_size = length;
dma_init_struct.direction = DMA_DIR_PERIPHERAL_TO_MEMORY;
dma_init_struct.memory_base_addr = (uint32_t)&dummy_data;
dma_init_struct.memory_data_width = DMA_MEMORY_DATA_WIDTH_BYTE;
dma_init_struct.memory_inc_enable = FALSE;
dma_init_struct.peripheral_base_addr = (uint32_t)(&SPI2->dt);
dma_init_struct.peripheral_data_width = DMA_PERIPHERAL_DATA_WIDTH_BYTE;
dma_init_struct.peripheral_inc_enable = FALSE;
dma_init_struct.priority = DMA_PRIORITY_VERY_HIGH;
dma_init_struct.loop_mode_enable = FALSE;
dma_init(DMA1_CHANNEL2, &dma_init_struct);
dmamux_enable(DMA1, TRUE);
dmamux_init(DMA1MUX_CHANNEL2, DMAMUX_DMAREQ_ID_SPI2_RX);
dma_init_struct.buffer_size = length;
dma_init_struct.direction = DMA_DIR_MEMORY_TO_PERIPHERAL;
dma_init_struct.memory_base_addr = (uint32_t)pbuffer;
dma_init_struct.memory_data_width = DMA_MEMORY_DATA_WIDTH_BYTE;
dma_init_struct.memory_inc_enable = TRUE;
dma_init_struct.peripheral_base_addr = (uint32_t)(&SPI2->dt);
dma_init_struct.peripheral_data_width = DMA_PERIPHERAL_DATA_WIDTH_BYTE;
dma_init_struct.peripheral_inc_enable = FALSE;
dma_init_struct.priority = DMA_PRIORITY_VERY_HIGH;
dma_init_struct.loop_mode_enable = FALSE;
dma_init(DMA1_CHANNEL3, &dma_init_struct);
dmamux_init(DMA1MUX_CHANNEL3, DMAMUX_DMAREQ_ID_SPI2_TX);
spi_i2s_dma_transmitter_enable(SPI2, TRUE);
spi_i2s_dma_receiver_enable(SPI2, TRUE);
dma_channel_enable(DMA1_CHANNEL2, TRUE);
dma_channel_enable(DMA1_CHANNEL3, TRUE);
while(dma_flag_get(DMA1_FDT2_FLAG) == RESET);
dma_flag_clear(DMA1_FDT2_FLAG);
dma_channel_enable(DMA1_CHANNEL2, FALSE);
dma_channel_enable(DMA1_CHANNEL3, FALSE);
spi_i2s_dma_transmitter_enable(SPI2, FALSE);
spi_i2s_dma_receiver_enable(SPI2, FALSE);
#else
while(length--)
{
while(spi_i2s_flag_get(SPI2, SPI_I2S_TDBE_FLAG) == RESET);
spi_i2s_data_transmit(SPI2, *pbuffer);
while(spi_i2s_flag_get(SPI2, SPI_I2S_RDBF_FLAG) == RESET);
dummy_data = spi_i2s_data_receive(SPI2);
pbuffer++;
}
#endif
}
/**
* @brief read data continuously
* @param pbuffer: buffer to save data
* @param length: buffer length
* @retval none
*/
void spi_bytes_read(uint8_t *pbuffer, uint32_t length)
{
uint8_t write_value = FLASH_SPI_DUMMY_BYTE;
#if defined(SPI_TRANS_DMA)
dma_init_type dma_init_struct;
dma_reset(DMA1_CHANNEL2);
dma_reset(DMA1_CHANNEL3);
dma_default_para_init(&dma_init_struct);
dma_init_struct.buffer_size = length;
dma_init_struct.direction = DMA_DIR_MEMORY_TO_PERIPHERAL;
dma_init_struct.memory_base_addr = (uint32_t)&write_value;
dma_init_struct.memory_data_width = DMA_MEMORY_DATA_WIDTH_BYTE;
dma_init_struct.memory_inc_enable = FALSE;
dma_init_struct.peripheral_base_addr = (uint32_t)(&SPI2->dt);
dma_init_struct.peripheral_data_width = DMA_PERIPHERAL_DATA_WIDTH_BYTE;
dma_init_struct.peripheral_inc_enable = FALSE;
dma_init_struct.priority = DMA_PRIORITY_VERY_HIGH;
dma_init_struct.loop_mode_enable = FALSE;
dma_init(DMA1_CHANNEL3, &dma_init_struct);
dmamux_enable(DMA1, TRUE);
dmamux_init(DMA1MUX_CHANNEL3, DMAMUX_DMAREQ_ID_SPI2_TX);
dma_init_struct.buffer_size = length;
dma_init_struct.direction = DMA_DIR_PERIPHERAL_TO_MEMORY;
dma_init_struct.memory_base_addr = (uint32_t)pbuffer;
dma_init_struct.memory_data_width = DMA_MEMORY_DATA_WIDTH_BYTE;
dma_init_struct.memory_inc_enable = TRUE;
dma_init_struct.peripheral_base_addr = (uint32_t)(&SPI2->dt);
dma_init_struct.peripheral_data_width = DMA_PERIPHERAL_DATA_WIDTH_BYTE;
dma_init_struct.peripheral_inc_enable = FALSE;
dma_init_struct.priority = DMA_PRIORITY_VERY_HIGH;
dma_init_struct.loop_mode_enable = FALSE;
dma_init(DMA1_CHANNEL2, &dma_init_struct);
dmamux_init(DMA1MUX_CHANNEL2, DMAMUX_DMAREQ_ID_SPI2_RX);
spi_i2s_dma_transmitter_enable(SPI2, TRUE);
spi_i2s_dma_receiver_enable(SPI2, TRUE);
dma_channel_enable(DMA1_CHANNEL2, TRUE);
dma_channel_enable(DMA1_CHANNEL3, TRUE);
while(dma_flag_get(DMA1_FDT2_FLAG) == RESET);
dma_flag_clear(DMA1_FDT2_FLAG);
dma_channel_enable(DMA1_CHANNEL2, FALSE);
dma_channel_enable(DMA1_CHANNEL3, FALSE);
spi_i2s_dma_transmitter_enable(SPI2, FALSE);
spi_i2s_dma_receiver_enable(SPI2, FALSE);
#else
while(length--)
{
while(spi_i2s_flag_get(SPI2, SPI_I2S_TDBE_FLAG) == RESET);
spi_i2s_data_transmit(SPI2, write_value);
while(spi_i2s_flag_get(SPI2, SPI_I2S_RDBF_FLAG) == RESET);
*pbuffer = spi_i2s_data_receive(SPI2);
pbuffer++;
}
#endif
}
/**
* @brief wait program done
* @param none
* @retval none
*/
void spiflash_wait_busy(void)
{
while((spiflash_read_sr1() & 0x01) == 0x01);
}
/**
* @brief read sr1 register
* @param none
* @retval none
*/
uint8_t spiflash_read_sr1(void)
{
uint8_t breadbyte = 0;
FLASH_CS_LOW();
spi_byte_write(SPIF_READSTATUSREG1);
breadbyte = (uint8_t)spi_byte_read();
FLASH_CS_HIGH();
return (breadbyte);
}
/**
* @brief enable write operation
* @param none
* @retval none
*/
void spiflash_write_enable(void)
{
FLASH_CS_LOW();
spi_byte_write(SPIF_WRITEENABLE);
FLASH_CS_HIGH();
}
/**
* @brief read device id
* @param none
* @retval device id
*/
uint16_t spiflash_read_id(void)
{
uint16_t wreceivedata = 0;
FLASH_CS_LOW();
spi_byte_write(SPIF_MANUFACTDEVICEID);
spi_byte_write(0x00);
spi_byte_write(0x00);
spi_byte_write(0x00);
wreceivedata |= spi_byte_read() << 8;
wreceivedata |= spi_byte_read();
FLASH_CS_HIGH();
return wreceivedata;
}
/**
* @brief write a byte to flash
* @param data: data to write
* @retval flash return data
*/
uint8_t spi_byte_write(uint8_t data)
{
uint8_t brxbuff;
spi_i2s_dma_transmitter_enable(SPI2, FALSE);
spi_i2s_dma_receiver_enable(SPI2, FALSE);
spi_i2s_data_transmit(SPI2, data);
while(spi_i2s_flag_get(SPI2, SPI_I2S_RDBF_FLAG) == RESET);
brxbuff = spi_i2s_data_receive(SPI2);
while(spi_i2s_flag_get(SPI2, SPI_I2S_BF_FLAG) != RESET);
return brxbuff;
}
/**
* @brief read a byte to flash
* @param none
* @retval flash return data
*/
uint8_t spi_byte_read(void)
{
return (spi_byte_write(FLASH_SPI_DUMMY_BYTE));
}
读写测试OK:
总结: SPI总线频率达到50Mh还是很稳定的,毕竟是杜邦线连接,没有继续往上调速了。
2d5428fd995681656fbb638e4f74f465
代码经过整理上传到了gitee仓库,有需要的小伙伴可以自行下载哦~~
|