打印
[STM32F1]

STM32的SPI采用DMA方式传输测试

[复制链接]
713|2
手机看帖
扫描二维码
随时随地手机跟帖
跳转到指定楼层
楼主
734774645|  楼主 | 2016-3-23 10:42 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式

环境:

主机:WIN7

开发环境:MDK4.23

MCU:STM32F103CBT6

SPI传输数据分为连续传输和非连续传输.

当在主模式下发送数据时,如果软件足够快,能够在检测到每次TXE的上升沿(或TXE中断),并立即在正在进行的传输结束之前写入SPI_DR寄存器,则能够实现连续的通信;此时,在每个数据项的传输之间的SPI时钟保持连续,同时BSY位不会被清除。

简而言之,就是要及时监测TXE.在SPI在1M以上波特率传输时,传输一位时间为1us,导致软件不能及时判断,此时可以用dma的方式来进行SPI传输.


配置:

#define buffersize 512

#define SPI1_DR_Addr ( (u32)0x4001300C )

extern uint8_t SPI1_TX_Buff[buffersize];
extern uint8_t SPI1_RX_Buff[buffersize];
void SPI1_DMA_Configuration( void )
{

    RCC->AHBENR |= 1<<0 ;                     //DMA1时钟使能

        /*------------------配置SPI1_RX_DMA通道Channel2---------------------*/

    DMA1_Channel2->CCR &= ~( 1<<14 ) ;        //非存储器到存储器模式
        DMA1_Channel2->CCR |=    2<<12   ;        //通道优先级高
        DMA1_Channel2->CCR &= ~( 3<<10 ) ;        //存储器数据宽度8bit
        DMA1_Channel2->CCR &= ~( 3<<8  ) ;        //外设数据宽度8bit
        DMA1_Channel2->CCR |=    1<<7    ;        //存储器地址增量模式
        DMA1_Channel2->CCR &= ~( 1<<6  ) ;        //不执行外设地址增量模式
        DMA1_Channel2->CCR &= ~( 1<<5  ) ;        //执行循环操作
        DMA1_Channel2->CCR &= ~( 1<<4  ) ;        //从外设读

        DMA1_Channel2->CNDTR &= 0x0000   ;        //传输数量寄存器清零
        DMA1_Channel2->CNDTR = buffersize ;       //传输数量设置为buffersize个

        DMA1_Channel2->CPAR = SPI1_DR_Addr ;      //设置外设地址,注意PSIZE
        DMA1_Channel2->CMAR = (u32)SPI1_RX_Buff ; //设置DMA存储器地址,注意MSIZE

        /*------------------配置SPI1_TX_DMA通道Channel3---------------------*/

        DMA1_Channel3->CCR &= ~( 1<<14 ) ;        //非存储器到存储器模式
        DMA1_Channel3->CCR |=    0<<12   ;        //通道优先级最低
        DMA1_Channel3->CCR &= ~( 3<<10 ) ;        //存储器数据宽度8bit
        DMA1_Channel3->CCR &= ~( 3<<8 )  ;        //外设数据宽度8bit
        DMA1_Channel3->CCR |=    1<<7    ;        //存储器地址增量模式
        DMA1_Channel3->CCR &= ~( 1<<6 )  ;        //不执行外设地址增量模式
        DMA1_Channel3->CCR &= ~( 1<<5 ) ;         //不执行循环操作
        DMA1_Channel3->CCR |=    1<<4    ;        //从存储器读

        DMA1_Channel3->CNDTR &= 0x0000   ;        //传输数量寄存器清零
        DMA1_Channel3->CNDTR = buffersize ;       //传输数量设置为buffersize个
       
        DMA1_Channel3->CPAR = SPI1_DR_Addr ;      //设置外设地址,注意PSIZE
        DMA1_Channel3->CMAR = (uint32_t)SPI1_TX_Buff ; //设置DMA存储器地址,注意MSIZE                                 
}


沙发
734774645|  楼主 | 2016-3-23 10:42 | 只看该作者
接收与发送:
void SPI1_ReceiveSendByte( u16 num )
{
        DMA1_Channel2->CNDTR = 0x0000   ;           //传输数量寄存器清零
        DMA1_Channel2->CNDTR = num ;         //传输数量设置为buffersize个

        DMA1_Channel3->CNDTR = 0x0000   ;           //传输数量寄存器清零
        DMA1_Channel3->CNDTR = num ;         //传输数量设置为buffersize个

        DMA1->IFCR = 0xF0 ;                         //清除通道2的标志位
        DMA1->IFCR = 0xF00 ;                        //清除通道3的标志位

        SPI1->DR ;                                                                        //接送前读一次SPI1->DR,保证接收缓冲区为空

        while( ( SPI1->SR & 0x02 ) == 0 );
       
        DMA1_Channel3->CCR |= 1 << 0 ;              //开启DMA通道3
        DMA1_Channel2->CCR |= 1 << 0 ;              //开启DMA通道2       

        while( ( DMA1->ISR & 0x20 ) == 0 );

        DMA1_Channel3->CCR &= ~( 1 << 0 ) ;         //关闭DMA通道3
        DMA1_Channel2->CCR &= ~( 1 << 0 ) ;         //关闭DMA通道2

}
//SPI发送一个字节
static uint8 SPI_SendByte(uint8 Data)
{
        #ifndef SPI_DMA
       
        // Loop while DR register in not emplty
        while( SPI_I2S_GetFlagStatus( SPI1, SPI_I2S_FLAG_TXE ) == RESET ) ;

        // Send byte through the SPI1 peripheral
        SPI_I2S_SendData( SPI1, Data ) ;

        // Wait to receive a byte
        while( SPI_I2S_GetFlagStatus( SPI1, SPI_I2S_FLAG_RXNE ) == RESET ) ;

        // Return the byte read from the SPI bus
        return SPI_I2S_ReceiveData( SPI1 ) ;
       
        #else

        SPI1_TX_Buff[0] = Data;
        SPI1_ReceiveSendByte(1);

        return (SPI1_RX_Buff[0]);
        #endif
}

//SPI读取Len字节
void SPI_ReadBytes( uint8 Addr, NtrxBufferPtr Buffer, uint8 Len )
{
        #ifndef SPI_DMA
        if( ( Len > 0x80 ) || ( Len == 0 ) )
                Len = 1 ;
        SPI_SendByte( Len ) ;
        SPI_SendByte( Addr ) ;
        while( Len-- )
            {
                    *Buffer = SPI_SendByte( 0xFF ) ;
                Buffer ++ ;
        }
        #else

        uint8 i = 0;

        if( ( Len > 0x80 ) || ( Len == 0 ) )
                Len = 1 ;

        SPI1_TX_Buff[0] = Len;
        SPI1_TX_Buff[1] = Addr;

        SPI1_ReceiveSendByte(Len + 2);

        for (i = 0;i < Len;i++)
        {
                 *Buffer++ = SPI1_RX_Buff[i + 2];       
        }
        #endif
}


使用特权

评论回复
板凳
玄德| | 2016-3-23 11:24 | 只看该作者

SPI接口的Rx、Tx行为都可以触发DMA,直接用更快。
貌似LZ不是这样做?

使用特权

评论回复
发新帖 我要提问
您需要登录后才可以回帖 登录 | 注册

本版积分规则

191

主题

3428

帖子

14

粉丝