nRF51822 SPI 驅動 ADXL362
阿新 • • 發佈:2019-01-04
硬體平臺:微雪nRF51822開發板
軟體平臺:MDK522
SDK版本:SDK5
nRF51822的任意管腳可以配置成SPI的管腳,其官方給的程式碼有一個SPI_master,裡面只有兩個函式:spi_master_init 和 spi_master_tx_rx,前面一個是初始化函式,後面一個是雙向傳輸函式。
1. nRF51822 SPI的使用
在spi_master_config.h 檔案裡面配置管腳資訊
此處的SPI0為我們需要使用的,與ADXL8632進行連線// 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的驅動編寫
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; }
2.2 寫一個暫存器的資料
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;
}
2.3 改進官方的讀取多個暫存器的函式
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上讀取到的暫存器資料
}
}
2.4 改進官方的寫兩個暫存器的函式
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也是好的,所以最終是啥問題不可得知,但是如果遇到時鐘訊號都沒有的情況,先把速率調至最低試試。