STM32_SPI_笔记

SPI主机负责产生时钟,决定了SPI通信速率。可以同时收发数据;

时钟极性(CPOL)决定同步时钟空闲状态;

时钟相位(CPHA):0:CLK的第一个跳变沿(上升沿或下降沿)数据被采样;

1:CLK的第二个跳变沿数据被采样;


写:主机对SPIX->DR写数据,CLK产生时钟,同时数据从MOSI -> MISO

读:主机对SPIX->DR写DUMMY(空字节),CLK产生时钟,DUMMY信号从MOSI -> MISO (该数据对从机无意义),同时要读取的数据从 MISO -> MOSI,主机从SPIX->DR读取数据。然后清除DR,以便接收下一个数据。

读写SPIX -> DR是两个不同的寄存器。


SPI中断事件:

中断事件 事件标志 使能控制位
发送缓冲器空标志 TXE TXEIE
接收缓冲器非空标志 RXNE RXNEIE
主模式错误事件 MODF ERRIE
溢出错误 OVR
CRC错误标志 CRCERR

案例1:简单SPI对接通信,SPI1主机,SPI3从机,中断方式,主机->从机

初始化代码

//步骤1 使能时钟
void RCC_Configuration(void)
{
    RCC_APB2PeriphClock_Enable(RCC_APB2PERIPH_GPIOA|  RCC_APB2PERIPH_GPIOB |  RCC_APB2PERIPH_GPIOC| RCC_APB2PERIPH_AF , ENABLE);
    RCC_APB2PeriphClock_Enable(RCC_APB2PERIPH_SPI1,ENABLE);
    RCC_APB1PeriphClock_Enable( RCC_APB1PERIPH_SPI3 ,ENABLE );    
}

//步骤2 配置GPIO
void GPIO_Configuration(void)
{
    GPIO_InitPara GPIO_InitStructure;
    GPIO_PinRemapConfig(GPIO_REMAP_SPI3, ENABLE);
    /* Configure SPI_MASTER pins: SCK and MOSI */
    GPIO_InitStructure.GPIO_Pin =  GPIO_PIN_5| GPIO_PIN_7;
    GPIO_InitStructure.GPIO_Speed = GPIO_SPEED_50MHZ;
    GPIO_InitStructure.GPIO_Mode = GPIO_MODE_AF_PP;
    GPIO_Init(GPIOA, &GPIO_InitStructure);
    /* Configure SPI_SLAVE pins: SCK and MISO */
    /* Configure SCK pin as Alternate Function */
    GPIO_InitStructure.GPIO_Pin = GPIO_PIN_10 ;
    GPIO_InitStructure.GPIO_Mode = GPIO_MODE_IN_FLOATING;
    GPIO_Init(GPIOC, &GPIO_InitStructure);
    /* Configure MISO pin as Alternate Function Push Pull */
    GPIO_InitStructure.GPIO_Pin = GPIO_PIN_11;
    GPIO_InitStructure.GPIO_Mode = GPIO_MODE_AF_PP;
    GPIO_Init(GPIOC, &GPIO_InitStructure);
}

//步骤3 配置SPI,SPI1主机 SPI3从机
void SPI_Configuration(void)
{
	SPI_InitPara SPI_InitStructure;
	
	SPI_InitStructure.SPI_TransType = SPI_TRANSTYPE_BDMTX;
    SPI_InitStructure.SPI_Mode = SPI_MODE_MASTER;
    SPI_InitStructure.SPI_FrameFormat = SPI_FRAMEFORMAT_8BIT;
    SPI_InitStructure.SPI_SCKPL = SPI_SCKPL_LOW;
    SPI_InitStructure.SPI_SCKPH = SPI_SCKPH_2EDGE;
    SPI_InitStructure.SPI_SWNSSEN = SPI_SWNSS_SOFT;
    SPI_InitStructure.SPI_PSC = SPI_PSC_16;
    SPI_InitStructure.SPI_FirstBit = SPI_FIRSTBIT_MSB;
    SPI_InitStructure.SPI_CRCPOL = 7;
    SPI_Init(SPI1, &SPI_InitStructure);

    /* SPI_SLAVE configuration */
    SPI_InitStructure.SPI_TransType = SPI_TRANSTYPE_BDMRX;
    SPI_InitStructure.SPI_Mode = SPI_MODE_SLAVE;
    SPI_Init(SPI3, &SPI_InitStructure);
    
    /* Enable SPI_MASTER TBE interrupt */
    SPI_I2S_INTConfig(SPI1, SPI_I2S_INT_TBE, ENABLE);
    /* Enable SPI_SLAVE RBNE interrupt */
    SPI_I2S_INTConfig(SPI3, SPI_I2S_INT_RBNE, ENABLE);
    /* Enable SPI1 AND SPI3 */
    SPI_Enable(SPI3, ENABLE);
    SPI_Enable(SPI1, ENABLE);
}

//步骤4 配置中断
void NVIC_Configuration(void)
{
    NVIC_InitPara NVIC_InitStructure;
    /* 1 bit for pre-emption priority, 3 bits for subpriority */
    NVIC_PRIGroup_Enable(NVIC_PRIGROUP_1);

    /* Configure and enable SPI_MASTER interrupt */
    NVIC_InitStructure.NVIC_IRQ = SPI1_IRQn;
    NVIC_InitStructure.NVIC_IRQPreemptPriority = 1;
    NVIC_InitStructure.NVIC_IRQSubPriority = 2;
    NVIC_InitStructure.NVIC_IRQEnable = ENABLE;
    NVIC_Init(&NVIC_InitStructure);
    
    /* Configure and enable SPI_SLAVE interrupt */
    NVIC_InitStructure.NVIC_IRQ = SPI3_IRQn;
    NVIC_InitStructure.NVIC_IRQPreemptPriority = 0;
    NVIC_InitStructure.NVIC_IRQSubPriority = 1;
    NVIC_InitStructure.NVIC_IRQEnable = ENABLE;
    NVIC_Init(&NVIC_InitStructure);
}

中断函数:

 void SPI1_IRQHandler(void)
{
    if (SPI_I2S_GetIntBitState(SPI1, SPI_I2S_INT_TBE) != RESET)
    {   
        /* Send SPI_MASTER data */
        while (SPI_I2S_GetBitState(SPI1, SPI_FLAG_TBE) == RESET);
        SPI_I2S_SendData(SPI1, SPI_MASTER_Buffer_Tx[ TxIdx++ ]);
        if (TxIdx == BufferSize)
        {
            /* Disable SPI_MASTER TBE interrupt */
            SPI_I2S_INTConfig(SPI1, SPI_I2S_INT_TBE, DISABLE);
        }
    }
}

void SPI3_IRQHandler(void)
{
    /* Store SPI_SLAVE received data */
    if (SPI_I2S_GetIntBitState(SPI3, SPI_I2S_INT_RBNE) == SET)
        SPI_SLAVE_Buffer_Rx[RxIdx++] = SPI_I2S_ReceiveData(SPI3);
}


案例2:DMA_SPI收发

 发送时,在每次TXE被设置为’1’时发出DMA请求,DMA控制器则写数据至SPI_DR寄存器,TXE标志因此而被清除。

接收时,在每次RXNE被设置为’1’时发出DMA请求,DMA控制器则从SPI_DR寄存器读出数据,RXNE标志因此而被清除。

DMA1_CHANNEL2:SPI1_RX

DMA1_CHANNEL3:SPI1_TX


配置DMA代码:

void SPI1_DMA_Configuration( void )
{
    DMA_InitTypeDef DMA_InitStructure;
    
    /* DMA1 Channel2 (triggered by SPI1 Rx event) Config */
  DMA_DeInit(DMA1_Channel2);  
  DMA_InitStructure.DMA_PeripheralBaseAddr = SPI1_DR_Addr;                          //设置 SPI1 发送外设(0x4001300C) 地址(目的地址)
  DMA_InitStructure.DMA_MemoryBaseAddr = (uint32_t)SPI1_RX_Buff;                    //设置 SRAM 存储地址(目的地址)
  DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralSRC;                                //传输方向 外设-内存
  DMA_InitStructure.DMA_BufferSize = SPI1_ReciveBufferSize;                         //设置 SPI1 发送长度
  DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable;
  DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable;
  DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_Byte;
  DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_Byte;
  DMA_InitStructure.DMA_Mode = DMA_Mode_Normal;
  DMA_InitStructure.DMA_Priority = DMA_Priority_VeryHigh;
  DMA_InitStructure.DMA_M2M = DMA_M2M_Disable;
  DMA_Init(DMA1_Channel2, &DMA_InitStructure);
  
  DMA_ITConfig(DMA1_Channel2, DMA_IT_TC, ENABLE);
  /* Enable SPI1 DMA RX request */
  SPI1->CR2 |= 1<<0;                                                                 //接收缓冲区DMA使能
  DMA_Cmd(DMA1_Channel2, ENABLE);
    
    
    /* DMA1 Channel3 (triggered by SPI1 Tx event) Config */
  DMA_DeInit(DMA1_Channel3);  
  DMA_InitStructure.DMA_PeripheralBaseAddr = SPI1_DR_Addr;                          //设置  接收外设(0x4001300C) 地址(源地址)
  DMA_InitStructure.DMA_MemoryBaseAddr = (uint32_t)SPI1_TX_Buff;                    //设置 SRAM 存储地址(源地址)
  DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralDST;                                //传输方向 内存-外设
  DMA_InitStructure.DMA_BufferSize = SPI1_SendBufferSize;                           //设置 SPI1 接收长度
  DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable;                  //外设地址增量(不变)
  DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable;                           //内存地址增量(变化)
  DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_Byte;           //外设传输宽度(字节)
  DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_Byte;                   //内存传输宽度(字节)
  DMA_InitStructure.DMA_Mode = DMA_Mode_Normal;                                     //传输方式,一次传输完停止,不重新加载
  DMA_InitStructure.DMA_Priority = DMA_Priority_VeryHigh;                           //中断方式-高(三级)
  DMA_InitStructure.DMA_M2M = DMA_M2M_Disable;                                      //内存到内存方式禁止
  DMA_Init(DMA1_Channel3, &DMA_InitStructure);
  
  DMA_ITConfig(DMA1_Channel3, DMA_IT_TC, ENABLE);                                   //开启 DMA1_Channel3 传输完成中断
  DMA_ITConfig(DMA1_Channel3, DMA_IT_TE, ENABLE);                                   //开启 DMA1_Channel3 传输错误中断
  /* Enable SPI1 DMA TX request */
  SPI1->CR2 |= 1<<1;                                                                //发送缓冲区DMA使能
  DMA_Cmd(DMA1_Channel3, DISABLE);                                                  //开启 DMA 通道 DMA1_Channel3
}

SPI发送

关闭DMA通道3之前必须等待TXE为1,等待忙标志为0

void SPI1_Send( u8 *buff, u32 len )
{
    DMA1_Channel3->CPAR = SPI1_DR_Addr; //外设地址
    DMA1_Channel3->CMAR = (u32) buff; //mem地址
    DMA1_Channel3->CNDTR = len ; //传输长度
    DMA1_Channel3->CCR = (0 << 14) | // 非存储器到存储器模式
            (2 << 12) | // 通道优先级高
            (0 << 11) | // 存储器数据宽度8bit
            (0 << 10) | // 存储器数据宽度8bit
            (0 <<  9) | // 外设数据宽度8bit
            (0 <<  8) | // 外设数据宽度8bit
            (1 <<  7) | // 存储器地址增量模式
            (0 <<  6) | // 外设地址增量模式(不增)
            (0 <<  5) | // 非循环模式
            (1 <<  4) | // 从存储器读
            (1 <<  3) | // 允许传输错误中断
            (0 <<  2) | // 允许半传输中断
            (1 <<  1) | // 允许传输完成中断
            (1);        // 通道开启
}


SPI接收

必须要先关闭通道2,然后再配置通道2的参数

void SPI1_Recive( u8 *buff, u32 len )
{
    DMA1_Channel2->CCR &= ~( 1 << 0 );          //关闭DMA通道2
    
    DMA1_Channel2->CPAR = SPI1_DR_Addr; //外设地址
    DMA1_Channel2->CMAR = (uint32_t)buff; //mem地址
    DMA1_Channel2->CNDTR = len ; //传输长度
    DMA1_Channel2->CCR = (0 << 14) | // 非存储器到存储器模式
            (2 << 12) | // 通道优先级高
            (0 << 11) | // 存储器数据宽度8bit
            (0 << 10) | // 存储器数据宽度8bit
            (0 <<  9) | // 外设数据宽度8bit
            (0 <<  8) | // 外设数据宽度8bit
            (1 <<  7) | // 存储器地址增量模式
            (0 <<  6) | // 外设地址增量模式(不增)
            (0 <<  5) | // 非循环模式
            (0 <<  4) | // 传输方向 外设-内存
            (0 <<  3) | // 允许传输错误中断
            (0 <<  2) | // 允许半传输中断
            (1 <<  1) | // 允许传输完成中断
            (1);        // 通道开启
}












你可能感兴趣的:(STM32_SPI_笔记)