打印
[学习笔记]

【AC7811开发板试用活动】4. SPI Master

[复制链接]
4283|9
手机看帖
扫描二维码
随时随地手机跟帖
跳转到指定楼层
楼主
pq113_6|  楼主 | 2019-10-21 08:45 | 只看该作者 |只看大图 回帖奖励 |倒序浏览 |阅读模式
一共有2SPI,频率范围为f bus /512f bus /2,以默认的48Mfbus频率为例,SPICLK频率范围为96K24MAC78xxSPIM CS可以由硬件控制,这点和STM32不同。

1.      相应的SPIM的IO配置
SPI1IO如下:
#define SPI1_CS_PIN                     (GPIO_PA0)
#define SPI1_SCK_PIN                    (GPIO_PA1)
#define SPI1_MISO_PIN                   (GPIO_PA2)
#define SPI1_MOSI_PIN                   (GPIO_PA3)
GPIO_SetFunc(SPI1_CS_PIN,   GPIO_FUNC_1);
GPIO_SetFunc(SPI1_SCK_PIN,  GPIO_FUNC_1);
GPIO_SetFunc(SPI1_MISO_PIN, GPIO_FUNC_1);
GPIO_SetFunc(SPI1_MOSI_PIN, GPIO_FUNC_1);

SPI2IO如下:
#define SPI2_CS_PIN                     (GPIO_PB11)
#define SPI2_SCK_PIN                    (GPIO_PB12)
#define SPI2_MISO_PIN                   (GPIO_PB13)
#define SPI2_MOSI_PIN                   (GPIO_PB14)
GPIO_SetFunc(SPI2_CS_PIN,   GPIO_FUNC_1);
GPIO_SetFunc(SPI2_SCK_PIN,  GPIO_FUNC_1);
GPIO_SetFunc(SPI2_MISO_PIN, GPIO_FUNC_1);
GPIO_SetFunc(SPI2_MOSI_PIN, GPIO_FUNC_1);

2.      初始化SPI
初始化函数原型:
int32_t SPI_Initialize(SPI_Type *SPIx,SPI_ConfigType *config)
SPIx对应SPI1SPI2,参数config的结构原型如下:
typedef struct
{
   SPI_SettingType setting;
   uint8_t sckHigh;
   uint8_t sckLow;
   uint8_t csHold;
   uint8_t csSetup;
} SPI_ConfigType, *SPI_ConfigPtr;
sckHighsckLow分别定义SCK的高低电平用几个总线时钟,0表示一个时钟,同时也能得到SPI的频率,计算公式如下:
f SCL =f bclk /(SCK_LOW+1+SCK_HIGH+1)
csHold是通信结束后CS维持的时间(以总线时钟为单位)。
csSetup是通信开始时(CS拉低后)多久时间(以总线时钟为单位)后SCK才开始变化。
参数setting的结构原型如下:
typedef struct
{
   uint32_t csIdle                    :8;        ///< CS Idle Time
   uint32_t txEmptyIntEn              :1;
   uint32_t rxFullIntEn                :1;
   uint32_t txUnderflowIntEn          :1;
   uint32_t rxOverflowIntEn           :1;
   uint32_t master                    :1;        ///< 1:Master0:Slave
   uint32_t modeErrorIntEn            :1;
   uint32_t dmaTxEn                   :1;
    uint32_t dmaRxEn                    :1;
   uint32_t cpol                      :1;
   uint32_t cpha                      :1;
   uint32_t txMsbFirst                :1;        ///< TX MSB First
   uint32_t rxMsbFirst                :1;        ///< RX MSB First
   uint32_t frmSize                   :4;
   uint32_t csOutputEn                :1;        ///< CS HardwareOutput Enable
   uint32_t modeFaultEn               :1;
   uint32_t continuousCSEn            :1;         ///< CS Continuous Output Enable
   uint32_t wakeUpEn                  :1;
   uint32_t spiEn                     :1;
   uint32_t swReset                   :1;
   uint32_t intEn                     :1;
   uint32_t                           :1;
}SPI_SettingType;
csIdle是通信结束后(CS拉高)保持高电平的时间。
sckHigh/sckLow/csHold/csSetup/csIdle的关系可以参考下图理解
Master表示SPI是使用Master还是Slave
dmaTxEn表示DMA发送使能;
dmaRxEn表示DMA接收使能;
cpolcpoh组合表示SPI的模式;
txMsbFirst表示发送是高位在前还是低位在前;
rxMsbFirst表示接收是高位在前还是低位在前;
frmSize设置帧大小,支持4-16bits,值的范围为0-15,一般为7
csOutputEn使能CS是否由硬件控制输出;
modeFaultEn使能主机模式故障检测,1 使能多主机检测功能;
continuousCSEn 使能CS 连续输出,1 CS 输出连续;
wakeUpEn使能从机唤醒功能;
spiEn初始化SPI
intEn使能SPI中断;
txEmptyIntEn/ rxFullIntEn/ txUnderflowIntEn/rxOverflowIntEn/ modeErrorIntEn/ swReset
未使用;

一组初始化例程:
         spiConfig.sckHigh= 0;                                                    //24MHz
   spiConfig.sckLow = 0;
spiConfig.setting.master= ENABLE;          //Master
   spiConfig.setting.intEn  =DISABLE;         //Disable interrupt
   spiConfig.setting.txMsbFirst = ENABLE;      //tx MSB
   spiConfig.setting.rxMsbFirst = ENABLE;      //rx MSB
   spiConfig.setting.csOutputEn = DISABLE;     //Disable CS hardware output
   spiConfig.setting.continuousCSEn = DISABLE; //No need if use GPIOcontrols CS
   spiConfig.setting.frmSize = 7;              //frame size is 8bit
   spiConfig.setting.cpha = 0;                 //SPI Mode 0
   spiConfig.setting.cpol = 0;
   spiConfig.setting.spiEn = ENABLE;

   SPI_Initialize(SPIx, &spiConfig);
3.      读写函数
SPI是全双工的,对应的API函数是SPI_TransferPoll,其函数原型为:
int32_t SPI_TransferPoll(SPI_Type *SPIx,uint16_t *rdBuff, uint16_t *wrBuff, uint32_t length)
返回值0表示成功,其他则表示错误。

这个函数要求rdBuffwrBuff都不能为NULL,而实际上一般应用只会把SPI当作半双工,所以修改一下库函数,另外,这个API函数的rdbufwrbuf都是16bit的,一般是用8bit的,需要改成8 bit的方式,干脆不调用库函数,根据库函数自己建立一个API函数
void spimTransferBytes(uint8_t port,uint8_t* wrBuf, uint8_t* rdBuf, uint16_t len)
{
   //SPI_TransferPoll(spimGroup[port], rdBuf, wrBuf, (uint32_t)len);
   SPI_Type* SPIx = spimGroup[port];
   uint32_t  i = 0;

   if (!len)
    {
       return;
    }

   for (i = 0; i < len; i++)
    {
       while (!SPI_IsTxEF(SPIx));
       if(wrBuf == NULL)
           SPI_WriteDataReg(SPIx, 0xff);
       else
           SPI_WriteDataReg(SPIx, wrBuf);
       while (!SPI_IsRxFF(SPIx));
       if(rdBuf == NULL)
           SPI_ReadDataReg(SPIx);
       else
           rdBuf = SPI_ReadDataReg(SPIx);
    }
   while ((SPI_IsBusy(SPIx)));
   SPI_CSRelease(SPIx);
}
使用SPI接口的彩屏驱动芯片验证SPI Master功能已经能正常显示。
SPI使用SPI2,频率为24MHzCS脚用软件控制(即初始化csOutputEn= DISABLE
利用驱动芯片内部1MBRAM测试一下SPI的通信效率,测试代码如下:
uint8_t buffer[1024 * 8] = {0};
uint16_t len = 1024 * 8, i;
uint32_t offset = 0;
for(i = 0; i < len; i++)
{
buffer = (i& 0xff);
}
gTimerDelayCount = 1000; //10 seconds
for(i = 0; i < (1024 * 1024) / len; i++)
{
ft8xxWrMemBuf(RAM_G+ offset, buffer, len);
offset += len;
}
Printf("SPI write time:%d(ms)\n",((1000 - gTimerDelayCount) * TIMER_MS));
gTimerDelayCount是在一个10ms的时间中断中不停的减一。验证结果如下:
频率
速率
24M
1200ms : 0.85MB
12M
1470ms : 0.70MB
6M
2120ms : 0.48MB
3M
3300ms : 0.31MB
1.5MB
5790ms : 0.18MB

使用特权

评论回复

相关帖子

沙发
TechHolder| | 2019-10-21 09:09 | 只看该作者

使用特权

评论回复
板凳
JasonLee27| | 2019-10-21 10:01 | 只看该作者
赞,我也觉得用库函数限制太多,不如自己写的好

使用特权

评论回复
地板
pq113_6|  楼主 | 2019-10-21 10:10 | 只看该作者

正在研究SPI DMA,你们手上有没有例程,我这边跑不起来

使用特权

评论回复
5
yubing823| | 2021-11-29 11:34 | 只看该作者
在使用spi时,调试发现TXEF一直为1是什么原因啊。

使用特权

评论回复
6
pq113_6|  楼主 | 2021-11-29 13:52 | 只看该作者
yubing823 发表于 2021-11-29 11:34
在使用spi时,调试发现TXEF一直为1是什么原因啊。

初始化的问题吧,SPI通讯从机不工作也可以读写的,肯定是主机这边有什么地方有错

使用特权

评论回复
7
ulystronglll| | 2022-5-28 16:28 | 只看该作者
这个可以做从机spi吗  

使用特权

评论回复
8
pixhw| | 2022-5-28 16:48 | 只看该作者
硬件组合比较复杂了。  

使用特权

评论回复
9
robertesth| | 2022-5-28 17:40 | 只看该作者
是硬件spi吗?

使用特权

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

本版积分规则

36

主题

284

帖子

2

粉丝