GD32单片机SPI数据传输发生错位

问题:使用两个GD32E103进行SPI数据传输,主机和从机接收的数组都会移位且不能按照数组顺序接收。

我作为从机,想要实现:主机发送7F 00 00 00 00 00 00 7F,从机传回7F 05 05 05 05 05 05 7F。如果不能实现数组形式传输,也可以一个数一个数的方式传输。

主机代码:

#include "gd32e10x.h"
#include "gd32e10x_eval.h"

//#define SPI_CRC_ENABLE           1
#define ARRAYSIZE                10

#define SET_SPI0_NSS_HIGH          gpio_bit_set(GPIOA,GPIO_PIN_4);
#define SET_SPI0_NSS_LOW           gpio_bit_reset(GPIOA,GPIO_PIN_4);

uint8_t spi0_send_array[ARRAYSIZE] = {0xA1, 0xA2, 0xA3, 0xA4, 0xA5, 0xA6, 0xA7, 0xA8, 0xA9, 0xAA};
uint8_t spi2_send_array[ARRAYSIZE] = {0xB1, 0xB2, 0xB3, 0xB4, 0xB5, 0xB6, 0xB7, 0xB8, 0xB9, 0xBA};
uint8_t spi0_receive_array[ARRAYSIZE] = {0xB1, 0xB2, 0xB3, 0xB4, 0xB5, 0xB6, 0xB7, 0xB8, 0xB9, 0xBA};
uint8_t spi2_receive_array[ARRAYSIZE];
uint32_t send_n = 0, receive_n = 0;
uint32_t crc_value1 = 0, crc_value2 = 0;

void rcu_config(void);
void gpio_config(void);
void spi_config(void);
ErrStatus memory_compare(uint8_t *src, uint8_t *dst, uint8_t length);

/*!
    \brief      main function
    \param[in]  none
    \param[out] none
    \retval     none
*/
int main(void)
{
    /* initialize the LEDs */
    gd_eval_led_init(LED2);
    gd_eval_led_init(LED3);
    /* enable peripheral clock */
    rcu_config();
    /* configure GPIO */
    gpio_config();
    
    SET_SPI0_NSS_LOW
    /* configure SPI */
    spi_config();
    /* enable SPI */
    spi_enable(SPI0);
    
#if SPI_CRC_ENABLE
    /* wait for transmit completed */
    while(send_n < ARRAYSIZE) {
        while(RESET == spi_i2s_flag_get(SPI2, SPI_FLAG_TBE)) {
        }
        spi_i2s_data_transmit(SPI2, spi2_send_array[send_n]);
        while(RESET == spi_i2s_flag_get(SPI0, SPI_FLAG_TBE)) {
        }
        spi_i2s_data_transmit(SPI0, spi0_send_array[send_n++]);
        while(RESET == spi_i2s_flag_get(SPI2, SPI_FLAG_RBNE)) {
        }
        spi2_receive_array[receive_n] = spi_i2s_data_receive(SPI2);
        while(RESET == spi_i2s_flag_get(SPI0, SPI_FLAG_RBNE)) {
        }
        spi0_receive_array[receive_n++] = spi_i2s_data_receive(SPI0);
    }

    /* send the last data */
    while(RESET == spi_i2s_flag_get(SPI2, SPI_FLAG_TBE)) {
    }
    spi_i2s_data_transmit(SPI2, spi2_send_array[send_n]);

    while(RESET == spi_i2s_flag_get(SPI0, SPI_FLAG_TBE)) {
    }
    spi_i2s_data_transmit(SPI0, spi0_send_array[send_n++]);

    /* send the CRC value */
    spi_crc_next(SPI2);
    spi_crc_next(SPI0);

    /* receive the last data */
    while(RESET == spi_i2s_flag_get(SPI0, SPI_FLAG_RBNE)) {
    }
    spi0_receive_array[receive_n] = spi_i2s_data_receive(SPI0);

    while(RESET == spi_i2s_flag_get(SPI2, SPI_FLAG_RBNE)) {
    }
    spi2_receive_array[receive_n++] = spi_i2s_data_receive(SPI2);

    /* receive the CRC value */
    while(RESET == spi_i2s_flag_get(SPI0, SPI_FLAG_RBNE)) {
    }
    while(RESET == spi_i2s_flag_get(SPI2, SPI_FLAG_RBNE)) {
    }
    crc_value1 = spi_i2s_data_receive(SPI0);
    crc_value2 = spi_i2s_data_receive(SPI2);

    /* check the CRC error status  */
    if(SET != spi_i2s_flag_get(SPI0, SPI_FLAG_CRCERR)) {
        gd_eval_led_on(LED2);
    } else {
        gd_eval_led_off(LED2);
    }

    if(SET != spi_i2s_flag_get(SPI2, SPI_FLAG_CRCERR)) {
        gd_eval_led_on(LED3);
    } else {
        gd_eval_led_off(LED3);
    }
#else
    /* wait for transmit completed */
    while(send_n < ARRAYSIZE) {
        while(RESET == spi_i2s_flag_get(SPI0, SPI_FLAG_TBE)) {
        }
        spi_i2s_data_transmit(SPI0, spi0_send_array[send_n++]);

        while(RESET == spi_i2s_flag_get(SPI0, SPI_FLAG_RBNE)) {
        }
        spi0_receive_array[receive_n++] = spi_i2s_data_receive(SPI0);
    }

    /* compare receive data with send data */
    if(ERROR != memory_compare(spi0_receive_array, spi0_send_array, ARRAYSIZE)) {
        gd_eval_led_on(LED2);
    } else {
        gd_eval_led_off(LED2);
    }

#endif /* enable CRC function */

    while(1) {
    }
}

/*!
    \brief      configure different peripheral clocks
    \param[in]  none
    \param[out] none
    \retval     none
*/
void rcu_config(void)
{
    rcu_periph_clock_enable(RCU_GPIOA);
    rcu_periph_clock_enable(RCU_GPIOC);
    rcu_periph_clock_enable(RCU_AF);
    rcu_periph_clock_enable(RCU_SPI0);
    rcu_periph_clock_enable(RCU_SPI2);
}

/*!
    \brief      configure the GPIO peripheral
    \param[in]  none
    \param[out] none
    \retval     none
*/
void gpio_config(void)
{
    /* configure SPI0 GPIO: SCK/PA5, MISO/PA6, MOSI/PA7 */
    gpio_init(GPIOA, GPIO_MODE_AF_PP, GPIO_OSPEED_50MHZ, GPIO_PIN_5 | GPIO_PIN_7);
    gpio_init(GPIOA, GPIO_MODE_IN_FLOATING, GPIO_OSPEED_50MHZ, GPIO_PIN_6);
    gpio_init(GPIOA, GPIO_MODE_AF_PP, GPIO_OSPEED_50MHZ, GPIO_PIN_4);

}

/*!
    \brief      configure the SPI peripheral
    \param[in]  none
    \param[out] none
    \retval     none
*/
void spi_config(void)
{
    spi_parameter_struct spi_init_struct;
    /* deinitilize SPI and the parameters */
    spi_i2s_deinit(SPI0);
    spi_i2s_deinit(SPI2);
    spi_struct_para_init(&spi_init_struct);

    /* configure SPI0 parameter */
    spi_init_struct.trans_mode           = SPI_TRANSMODE_FULLDUPLEX;
    spi_init_struct.device_mode          = SPI_MASTER;
    spi_init_struct.frame_size           = SPI_FRAMESIZE_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);

#if SPI_CRC_ENABLE
    /* configure SPI CRC function */
    spi_crc_polynomial_set(SPI0, 7);
    spi_crc_polynomial_set(SPI2, 7);
    spi_crc_on(SPI0);
    spi_crc_on(SPI2);
#endif /* enable CRC function */
}

/*!
    \brief      memory compare function
    \param[in]  src: source data pointer
    \param[in]  dst: destination data pointer
    \param[in]  length: the compare data length
    \param[out] none
    \retval     ErrStatus: ERROR or SUCCESS
*/
ErrStatus memory_compare(uint8_t *src, uint8_t *dst, uint8_t length)
{
    while(length--) {
        if(*src++ != *dst++) {
            return ERROR;
        }
    }
    return SUCCESS;
}



从机代码:

#include "gd32e10x.h"
#include "gd32e10x_eval.h"

//#define SPI_CRC_ENABLE           1
#define ARRAYSIZE                10

uint8_t spi0_send_array[ARRAYSIZE] = {0xA1, 0xA2, 0xA3, 0xA4, 0xA5, 0xA6, 0xA7, 0xA8, 0xA9, 0xAA};
uint8_t spi2_send_array[ARRAYSIZE] = {0xB1, 0xB2, 0xB3, 0xB4, 0xB5, 0xB6, 0xB7, 0xB8, 0xB9, 0xBA};
uint8_t spi0_receive_array[ARRAYSIZE];
uint8_t spi2_receive_array[ARRAYSIZE];
uint32_t send_n = 0, receive_n = 0;
uint32_t crc_value1 = 0, crc_value2 = 0;

void rcu_config(void);
void gpio_config(void);
void spi_config(void);
ErrStatus memory_compare(uint8_t *src, uint8_t *dst, uint8_t length);

/*!
    \brief      main function
    \param[in]  none
    \param[out] none
    \retval     none
*/
int main(void)
{
    /* initialize the LEDs */
    gd_eval_led_init(LED2);
    gd_eval_led_init(LED3);
    /* enable peripheral clock */
    rcu_config();
    /* configure GPIO */
    gpio_config();
    /* configure SPI */
    spi_config();
    /* enable SPI */
    spi_enable(SPI2);
    spi_enable(SPI0);

#if SPI_CRC_ENABLE
    /* wait for transmit completed */
    while(send_n < ARRAYSIZE) {
        while(RESET == spi_i2s_flag_get(SPI2, SPI_FLAG_TBE)) {
        }
        spi_i2s_data_transmit(SPI2, spi2_send_array[send_n]);
        while(RESET == spi_i2s_flag_get(SPI0, SPI_FLAG_TBE)) {
        }
        spi_i2s_data_transmit(SPI0, spi0_send_array[send_n++]);
        while(RESET == spi_i2s_flag_get(SPI2, SPI_FLAG_RBNE)) {
        }
        spi2_receive_array[receive_n] = spi_i2s_data_receive(SPI2);
        while(RESET == spi_i2s_flag_get(SPI0, SPI_FLAG_RBNE)) {
        }
        spi0_receive_array[receive_n++] = spi_i2s_data_receive(SPI0);
    }

    /* send the last data */
    while(RESET == spi_i2s_flag_get(SPI2, SPI_FLAG_TBE)) {
    }
    spi_i2s_data_transmit(SPI2, spi2_send_array[send_n]);

    while(RESET == spi_i2s_flag_get(SPI0, SPI_FLAG_TBE)) {
    }
    spi_i2s_data_transmit(SPI0, spi0_send_array[send_n++]);

    /* send the CRC value */
    spi_crc_next(SPI2);
    spi_crc_next(SPI0);

    /* receive the last data */
    while(RESET == spi_i2s_flag_get(SPI0, SPI_FLAG_RBNE)) {
    }
    spi0_receive_array[receive_n] = spi_i2s_data_receive(SPI0);

    while(RESET == spi_i2s_flag_get(SPI2, SPI_FLAG_RBNE)) {
    }
    spi2_receive_array[receive_n++] = spi_i2s_data_receive(SPI2);

    /* receive the CRC value */
    while(RESET == spi_i2s_flag_get(SPI0, SPI_FLAG_RBNE)) {
    }
    while(RESET == spi_i2s_flag_get(SPI2, SPI_FLAG_RBNE)) {
    }
    crc_value1 = spi_i2s_data_receive(SPI0);
    crc_value2 = spi_i2s_data_receive(SPI2);

    /* check the CRC error status  */
    if(SET != spi_i2s_flag_get(SPI0, SPI_FLAG_CRCERR)) {
        gd_eval_led_on(LED2);
    } else {
        gd_eval_led_off(LED2);
    }

    if(SET != spi_i2s_flag_get(SPI2, SPI_FLAG_CRCERR)) {
        gd_eval_led_on(LED3);
    } else {
        gd_eval_led_off(LED3);
    }
#else
    /* wait for transmit completed */
    while(receive_n < ARRAYSIZE) {
        while(RESET == spi_i2s_flag_get(SPI0, SPI_FLAG_TBE)) {
        }
        spi_i2s_data_transmit(SPI0, spi0_send_array[send_n++]);
        while(RESET == spi_i2s_flag_get(SPI0, SPI_FLAG_RBNE)) {
        }
        spi0_receive_array[receive_n++] = spi_i2s_data_receive(SPI0);
        
        
    }

    /* compare receive data with send data */
    if(ERROR != memory_compare(spi0_receive_array, spi0_send_array, ARRAYSIZE)) {
        gd_eval_led_on(LED2);
    } else {
        gd_eval_led_off(LED2);
    }
    

#endif /* enable CRC function */

    while(1) {
    }
}

/*!
    \brief      configure different peripheral clocks
    \param[in]  none
    \param[out] none
    \retval     none
*/
void rcu_config(void)
{
    rcu_periph_clock_enable(RCU_GPIOA);
    rcu_periph_clock_enable(RCU_GPIOC);
    rcu_periph_clock_enable(RCU_AF);
    rcu_periph_clock_enable(RCU_SPI0);
    rcu_periph_clock_enable(RCU_SPI2);
}

/*!
    \brief      configure the GPIO peripheral
    \param[in]  none
    \param[out] none
    \retval     none
*/
void gpio_config(void)
{
    /* configure SPI0 GPIO: SCK/PA5, MISO/PA6, MOSI/PA7 */
     /* set GPIO PA4 as SPI0 NSS input */

    
    gpio_init(GPIOA, GPIO_MODE_IN_FLOATING, GPIO_OSPEED_50MHZ, GPIO_PIN_5 | GPIO_PIN_7);
    gpio_init(GPIOA, GPIO_MODE_IN_FLOATING, GPIO_OSPEED_50MHZ, GPIO_PIN_4);
    gpio_init(GPIOA, GPIO_MODE_AF_PP, GPIO_OSPEED_50MHZ, GPIO_PIN_6);

}

/*!
    \brief      configure the SPI peripheral
    \param[in]  none
    \param[out] none
    \retval     none
*/
void spi_config(void)
{
    spi_parameter_struct spi_init_struct;
    /* deinitilize SPI and the parameters */
    spi_i2s_deinit(SPI0);
    spi_struct_para_init(&spi_init_struct);

    /* configure SPI0 parameter */
    spi_init_struct.trans_mode           = SPI_TRANSMODE_FULLDUPLEX;
    spi_init_struct.device_mode          = SPI_SLAVE;
    spi_init_struct.frame_size           = SPI_FRAMESIZE_8BIT;
    spi_init_struct.clock_polarity_phase = SPI_CK_PL_LOW_PH_1EDGE;
    spi_init_struct.nss                  = SPI_NSS_HARD;
    spi_init_struct.prescale             = SPI_PSC_256;
    spi_init_struct.endian               = SPI_ENDIAN_MSB;
    spi_init(SPI0, &spi_init_struct);

#if SPI_CRC_ENABLE
    /* configure SPI CRC function */
    spi_crc_polynomial_set(SPI0, 7);
    spi_crc_polynomial_set(SPI2, 7);
    spi_crc_on(SPI0);
    spi_crc_on(SPI2);
#endif /* enable CRC function */
}

/*!
    \brief      memory compare function
    \param[in]  src: source data pointer
    \param[in]  dst: destination data pointer
    \param[in]  length: the compare data length
    \param[out] none
    \retval     ErrStatus: ERROR or SUCCESS
*/
ErrStatus memory_compare(uint8_t *src, uint8_t *dst, uint8_t length)
{
    while(length--) {
        if(*src++ != *dst++) {
            return ERROR;
        }
    }
    return SUCCESS;
}


传输0x05,更改传输速度8分频,时钟极性1,第二个边沿采样得到如下结果:

img

img

img

传输0x05,更改传输速度64分频,时钟极性1,第二个边沿采样得到如下结果:

img


得到结果会移位,也就是
14
0001 0100

A0
1010 0000

0A
0000 1010

更改256分频,时钟极性0,第一个边沿采样得到如下结果:

img

img


数据正确,但是顺序不是按照发送顺序。
还尝试过中断和DMA处理,都是相同情况。
有没有工程师知道怎么解决的。

  1. 检查SPI时钟频率是否正确,确保时钟频率在设备允许的范围内;

  2. 检查SPI数据传输模式是否正确,确保数据传输模式与设备要求的模式一致;

  3. 检查SPI数据位宽是否正确,确保数据位宽与设备要求的位宽一致;

  4. 检查SPI片选信号是否正确,确保片选信号与设备要求的信号一致;

  5. 检查SPI数据传输顺序是否正确,确保数据传输顺序与设备要求的顺序一致;

  6. 检查SPI数据传输时序是否正确,确保数据传输时序与设备要求的时序一致;

  7. 检查SPI数据传输方向是否正确,确保数据传输方向与设备要求的方向一致;

  8. 检查SPI数据传输格式是否正确,确保数据传输格式与设备要求的格式一致;

  9. 检查SPI数据传输时的中断是否正确,确保数据传输时的中断与设备要求的中断一致;

  10. 检查SPI数据传输时的延时是否正确,确保数据传输时的延时与设备要求的延时一致。

  • 以下回答由chatgpt基于相关博客总结生成:

    问题标题: GD32单片机SPI数据传输发生错位

    问题内容: 我正在使用两个GD32E103单片机进行SPI数据传输,但是主机和从机接收的数组都会发生移位,并且无法按照数组顺序接收。我作为从机,希望实现以下传输方式: 主机发送数据7F 00 00 00 00 00 00 7F,从机应该回传数据7F 05 05 05 05 05 05 7F。如果无法实现以数组形式传输,也可以按照单个数据进行传输。

    优化后的问题:

    我正在使用两个GD32E103单片机进行SPI数据传输,但是主机和从机接收的数组都会发生移位,并且无法按照数组顺序接收。我作为从机,希望实现以下传输方式: 主机发送数据7F 00 00 00 00 00 00 7F,从机应该回传数据7F 05 05 05 05 05 05 7F。请问如何解决这个问题?谢谢!

    主机代码示例:

    [请提供主机代码]
    

    从机代码示例:

    [请提供从机代码]
    

    传输结果1: 14 0001 0100 A0 1010 0000 0A 0000 1010

    传输结果2: [请提供传输结果2]

    传输结果3: [请提供传输结果3]

    尽管数据是正确的,但顺序并不按照发送顺序。我也尝试过使用中断和DMA处理,但问题依然存在。

    有没有了解如何解决这个问题的工程师能够提供帮助?谢谢!