STM 32下CMA 3000のSPIドライバ
6705 ワード
STM 32ファームウェアライブラリはSPIのサポートはかなり良いですが、以下の点を理解してください.そうしないと、使用が適切ではありません.
当時、CMA 3000のドライバが書かれていましたが、主にSPIインタフェースを使用して対応する構成操作を完了し、データを読み出しました.
しかし、デバッグ中にいくつかの困難に直面し、プログラムが読み出したデータはずっと0 x 3 Aであり、どんなレジスタを読み出してもこの値である.
長い間気がふさいでいたが、オシロスコープに接続して波形を観察し、0 x 3 AはMCUがCMA 3000にアドレスを送信したときのMISO上の値だった.
そして重要な発見があります:SCKは8つのclkしかありません.これはすべきではありません.アドレスを送信した後、もう1回の読み取りの過程があるからです.
私の理解ではもう1回8つのclkが現れるはずです.そうすればデータを読み出すことができますが、後で送信され、MOSIが書き込まれたときだけSCKがあります.
つまり、addrが書き込まれた次のSCKにデータが現れたら、もう一度書くべきです!
SCKは書き込み時のみ!
この問題を見つけてから、すべての問題が解決しました.
またSPIにはいくつかのモードがあり、主にidle時にSCKがハイレベルかローレベルか、上昇エッジがトリガするか下降エッジがトリガするかである.
具体的にどのモードを使うかはデバイスのマニュアルに基づいて決めます.
具体的なコードは以下の通りです.
当時、CMA 3000のドライバが書かれていましたが、主にSPIインタフェースを使用して対応する構成操作を完了し、データを読み出しました.
しかし、デバッグ中にいくつかの困難に直面し、プログラムが読み出したデータはずっと0 x 3 Aであり、どんなレジスタを読み出してもこの値である.
長い間気がふさいでいたが、オシロスコープに接続して波形を観察し、0 x 3 AはMCUがCMA 3000にアドレスを送信したときのMISO上の値だった.
そして重要な発見があります:SCKは8つのclkしかありません.これはすべきではありません.アドレスを送信した後、もう1回の読み取りの過程があるからです.
私の理解ではもう1回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;
}