STM32下CMA3000的SPI驱动程序

来源:互联网 发布:重新分区后数据恢复 编辑:程序博客网 时间:2024/05/22 17:26

STM32固件库对SPI的支持相当得好,但要理解以下几点,不然对使用不当。

当时写了一个CMA3000的驱动程序,主要是使用SPI接口完成一些相应的配置操作,然后读出数据。

但在调试的时候遇到了一些困难,程序读出的数据一直是0x3A,无论读取什么寄存器也是这一个值。

当时郁闷了好久,接上示波器观察波形,发出0x3A是在MCU向CMA3000发送地址时MISO上的值。

并且有一个很重要的发现:SCK只有8个clk,这是不应该的,因为在发送完地址后,还有一次读取的过程,

按我的理解应该还有一次8个clk出现,这样才能读出数据,但后来发出,只有在MOSI写入的时候才会有SCK,

也就是说,如果数据是在addr被写入后的下一次SCK出现,那么应该再写一次!

只有写入时才会有SCK!

找到这个问题之后,所有的问题都解决了。

另外SPI还有好几种模式,主要是在idle时SCK是高电平还是低电平,还有就是上升沿触发还是下降沿触发。

具体用哪一种模式要根据器件的手册来定。

具体的代码如下:

#ifndef __CMA3000_H__#define __CMA3000_H__#include "HKY_timer.h"void CMA3000_init(void);u8 CMA3000_getMotionState(void);u8 CMA3000_read(u8 addr);u8 CMA3000_write(u8 addr, u8 cmd);u8 CMA3000_getXYZ(u8 *px, u8 *py, u8 *pz);#endif // __CMA3000_H__

#include "HKY_cma3000.h"#define CMA_SPI SPI1#define CMA_APB_SPI RCC_APB2Periph_SPI1#define CMA_PIN_PORT GPIOA#define CMA_PIN_NSS GPIO_Pin_4#define CMA_PIN_SCK GPIO_Pin_5#define CMA_PIN_MISO GPIO_Pin_6#define CMA_PIN_MOSI GPIO_Pin_7#define CMA3000_CS_LOW() GPIO_ResetBits(CMA_PIN_PORT, CMA_PIN_NSS)#define CMA3000_CS_HIGH() GPIO_SetBits(CMA_PIN_PORT, CMA_PIN_NSS)// CMA3000 寄存器#define WHO_AM_I0x00#define REVID0x01#define CTRL0x02#define STATUS0x03#define RSTR0x04#define INT_STATUS0x05#define DOUTX0x06#define DOUTY0x07#define DOUTZ0x08#define MDTHR0x09#define MDFFTMR0x0A#define FFTHR0x0B#define I2C_ADDR0x0C/* Control Register setup  */// G_RANGE#define G_RANGE_20x80  // 2g range // INT_LEVEL#define INT_LEVEL_LOW0x40  // INT active high // MDET_EXIT#define MDET_NO_EXIT0x20  // Remain in motion detection mode // I2C_DIS#define I2C_DIS0x10  // I2C disabled // MODE[2:0]#define MODE_PD0x00  // Power Down #define MODE_1000x02  // Measurement mode 100 Hz ODR #define MODE_4000x04  // Measurement mode 400 Hz ODR #define MODE_400x06  // Measurement mode 40 Hz ODR #define MODE_MD_100x08  // Motion detection mode 10 Hz ODR #define MODE_FF_1000x0A  // Free fall detection mode 100 Hz ODR #define MODE_FF_4000x0C  // Free fall detection mode 400 Hz ODR // INT_DIS#define INT_DIS0x01  // Interrupts enabled extern void HKY_delayUs(vu32 m);extern void HKY_delayMs(vu32 m);static void CMA3000_SPI_init(){    GPIO_InitTypeDef GPIO_InitStructure;    SPI_InitTypeDef  SPI_InitStructure;    RCC_APB2PeriphClockCmd( RCC_APB2Periph_GPIOA , ENABLE  );    // configure SCK, MISO, MOSI pins    GPIO_InitStructure.GPIO_Pin = CMA_PIN_SCK | CMA_PIN_MISO | CMA_PIN_MOSI;    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;    /*GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_OD;*/    GPIO_Init(CMA_PIN_PORT, &GPIO_InitStructure);    // configure NSS pin    GPIO_InitStructure.GPIO_Pin = CMA_PIN_NSS;    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;    GPIO_Init(CMA_PIN_PORT, &GPIO_InitStructure);    //SPI port initialization     RCC_APB2PeriphClockCmd(CMA_APB_SPI, ENABLE);     SPI_Cmd(CMA_SPI, DISABLE);    SPI_InitStructure.SPI_Direction = SPI_Direction_2Lines_FullDuplex;     SPI_InitStructure.SPI_Mode = SPI_Mode_Master;//SPI_Mode_Slave;    SPI_InitStructure.SPI_DataSize = SPI_DataSize_8b;    SPI_InitStructure.SPI_CPOL = SPI_CPOL_Low; // SCK is low when idle    SPI_InitStructure.SPI_CPHA = SPI_CPHA_1Edge; //rising edge    SPI_InitStructure.SPI_NSS = SPI_NSS_Soft;    SPI_InitStructure.SPI_BaudRatePrescaler = SPI_BaudRatePrescaler_256;    SPI_InitStructure.SPI_FirstBit = SPI_FirstBit_MSB;    SPI_Init(CMA_SPI, &SPI_InitStructure);     SPI_Cmd(CMA_SPI, ENABLE);       }u8 CMA3000_write(u8 addr, u8 cmd){    u8 ret;    addr = (addr << 2) | 0x02;    CMA3000_CS_LOW();    HKY_delayUs(10);        // read to clear rx flag    ret = SPI_I2S_ReceiveData(CMA_SPI);       // send address     while((SPI_I2S_GetFlagStatus(CMA_SPI, SPI_I2S_FLAG_TXE))==RESET);    SPI_I2S_SendData(CMA_SPI, addr);    // wait    while( (SPI_I2S_GetFlagStatus(CMA_SPI, SPI_I2S_FLAG_RXNE)) == RESET );    ret = SPI_I2S_ReceiveData(CMA_SPI);    // send command    while((SPI_I2S_GetFlagStatus(CMA_SPI, SPI_I2S_FLAG_TXE))==RESET);    SPI_I2S_SendData(CMA_SPI, cmd);    // wait     while( (SPI_I2S_GetFlagStatus(CMA_SPI, SPI_I2S_FLAG_RXNE)) == RESET );    ret = SPI_I2S_ReceiveData(CMA_SPI);    HKY_delayUs(10);    CMA3000_CS_HIGH();        return ret;}u8 CMA3000_read(u8 addr){    u8 ret;    addr = (addr << 2);    CMA3000_CS_LOW();    HKY_delayUs(10);    // clear rx flag    ret = SPI_I2S_ReceiveData(CMA_SPI);        // send address    while((SPI_I2S_GetFlagStatus(CMA_SPI, SPI_I2S_FLAG_TXE))==RESET);    SPI_I2S_SendData(CMA_SPI, addr);    // wait    while( (SPI_I2S_GetFlagStatus(CMA_SPI, SPI_I2S_FLAG_RXNE)) == RESET );    ret = SPI_I2S_ReceiveData(CMA_SPI);    // dummy write    while((SPI_I2S_GetFlagStatus(CMA_SPI, SPI_I2S_FLAG_TXE))==RESET);    SPI_I2S_SendData(CMA_SPI, 0);    // read    while( (SPI_I2S_GetFlagStatus(CMA_SPI, SPI_I2S_FLAG_RXNE)) == RESET );    ret = SPI_I2S_ReceiveData(CMA_SPI);        HKY_delayUs(10);    CMA3000_CS_HIGH();    return ret;}u8 CMA3000_getMotionState(){    u8 ret = 0x0;    ret = CMA3000_read(INT_STATUS);    return ( (ret & 0x03) != 0);}void CMA3000_reset(){    // writing 0x02, 0x0A, 0x04 to reset ASIC    CMA3000_write(RSTR, 0x02);    HKY_delayUs(50);    CMA3000_write(RSTR, 0x0A);    HKY_delayUs(50);    CMA3000_write(RSTR, 0x04);    HKY_delayUs(50);}void CMA3000_init(){    CMA3000_SPI_init();        CMA3000_reset();    HKY_delayMs(100);    CMA3000_write(MDTHR, 0x02);  //143 mg    HKY_delayUs(50);    CMA3000_write(MDFFTMR, 0x10);  //100 ms    HKY_delayUs(50);    /*CMA3000_write(CTRL, 0x38); */    CMA3000_write(CTRL, MDET_NO_EXIT | I2C_DIS | MODE_MD_10);         HKY_delayUs(50);    HKY_delayMs(50);    CMA3000_getMotionState();    HKY_delayMs(50);    CMA3000_getMotionState();    HKY_delayMs(50);    CMA3000_getMotionState();}u8 CMA3000_getXYZ(u8 *px, u8 *py, u8 *pz){    *px = CMA3000_read(DOUTX);    HKY_delayUs(50);    if (*px == 0xff)return -1;    *py = CMA3000_read(DOUTY);    HKY_delayUs(50);    if (*py == 0xff)return -1;    *pz = CMA3000_read(DOUTZ);    HKY_delayUs(50);    if (*pz == 0xff)return -1;    return 0;}