硬件平台:微雪nRF51822开发板
软件平台:MDK522
SDK版本:SDK5
nRF51822的任意管脚可以配置成SPI的管脚,其官方给的代码有一个SPI_master,里面只有两个函数:spi_master_init 和 spi_master_tx_rx,前面一个是初始化函数,后面一个是双向传输函数。
1. nRF51822 SPI的使用
在spi_master_config.h 文件里面配置管脚信息
// SPI0.
#define SPI_PSELSCK0 25u /**< SPI clock GPIO pin number. */
#define SPI_PSELMOSI0 24u /**< SPI Master Out Slave In GPIO pin number. */
#define SPI_PSELMISO0 23u /**< SPI Master In Slave Out GPIO pin number. */
#define SPI_PSELSS0 30u /**< SPI Slave Select GPIO pin number. */
// SPI1.
#define SPI_PSELSCK1 19u /**< SPI clock GPIO pin number. */
#define SPI_PSELMOSI1 20u /**< SPI Master Out Slave In GPIO pin number. */
#define SPI_PSELMISO1 22u /**< SPI Master In Slave Out GPIO pin number. */
#define SPI_PSELSS1 21u /**< SPI Slave Select GPIO pin number. */
初始化函数
spi_base_address = spi_master_init(SPI0,SPI_MODE0,false); //选择SPI0,mode0,lsb false
传输函数:选择为SPI0,传输的size,然后是两个数据线的buff
bool spi_master_tx_rx(uint32_t *spi_base_address, uint16_t transfer_size, const uint8_t *tx_data, uint8_t *rx_data)
2. adxl362的驱动编写
在官网(http://www.analog.com/cn/products/mems/accelerometers/adxl362.html#product-documentation)上有驱动的上层代码,主要是初始化和寄存器的一些操作。需要我们自己编写底层的SPI的操作,而且driver里面SPI是有write和read函数的,我们需要使用spi_master_tx_rx这个函数来完成操作。
2.1 读一个寄存器的数据
首先需要读取ID值,我们改进的函数为:
bool ADXL362_ReadOneReg(u8_t Reg, u8_t* Data)
{
/* Write transaction */
uint8_t transfer_size = 3; //先是read命令,然后是寄存器地址,最后是数据
SPIMasterBuffer[0] = ADXL362_READ_REG; //read命令
SPIMasterBuffer[1] = Reg; //寄存器地址
spi_master_tx_rx((uint32_t *)NRF_SPI0,transfer_size,SPIMasterBuffer,SPISlaveBuffer); //进行数据双向传输
/* Send received value back to the caller */
*Data = SPISlaveBuffer[2]; //在MISO线上第三个数据则是ID数据
return true;
}
bool ADXL362_WriteOneReg(u8_t WriteAddr, u8_t Data)
{
SPIWriteLength = 3; //write命令+寄存器地址+写入的数据
SPIReadLength = 0;
SPIMasterBuffer[0] = ADXL362_WRITE_REG;
SPIMasterBuffer[1] = WriteAddr;
SPIMasterBuffer[2] = (Data);
/* Check if we got an ACK or TIMEOUT error */
spi_master_tx_rx((uint32_t *)NRF_SPI0,SPIWriteLength,SPIMasterBuffer,SPISlaveBuffer);
return true;
}
void ADXL362_GetRegisterValue(unsigned char* pReadData,
unsigned char registerAddress,
unsigned char bytesNumber)
{
unsigned char M_buffer[32]; //MOSI的数据
unsigned char S_buffer[32]; //MISO的数据
unsigned char index = 0;
/* Write transaction */
uint8_t transfer_size = bytesNumber + 2; //读取多个数据,再加上读取命令和开始地址
M_buffer[0] = ADXL362_READ_REG; //读取命令
M_buffer[1] = registerAddress; //开始地址
spi_master_tx_rx((uint32_t *)NRF_SPI0,transfer_size,M_buffer,S_buffer); //传输了读取命令,然后开始读取
/* Send received value back to the caller */
for(index = 0; index < bytesNumber; index++)
{
pReadData[index] = S_buffer[index + 2]; //除去前面两个之后,后面的都是MISO上读取到的寄存器数据
}
}
void ADXL362_SetRegisterValue(unsigned short registerValue,
unsigned char registerAddress,
unsigned char bytesNumber)
{
SPIWriteLength = bytesNumber+2;
SPIReadLength = 0;
SPIMasterBuffer[0] = ADXL362_WRITE_REG;
SPIMasterBuffer[1] = registerAddress;
SPIMasterBuffer[2] = (registerValue & 0x00FF); //we can get the last 8 bit
SPIMasterBuffer[3] = (registerValue >> 8); //we can get the first 8 bit
/* Check if we got an ACK or TIMEOUT error */
spi_master_tx_rx((uint32_t *)NRF_SPI0,SPIWriteLength,SPIMasterBuffer,SPISlaveBuffer);
}
2.5 初始化函数
bool ADXL362_Init(void)
{
unsigned char regValue = 0;
spi_base_address = spi_master_init(SPI0,SPI_MODE0,false);
if (spi_base_address == 0) {
printf("the spi is not ok\r\n");
}
spi_master_enable(SPI0);
ADXL362_GetRegisterValue(®Value, ADXL362_REG_PARTID, 1);
if((regValue == ADXL362_PART_ID))
{
// printf("the acc is on, and the geten id is %d\r\n",regValue);
ADXL362_WriteOneReg(ADXL362_REG_FILTER_CTL, 0x10);
ADXL362_WriteOneReg(ADXL362_REG_INTMAP2, 0x01);
ADXL362_WriteOneReg(ADXL362_REG_POWER_CTL, 0x02);
return true;
}
else{
return false;
}
}
3. debug的状态
SPI出了问题,使用示波器发现SPI的时钟产生一两个之后就停了,完整的时钟信号都没有。
在确定各种初始化都没问题之后,发现产生的时钟的频率也不对,在调低了时钟速率之后,这个问题得到了解决,从1M变成125K之后变好了,再调上1M也是好的,所以最终是啥问题不可得知,但是如果遇到时钟信号都没有的情况,先把速率调至最低试试。