STM32下CMA3000的SPI驱动程序

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_I			0x00
#define REVID				0x01
#define CTRL				0x02
#define STATUS				0x03
#define RSTR				0x04
#define INT_STATUS			0x05
#define DOUTX				0x06
#define DOUTY				0x07
#define DOUTZ				0x08
#define MDTHR				0x09
#define MDFFTMR				0x0A
#define FFTHR				0x0B
#define I2C_ADDR			0x0C

/* Control Register setup  */
// G_RANGE
#define G_RANGE_2			0x80  // 2g range 
// INT_LEVEL
#define INT_LEVEL_LOW			0x40  // INT active high 
// MDET_EXIT
#define MDET_NO_EXIT			0x20  // Remain in motion detection mode 
// I2C_DIS
#define I2C_DIS				0x10  // I2C disabled 
// MODE[2:0]
#define MODE_PD				0x00  // Power Down 
#define MODE_100			0x02  // Measurement mode 100 Hz ODR 
#define MODE_400			0x04  // Measurement mode 400 Hz ODR 
#define MODE_40				0x06  // Measurement mode 40 Hz ODR 
#define MODE_MD_10			0x08  // Motion detection mode 10 Hz ODR 
#define MODE_FF_100			0x0A  // Free fall detection mode 100 Hz ODR 
#define MODE_FF_400			0x0C  // Free fall detection mode 400 Hz ODR 
// INT_DIS
#define INT_DIS				0x01  // 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;
}


你可能感兴趣的:(c,command,cmd,initialization)