1. 程式人生 > >nRF51822 SPI 驅動 ADXL362

nRF51822 SPI 驅動 ADXL362

硬體平臺:微雪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. */
此處的SPI0為我們需要使用的,與ADXL8632進行連線

初始化函式

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(&regValue, 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也是好的,所以最終是啥問題不可得知,但是如果遇到時鐘訊號都沒有的情況,先把速率調至最低試試。