这久在做一个无线数传模块的驱动,需要写一个CC2530的SPI驱动,结果弄了两个晚上,这个芯片有些地方实在是很有意思。
它的datasheet里面对于SPI的极性和相位的解释,很复杂。

其实,这里完全可以说的比较明了。
CPOL为0时,空闲的时候SCK为低电平。当CPOL为1时,空闲的时候SCK为高电平。
CPHA呢,当等于1时,在第二个边沿采样,当它为0时,在第一个边沿采样。
然后,对于SPI速率的配置,给了个公式

不过,这公式我个人认为不太实用,毕竟SPI通信,尽量还是用那几个经典的波特率,下面的这张表,这比上面这公式实用的多。

接着,引脚的选择,datasheet里面又给了张表,

这个SSN脚是从机可以把这个映射到外设,但是主机就不用拘于这个引脚,因为

它说主机需要自己选择SSN脚,用GPIO模式,软件控制。所以任意GPIO脚都行。
但是CC2530作为主机时候的接收就比较奇葩。因为它的设计机制实在是天马行空。它把UxBUFF变成了一个doubleBUFF,然后在发送的同时,它就开启了接收。
因为速率是匹配的,所以,发送完成的时候,接收也就完成了。所以,为了和正常的外设联调,当我们需要读取数据时,我们需要先向UxBUFF里面灌进数据,这样才能输出时钟,然后读的标志位是UxCSR.TX_BYTE,并不是UxCSR.RX_BYTE!!!

由上图可以知道,RX_BYTE只有在从机模式的时候才有效,TX_BYTE则在主机模式的时候才有效。
下面附上接收代码。
它的datasheet里面对于SPI的极性和相位的解释,很复杂。
其实,这里完全可以说的比较明了。
CPOL为0时,空闲的时候SCK为低电平。当CPOL为1时,空闲的时候SCK为高电平。
CPHA呢,当等于1时,在第二个边沿采样,当它为0时,在第一个边沿采样。
然后,对于SPI速率的配置,给了个公式
不过,这公式我个人认为不太实用,毕竟SPI通信,尽量还是用那几个经典的波特率,下面的这张表,这比上面这公式实用的多。
接着,引脚的选择,datasheet里面又给了张表,
这个SSN脚是从机可以把这个映射到外设,但是主机就不用拘于这个引脚,因为
它说主机需要自己选择SSN脚,用GPIO模式,软件控制。所以任意GPIO脚都行。
接着重头戏来了。CC2530作为主机时候的发送比较简单,只用配置好后,像UXBUFF里面写入数据,这时它就会自动发送,这时,只用一直读取UxCSR.TX_BYTE位就行,当它为1时就发送完成了。
void SPI_Write(unsigned char Command)
{
U1DBUF = Command;
while (!(U1CSR&0x02)){} //等待发送完成
U1CSR &= 0xFD;//复位
}
<span style="font-family:Microsoft YaHei;font-size:18px;">void SPI_Write(unsigned char Command)
{
U1DBUF = Command;
while (!(U1CSR&0x02)){} //等待发送完成
U1CSR &= 0xFD;//复位
}</span>
但是CC2530作为主机时候的接收就比较奇葩。因为它的设计机制实在是天马行空。它把UxBUFF变成了一个doubleBUFF,然后在发送的同时,它就开启了接收。
因为速率是匹配的,所以,发送完成的时候,接收也就完成了。所以,为了和正常的外设联调,当我们需要读取数据时,我们需要先向UxBUFF里面灌进数据,这样才能输出时钟,然后读的标志位是UxCSR.TX_BYTE,并不是UxCSR.RX_BYTE!!!
由上图可以知道,RX_BYTE只有在从机模式的时候才有效,TX_BYTE则在主机模式的时候才有效。
下面附上接收代码。
- unsigned char SPI_Read(void)
- {
- U1DBUF = 0x00;//废数据,为了输出SCK时钟
- while (!(U1CSR&0x02)){} //等待发送完成
- U1CSR &= 0xFD;//复位
- unsigned char temp = U1DBUF;//读取UxBUFF时,硬件会自动清零
- return temp;
- }