- #include "gd32h7xx.h"
- #include "gd32h7xx_dma.h"
- #include "gd32h7xx_gpio.h"
- #include "gd32h7xx_spi.h"
- //#include "gd32h759i_eval.h"
- //#include "Utils.h" // TODO
- #define DbgPrintf printf
- #define Assert(x) while(1);
- #include <stdio.h>
- #include <stdlib.h>
- // TODO: #pragma clang optimize off
- #define ARRAYSIZE 32
- #define SET_SPI0_NSS_HIGH gpio_bit_set(GPIOA,GPIO_PIN_4);
- #define SET_SPI0_NSS_LOW gpio_bit_reset(GPIOA,GPIO_PIN_4);
- static volatile uint8_t spi0_send_array[ARRAYSIZE] = {};
- static volatile uint8_t spi0_receive_array[ARRAYSIZE] = {};
- static uint8_t g_TxCount;
- static uint8_t g_RxCount;
- ErrStatus memory_compare(uint8_t *src, uint8_t *dst, uint8_t length);
- void cache_enable(void);
- void rcu_config(void);
- void gpio_config(void);
- void dma_config(void);
- void spi_config(void);
- // 计算循环 DMA 的增量
- static uint32_t GetCircularIncrease(uint32_t last, uint32_t curr)
- {
- if (last <= curr)
- {
- // 增量区间数量
- return curr - last;
- }
- else
- {
- // 回绕情况, 尾部数量 + 首部数量
- return (ARRAYSIZE - last) + curr;
- }
- }
- static uint32_t SPIDMA_Tx()
- {
- uint32_t periph = DMA0;
- dma_channel_enum channel = DMA_CH0;
- uint8_t *memAddr = spi0_send_array;
- // TODO: 发送 1 字节或者 2 字节
- uint32_t count = (rand() & 1) + 1;
- uint32_t i;
- // TODO: 生成用于测试的顺序数据
- for (i = 0; i < count; ++i)
- {
- // TODO: 使用非 0 的固定值
- memAddr[i] = 0x66;
- }
- // TODO: DCache commit
- //SCB_CleanDCache();
- // TODO: 内存同步
- __DSB();
- dma_channel_disable(periph, channel);
- dma_memory_address_config(periph, channel, DMA_MEMORY_0, (uint32_t)memAddr);
- dma_transfer_number_config(periph, channel, count);
- dma_channel_enable(periph, channel);
- // SPI 开始传输
- spi_master_transfer_start(SPI0, SPI_TRANS_START);
- return count;
- }
- /*!
- \brief main function
- \param[in] none
- \param[out] none
- \retval none
- */
- int main(void)
- {
- uint32_t txTotal = 0;
- uint32_t rxTotal = 0;
- uint32_t rxLast = 0;
- uint32_t i, j;
- SCB_EnableICache();
- // TODO: 关闭 DCache, 排除缓存一致性问题
- SCB_DisableDCache();
- /* peripheral clock enable */
- rcu_config();
- /* configure GPIO */
- gpio_config();
- /* configure SPI */
- spi_config();
- /* configure DMA */
- dma_config();
- /* configure SPI current data number */
- // TODO: SPI 使用无限循环发送模式
- spi_current_data_num_config(SPI0, 0);
- SET_SPI0_NSS_HIGH
- /* SPI enable */
- spi_enable(SPI0);
- SET_SPI0_NSS_LOW
- /* SPI DMA enable */
- spi_dma_enable(SPI0, SPI_DMA_RECEIVE);
- spi_dma_enable(SPI0, SPI_DMA_TRANSMIT);
- // TODO: 先发送 1 个字节
- txTotal += SPIDMA_Tx();
- // 循环收发
- for (j = 0; j < ARRAYSIZE * 1000; ++j)
- {
- uint32_t rxCurr;
- uint32_t rxInc;
- // TODO: 等待发送完毕
- if (dma_flag_get(DMA0, DMA_CH0, DMA_FLAG_FTF))
- {
- dma_flag_clear(DMA0, DMA_CH0, DMA_FLAG_FTF);
- // 发送完毕后继续发送, 直到发送一定次数后停止发送
- if (j < 9999)
- {
- // 继续发送 1 个字节
- txTotal += SPIDMA_Tx();
- }
- }
- // 计算循环 DMA 的增量, 累计接收的字节数
- rxCurr = ARRAYSIZE - dma_transfer_number_get(DMA0, DMA_CH1);
- // 在接收 DMA 半满/全满时, 检查第一个字节是不是有问题
- if (dma_flag_get(DMA0, DMA_CH1, DMA_FLAG_HTF) ||
- dma_flag_get(DMA0, DMA_CH1, DMA_FLAG_FTF))
- {
- dma_flag_clear(DMA0, DMA_CH1, DMA_FLAG_HTF);
- dma_flag_clear(DMA0, DMA_CH1, DMA_FLAG_FTF);
- // TODO: 检测到数据有问题时打印
- //if (spi0_receive_array[0] == 0)
- {
- DbgPrintf("!! Got, %02X\n", spi0_receive_array[0]);
- }
- }
- rxInc = GetCircularIncrease(rxLast, rxCurr);
- rxLast = rxCurr;
- rxTotal += rxInc;
- //DbgPrintf("tx=%u, rx=%u, diff=%d\n", txTotal, rxTotal, (int)(txTotal - rxTotal));
- // TODO: 检测到 BUG, 退出循环
- if ((int)(txTotal - rxTotal) < 0)
- {
- DbgPrintf("tx=%u, rx=%u, diff=%d\n", txTotal, rxTotal, (int)(txTotal - rxTotal));
- DbgPrintf("!!! ERR: Receive larger than Send!\n");
- break;
- }
- }
- DbgPrintf("Done\n");
- /* wait DMA transmit complete */
- while (dma_flag_get(DMA0, DMA_CH0, DMA_FLAG_FTF) == RESET);
- while (dma_flag_get(DMA0, DMA_CH1, DMA_FLAG_FTF) == RESET);
- /* Clear DMA Transfer Complete Flags */
- dma_flag_clear(DMA0, DMA_CH0, DMA_FLAG_FTF);
- dma_flag_clear(DMA0, DMA_CH1, DMA_FLAG_FTF);
- SET_SPI0_NSS_HIGH
- /* SPI disable */
- spi_disable(SPI0);
- while (1);
- }
- /*!
- \brief configure different peripheral clocks
- \param[in] none
- \param[out] none
- \retval none
- */
- void rcu_config(void)
- {
- /* enable the peripherals clock */
- rcu_periph_clock_enable(RCU_GPIOA);
- rcu_periph_clock_enable(RCU_GPIOB);
- rcu_periph_clock_enable(RCU_GPIOG);
- rcu_periph_clock_enable(RCU_SPI0);
- rcu_periph_clock_enable(RCU_DMA0);
- rcu_periph_clock_enable(RCU_DMAMUX);
- rcu_spi_clock_config(IDX_SPI0, RCU_SPISRC_PLL0Q);
- }
- /*!
- \brief configure the GPIO peripheral
- \param[in] none
- \param[out] none
- \retval none
- */
- void gpio_config(void)
- {
- /* connect port to SPI0_NSS->PA4
- SPI0_SCK->PA5
- SPI0_MISO->PA6
- SPI0_MOSI->PA7 */
- gpio_mode_set(GPIOA, GPIO_MODE_OUTPUT, GPIO_PUPD_NONE, GPIO_PIN_4);
- gpio_output_options_set(GPIOA, GPIO_OTYPE_PP, GPIO_OSPEED_60MHZ, GPIO_PIN_4);
- gpio_af_set(GPIOA, GPIO_AF_5, GPIO_PIN_5 | GPIO_PIN_6 | GPIO_PIN_7);
- gpio_mode_set(GPIOA, GPIO_MODE_AF, GPIO_PUPD_NONE, GPIO_PIN_5 | GPIO_PIN_6 | GPIO_PIN_7);
- gpio_output_options_set(GPIOA, GPIO_OTYPE_PP, GPIO_OSPEED_60MHZ, GPIO_PIN_5 | GPIO_PIN_6 | GPIO_PIN_7);
- }
- /*!
- \brief configure the DMA peripheral
- \param[in] none
- \param[out] none
- \retval none
- */
- void dma_config(void)
- {
- dma_single_data_parameter_struct dma_init_struct;
- /* deinitialize DMA registers of a channel */
- dma_deinit(DMA0, DMA_CH0);
- dma_deinit(DMA0, DMA_CH1);
- dma_single_data_para_struct_init(&dma_init_struct);
- /* SPI0 transmit DMA config: DMA_CH0 */
- dma_init_struct.request = DMA_REQUEST_SPI0_TX;
- dma_init_struct.direction = DMA_MEMORY_TO_PERIPH;
- dma_init_struct.memory0_addr = (uint32_t)spi0_send_array;
- dma_init_struct.memory_inc = DMA_MEMORY_INCREASE_ENABLE;
- dma_init_struct.periph_memory_width = DMA_PERIPH_WIDTH_8BIT;
- dma_init_struct.number = ARRAYSIZE;
- dma_init_struct.periph_addr = (uint32_t)&SPI_TDATA(SPI0);
- dma_init_struct.periph_inc = DMA_PERIPH_INCREASE_DISABLE;
- dma_init_struct.priority = DMA_PRIORITY_HIGH;
- dma_init_struct.circular_mode = DMA_CIRCULAR_MODE_DISABLE;
- dma_single_data_mode_init(DMA0, DMA_CH0, &dma_init_struct);
- /* SPI0 receive DMA config: DMA_CH1 */
- dma_init_struct.request = DMA_REQUEST_SPI0_RX;
- dma_init_struct.direction = DMA_PERIPH_TO_MEMORY;
- dma_init_struct.memory0_addr = (uint32_t)spi0_receive_array;
- dma_init_struct.periph_addr = (uint32_t)&SPI_RDATA(SPI0);
- dma_init_struct.priority = DMA_PRIORITY_ULTRA_HIGH;
- dma_init_struct.circular_mode = DMA_CIRCULAR_MODE_ENABLE; // TODO: 循环接收
- dma_single_data_mode_init(DMA0, DMA_CH1, &dma_init_struct);
- /* enable DMA channel */
- //dma_channel_enable(DMA0, DMA_CH0);
- dma_channel_enable(DMA0, DMA_CH1);
- }
- /*!
- \brief configure the SPI peripheral
- \param[in] none
- \param[out] none
- \retval none
- */
- void spi_config(void)
- {
- spi_parameter_struct spi_init_struct;
- /* deinitialize SPI and the parameters */
- spi_i2s_deinit(SPI0);
- spi_struct_para_init(&spi_init_struct);
- /* SPI0 parameter configuration */
- spi_init_struct.trans_mode = SPI_TRANSMODE_FULLDUPLEX;
- spi_init_struct.device_mode = SPI_MASTER;
- spi_init_struct.data_size = SPI_DATASIZE_8BIT;
- spi_init_struct.clock_polarity_phase = SPI_CK_PL_LOW_PH_1EDGE;
- spi_init_struct.nss = SPI_NSS_SOFT;
- spi_init_struct.prescale = SPI_PSC_256;
- spi_init_struct.endian = SPI_ENDIAN_MSB;
- spi_init(SPI0, &spi_init_struct);
- /* enable SPI byte access */
- spi_byte_access_enable(SPI0);
- /* enable SPI NSS output */
- spi_nss_output_enable(SPI0);
- //spi_fifo_threshold_level_set(SPI0, SPI_FIFO_TH_02DATA);
- }