Dylan疾风闪电 发表于 2015-1-5 20:36:39

STM32F030的硬件SPI从模式,从机应答时丢失首个字节?

如题,主机发送{0,0,0,0},想要得到的从机应答{0x00,0x70,0x53,0xb0};实际获取的应答为{0x70,0x53,0xb0,0x00}。

中断程序如下:

uint32_t spi_TxBuff = 0x00000000;

uint32_t DataRegs;
#define OFFSET_0                        24
uint8_t offsetbits = OFFSET_0;

uint8_t rw_Flag;//0x00:read,0x80:write,=data & 0x80;
uint8_t reg_Address;//=data & 0x7F;

void SPI2_IRQHandler(void)
{
        uint8_t data;
       
        if (SPI2->SR & 0x1)
        {
                data = SPI_ReceiveData8(SPI2);
               
                rw_Flag = data & 0x80;
                reg_Address = data & 0x7F;
               
                if (rw_Flag != 0x00)
                {
                        //write to regs
                       
                        //SPI_I2S_ITConfig(SPI2, SPI_I2S_IT_TXE, DISABLE);
                }
                else
                {
                        //read from regs       
                        if (reg_Address < 10)
                        {
                                if (offsetbits == OFFSET_0)
                                {
                                        spi_TxBuff = DataRegs;
                                }
                        }
                        else
                        {
                                spi_TxBuff = 0x00FFFFFF;
                        }
                }
        }
       
        if (SPI2->SR & 0x2)
        {
                SPI_SendData8(SPI2, (0xFF & (spi_TxBuff >> offsetbits)));
               
                if (offsetbits >= 8)
                {
                        offsetbits -= 8;
                }
                else
                {
                        offsetbits = OFFSET_0;
                }
        }
}

void EXTI4_15_IRQHandler(void)
{
        EXTI->PR ^= (uint16_t)~EXTI_Line11;

        offsetbits = OFFSET_0;
}

Dylan疾风闪电 发表于 2015-1-5 20:42:42

本帖最后由 Dylan疾风闪电 于 2015-1-5 20:44 编辑

SPI的主/从的初始化代码:
void connectSPI1ToExt(uint16_t BaudRatePCLKDiv, uint16_t CPOL, uint16_t CPHA_Edge)
{
        GPIO_InitTypeDef GPIO_InitStructure;
        SPI_InitTypeDefSPI_InitStructure;

        RCC_AHBPeriphClockCmd(RCC_AHBPeriph_GPIOA, ENABLE);

        //SPIx_SCK 主模式 推挽复用输出
        //SPIx_MOSI 全双工模式/主模式 推挽复用输出
        //SPIx_MISO 全双工模式/主模式 浮空输入或带上拉输入
        GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF;
        GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;
        GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
        GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL;
        GPIO_InitStructure.GPIO_Pin = SPLIT_DEFINE_PIN(X2_CLK);
        GPIO_Init(SPLIT_DEFINE_PORT(X2_CLK), &GPIO_InitStructure);
        SetAF_SPI1_SCK;
       
        GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF;
        GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;
        GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
        GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL;
        GPIO_InitStructure.GPIO_Pin = SPLIT_DEFINE_PIN(X2_SDI);
        GPIO_Init(SPLIT_DEFINE_PORT(X2_SDI), &GPIO_InitStructure);
        SetAF_SPI1_MOSI;

        GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF;
        GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;
        GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
        GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_UP;
        GPIO_InitStructure.GPIO_Pin = SPLIT_DEFINE_PIN(X2_SDO);
        GPIO_Init(SPLIT_DEFINE_PORT(X2_SDO), &GPIO_InitStructure);
        SetAF_SPI1_MISO;

        //
        RCC_APB2PeriphClockCmd(RCC_APB2Periph_SPI1, ENABLE);
        RCC_APB2PeriphResetCmd(RCC_APB2Periph_SPI1, ENABLE);
        RCC_APB2PeriphResetCmd(RCC_APB2Periph_SPI1, DISABLE);

        SPI_InitStructure.SPI_Direction = SPI_Direction_2Lines_FullDuplex;
        SPI_InitStructure.SPI_Mode = SPI_Mode_Master;
        SPI_InitStructure.SPI_DataSize = SPI_DataSize_8b;
        SPI_InitStructure.SPI_CPOL = CPOL;
        SPI_InitStructure.SPI_CPHA = CPHA_Edge;
        SPI_InitStructure.SPI_NSS = SPI_NSS_Soft;
        SPI_InitStructure.SPI_BaudRatePrescaler = BaudRatePCLKDiv;
        SPI_InitStructure.SPI_FirstBit = SPI_FirstBit_MSB;
        SPI_InitStructure.SPI_CRCPolynomial = 7;
        SPI_Init(SPI1, &SPI_InitStructure);
        SPI_CalculateCRC(SPI1,DISABLE);

        SPI_RxFIFOThresholdConfig(SPI1, SPI_RxFIFOThreshold_QF);

        SPI_Cmd(SPI1, ENABLE);
}

void connectSPI2SlaveToExt(uint16_t BaudRatePCLKDiv, uint16_t CPOL, uint16_t CPHA_Edge)
{
        GPIO_InitTypeDef GPIO_InitStructure;

        RCC_AHBPeriphClockCmd(RCC_AHBPeriph_GPIOB, ENABLE);

        //SPIx_SCK 从模式 浮空输入
        //SPIx_MOSI 全双工模式/从模式 浮空输入或带上拉输入
        //SPIx_MISO 全双工模式/从模式 推挽复用输出
        GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF;
        GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;
        GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
        GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL;
        GPIO_InitStructure.GPIO_Pin = SPLIT_DEFINE_PIN(X3_CLK_S);
        GPIO_Init(SPLIT_DEFINE_PORT(X3_CLK_S), &GPIO_InitStructure);
        SetAF_SPI2_SCK;

        GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF;
        GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;
        GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
        GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_UP;
        GPIO_InitStructure.GPIO_Pin = SPLIT_DEFINE_PIN(X3_SDI_S);
        GPIO_Init(SPLIT_DEFINE_PORT(X3_SDI_S), &GPIO_InitStructure);
        SetAF_SPI2_MOSI;

        GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF;
        GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;
        GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
        GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL;
        GPIO_InitStructure.GPIO_Pin = SPLIT_DEFINE_PIN(X3_SDO_S);
        GPIO_Init(SPLIT_DEFINE_PORT(X3_SDO_S), &GPIO_InitStructure);
        SetAF_SPI2_MISO;
       
        GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF;
        GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;
        GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
        GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_UP;
        GPIO_InitStructure.GPIO_Pin = SPLIT_DEFINE_PIN(X3_CS_S);
        GPIO_Init(SPLIT_DEFINE_PORT(X3_CS_S), &GPIO_InitStructure);
        SetAF_SPI2_NSS;

        //寄存器操作
        RCC_APB1PeriphClockCmd(RCC_APB1Periph_SPI2, ENABLE);
        RCC_APB1PeriphResetCmd(RCC_APB1Periph_SPI2, ENABLE);
        RCC_APB1PeriphResetCmd(RCC_APB1Periph_SPI2, DISABLE);

        /*---------------------------- SPIx CR1 Configuration ------------------------
       *
       * BIDIMode(双向数据模式使能) = 0 :选择2线的单向数据模式(1:选择单线双向数据模式)。
       * BIDIOE(双向模式输出使能) = 0 :输出禁止,只收模式(1:输出使能,只发模式)。
       * *注* BIDIOE和BIDIMode决定了通讯的“双线单向模式”、“单线双向模式”和“单线单向模式”。
       * CRCEN(硬件CRC使能) = 0 :禁用CRC计算(1:CRC计算使能)。
       * CRCNEXT(下一个发送CRC) = 0 :下个发送的值来自发送缓冲器(1:下个发送的值来自CRC寄存器).
       * CRCL(CRC的数据长度) = x (0:8位CRC长度)(1:16位CRC长度).
       * RxONLY = 0 :全双工(1:只收模式)。
       * SSM(软件从机管理) = 0 :禁止软件从设备管理(1:启用软件从设备管理,NSS引脚的电平由SSI位决定)。
       * SSI(内部从设备选择) = x 决定了NSS引脚的电平。
       * LSBFirst(帧格式) = 0 :先发送MSB(1:先发送LSB)。
       * SPE(SPI使能) = 0 :禁止SPI设备(1:开启SPI设备)。
       * BR(波特率控制) = value (通信速率为{fPCLK/(2^})。
       * MSTR(主设备选择) = 0 :配置为从设备(1:配置为主设备)。
       * CPOL(时钟极性) = value (0:空闲状态下SCK保持低电平)(1:空闲状态SCK保持高电平)。
       * CPHA(时钟相位) = value (0:第一个时钟边沿开始数据采样)(1:第二个时钟边沿开始数据采样)。
       *---------------------------------------------------------------------------*/

        SPI2->CR1 &= 0x0000;
        SPI2->CR1 |= (uint16_t)(BaudRatePCLKDiv | CPOL | CPHA_Edge);

        /*---------------------------- SPIx CR2 Configuration ------------------------
       *
       * DS(数据长度) = 0111b :8位(0011b~1111b:4位~16位数据长度)。
       *---------------------------------------------------------------------------*/
        SPI2->CR2 &= 0xF0FF;
        SPI2->CR2 |= 0x0700;

        /*---------------------------- SPIx CRCPOLY Configuration --------------------
       *
       * CRCPOLY(数据长度) = 0x0007 :默认的复位值是0x0007。(复位过后可忽略)
       *---------------------------------------------------------------------------*/
        //SPI2->CRCPR = 0x0007;

        /*---------------------------- Activate the SPI mode -------------------------
       *
       * I2SMODE(I2S模式选择) = 0 :选择SPI模式(选择I2S模式)。
       *---------------------------------------------------------------------------*/
        SPI2->I2SCFGR &= 0xF7FF;       

        SPI_RxFIFOThresholdConfig(SPI2, SPI_RxFIFOThreshold_QF);

        SPI_Cmd(SPI2, ENABLE);
}

Dylan疾风闪电 发表于 2015-1-5 20:52:29

主循环部分代码:
uint8_t temp;
......

int main()
{
        NVIC_InitTypeDef NVIC_InitStructure;

        ......

        connectSPI1ToExt(SPI_BaudRatePrescaler_32, SPI_CPOL_Low, SPI_CPHA_1Edge);

        connectSPI2SlaveToExt(SPI_BaudRatePrescaler_32, SPI_CPOL_Low, SPI_CPHA_1Edge);
        SPI_I2S_ITConfig(SPI2, SPI_I2S_IT_RXNE, ENABLE);       
        SPI_I2S_ITConfig(SPI2, SPI_I2S_IT_TXE, ENABLE);

        //Interrupts
        NVIC_InitStructure.NVIC_IRQChannel = SPI2_IRQn;
        NVIC_InitStructure.NVIC_IRQChannelPriority = 0;
        NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
        NVIC_Init(&NVIC_InitStructure);

        NVIC_InitStructure.NVIC_IRQChannel = EXTI4_15_IRQn;
        NVIC_InitStructure.NVIC_IRQChannelPriority = 1;
        NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
        NVIC_Init(&NVIC_InitStructure);

        while(1)
        {
                DELAY_MS(500);               
                SPI1_SS_Low;
                DELAY_MS(10);
                       
                for(int i=0; i<4; i++)
                {
                        temp = 0;
                               
                        while (!(SPI1->SR & 0x2));               
                        SPI_SendData8(SPI1, 0x00);
                       
                        while (!(SPI1->SR & 0x1));               
                        temp = SPI_ReceiveData8(SPI1);
                }
                       
                DELAY_MS(10);
                SPI1_SS_High;;
                DELAY_MS(500);
        }
}

Dylan疾风闪电 发表于 2015-1-5 20:59:18

请各位帮忙看一下,中断处理函数是不是存在什么问题?
因为从设备启用了硬件NSS,所以在片选为高的情况下,硬件应答是0xFF;同时在片选上升沿通过EXTI中断复位偏移量(offsetbits)。
----------------------------------------------------------------------------------------------------
收到数据0x00后,依次发送spi_TxBuff的【31:24】【23:16】【15:8】【7:0】。:)

Dylan疾风闪电 发表于 2015-1-12 16:43:45

自己顶一下,哪位高工来看一下,这个问题怎么解决?

6874577 发表于 2015-1-13 12:48:25

:)这个问题怎么解决?

Dylan疾风闪电 发表于 2015-1-13 16:40:21

6874577 发表于 2015-1-13 12:48
这个问题怎么解决?

我就是想知道啊!不知道程序哪边有问题,重点怀疑是中断函数中的处理机制。

发表于 2015-1-13 17:40:47

在SPI发送中加断点,看一下发送的时候的spi_TxBuff数据是多少,另外看一下offsetbits值是多少。

Dylan疾风闪电 发表于 2015-1-13 21:54:31

spi_TxBuff=0x007053b0;
offsetbits = 24;

mlxy123xy 发表于 2015-1-14 00:16:39

从机应答丢失首字节,你试试从机响应的首字节加点延迟。
页: [1] 2
查看完整版本: STM32F030的硬件SPI从模式,从机应答时丢失首个字节?