在线时间6057 小时
UID3426478
注册时间2017-9-25
NXP金币5148
TA的每日心情 | 慵懒 2024-4-9 17:01 |
---|
签到天数: 1478 天 [LV.10]以坛为家III
超级版主
- 积分
- 92609
- 最后登录
- 2024-4-9
|
本帖最后由 stm1024 于 2018-11-21 09:44 编辑
这次测试了一下LPC11U68的SSP接口,该接口可以实现多种协议:SPI、SSI或者Microwire 。其中SPI应该是应用的比较多的一种串行协议。使用SPI需要做的就是打开时钟,配置波特率,设置工作模式等。以SSP0为例,测试代码:
- void SPI0_Init(uint8_t mode)
- {
- uint8_t x=0;
- LPC_IOCON->PIO0[2]=IOCON_FUNC1|IOCON_MODE_PULLUP;//CS
- LPC_IOCON->PIO1[29]=IOCON_FUNC1|IOCON_MODE_PULLUP;//CLK
- LPC_IOCON->PIO0[9]=IOCON_FUNC1|IOCON_MODE_PULLUP;//MOSI
- LPC_IOCON->PIO0[8]=IOCON_FUNC1|IOCON_MODE_PULLUP;//MISO
- LPC_SYSCTL->SYSAHBCLKCTRL|=(1UL<<11);//SSP0
- LPC_SYSCON->SSP0CLKDIV=0x01;//Peripheral clock
- LPC_SYSCON->PRESETCTRL|=(1UL<<0);//Reset
- LPC_SSP0->CPSR=0x08;//prescaler
- //8-bit transfer,SPI, MODE3
- LPC_SSP0->CR0=0x07|(mode<<6)|(59<<8);
- //baudrate=SYSCLK/SSP0CLKDIV/CPSR/(SCR+1)
- //so:48000000/1/8/(59+1)=100kbps
- LPC_SSP0->ICR=0x03;
- LPC_SSP0->CR1|=1UL<<1;//enable
- //clear RX FIFO
- while((LPC_SSP0->SR & (1UL<<2))!=0x00)x=LPC_SSP0->SR;
- }
复制代码 其实CS、MISO、MOSI或SCLK有多个针脚可供配置:
SSP0_SSEL: P0.2(FUNC1) P1.15(FUNC1)
SSP0_SCK: P0.6(FUNC2) P0.10(FUNC2) P1.29(FUNC1) P2.7(FUNC1)
SSP0_MOSI: P0.9(FUNC1) P1.12(FUNC1)
SSP0_MISO: P0.8(FUNC1) P1.16(FUNC1)
这里选用的是P0.2,P1.29,P0.8,P0.9,因为这四个位置刚好在开发板的Arduino插口上挨着的:
然后是通讯的波特率,通过SSP时钟分频、预分频和SCR,配置为100kbps,当然配置为400kbps也行,这应该是应用的最多的两种波特率。
由于SPI的工作原理类似于主从之间形成了一个循环移位寄存器,你给多少位数据,就能获取多少位数据,非常有意思的一种协议,以下是交换数据代码:
- uint8_t SPI0_SwapByte(uint8_t dat)
- {
- uint8_t x;
- LPC_SSP0->DR=dat;
- while((LPC_SSP0->SR & (1UL<<2))!=0x00)//only need the most recent 1 byte
- x=LPC_SSP0->DR & 0xff;
- while((LPC_SSP0->SR & (1UL<<4))!=0x00);//wait to idle
- return x;
- }
复制代码 上面的代码,交换完字节后,CS就会被硬件拉高。由于SPI总线的CS是由硬件拉低和拉高的,在时序上似乎并没有像STM32那样,使用软件控制的方式那么直观,通读了user manual整章节,也没有发现关于SSEL的软件控制方式,这个代码并不能实现多字节的传输,在多字节发送的时候就有点麻烦。
在帖子:https://www.nxpic.org.cn/module/forum/thread-606606-1-1.html?qd中,提到了用一般的GPIO口做CS,这个自然没问题,但是我总感觉NXP作为一个具有这么多年芯片设计的大厂,不会想到用这种ugly的方式来实现,肯定有别的方法。
经过测试,我认为我找到了一个合理的解决方法,那就是监控总线状态,只要FIFO中有数据,SSP就会传输,则总线在处于Busy,CS一定是拉低的,一旦传输完成,下一个时钟周期CS就会被硬件拉高,标识传输完成。
首先, 丢出多字节发送的代码:
- //len<=8
- void SPI0_Swap(uint8_t* txbuff,uint8_t* rxbuff,int8_t len)
- {
- uint8_t i;
- for(i=0;i<len;i++)
- {
- LPC_SSP0->DR=txbuff[i];
- rxbuff[i]=LPC_SSP0->DR & 0xff;
- }
- while((LPC_SSP0->SR & (1UL<<4))!=0x00);//wait to idle
- }
复制代码 LPC11U68的SSP带有FIFO,好像是8帧,如果你不停地给DR寄存器中写入数据,则在FIFO为空之前,CS是会一直被拉低的,直到总线传输完成。
以W25Q32这种SPI接口的Flash为例:
读取JEDEC ID的代码:
- uint32_t W25Q32_JEDEC_ID(void)
- {
- uint8_t cc[4]={0x9f,0x00,0x00,0x00};
- SPI0_Swap(cc,cc,4);
- return (cc[1]<<16)|(cc[2]<<8)|(cc[3]);
- }
复制代码 结果应该是:
通过逻辑分析仪抓数据:
如果采用反复调用单字节交换的方式:
可以看到,MISO中的数据是不对的,因为CS有短暂的时间被拉高。
如果换第二种方式,就没有什么问题了:
同样可以看到,CS在这四个字节传输时一直处于拉低状态,而且返回的字节也符合文档的说明。最后还有一个写字节的时序,涉及到了三个操作,前面0x06和后面的0x04分别是允许写入和锁止写入,中间是实际的写字节,看CS的确实都拉高了
|
|