Arduino SD 卡与其他 SPI 设备一起使用时无法写入
Arduino SD card fails to write when used with another SPI device
我有一个连接到 Adafruit Feather Adalogger 的 ADXL355 加速度计。我可以配置和读取传感器。我还可以将二进制值写入 SD 卡。当我尝试从传感器读取数据然后将该数据写入 SD 卡时出现问题。我唯一能想到的就是我以某种方式搞乱了 SPI 通信,但我看不到哪里。我查看了 pins_arduino.h
我的电路板,SD 卡(引脚 4)与引脚 10 在不同的寄存器上,所以我看不出我是如何破坏东西的。
我的操作是这样进行的。全局传感器创建,Serial.begin
,SD.begin
,SPI.begin
,测试传感器连接,在 SD 卡上创建输出文件,初始化传感器,读取传感器 FIFO,写入文件,永远重复最后 2 个。
文件已创建,但文件大小仍为 0,即实际上没有任何内容写入卡。
传感器可以以 4 kHz 的频率运行,这使用 digitalWrite
函数很难实现,所以我转而使用 Feather 上的端口寄存器。我是这样做的:
#include <SM_ADXL355_SPI_fast.h>
#include <SPI.h>
#include <SD.h>
#define cardSelect 4
ADXL355_SPIF adxl355(&DDRB, &PORTB, _BV(6)); // values taken from pins_arduino.h, tested and working on pin 10
void setup() {
Serial.begin(57600);
while(!Serial){
// wait for Serial
}
SD.begin(cardSelect);
SPI.begin();
while(!adxl355.TestConnection()){
delay(1000);
}
adxl355.OpenFile("TestSPI.bin");
adxl355.Initialize(1, 10, 0); // set range to 2g's, frequency to 4 Hz and filter to off
}
void loop() {
while(true){ // avoid Arduino overhead of their loop function
adxl355.ReadFIFO();
adxl355.WriteFIFOToFile();
}
}
这是 ADXL 构造函数
ADXL355_SPIF::ADXL355_SPIF(volatile uint8_t * outReg, volatile uint8_t * outPort, uint8_t bitValue) : sensorOutReg(outReg), sensorPort(outPort), sensorBitValue(bitValue){
*sensorOutReg |= sensorBitValue;
*sensorPort |= sensorBitValue;
sensorWriteCount = 0;
}
TestConnection
测试 DeviceID 读取 0xAD
。 Initialize
设置 G 范围、以 Hz 为单位的采样率和滤波器。我已经用串行输出测试了它们,它们工作正常。
OpenFile
看起来像这样:
bool ADXL355_SPIF::OpenFile(const String& fileName){
sensorFile = SD.open(fileName, FILE_WRITE);
if (!sensorFile){
Serial.print("Could not create file: ");
Serial.println(fileName);
return false;
}
return true;
}
在 运行 之后,SD 卡上确实创建了一个名为 "TESTSPI.BIN" 的文件,文件大小为 0。
ReadFIFO
读取 FIFO 中的条目数,存储为 fifoCount
,然后使用 FIFO 中的值填充缓冲区 (sensorFIFO[32][3]
)。我已将此缓冲区打印到 Serial 以表明它正在工作。这是那个函数
void ADXL355_SPIF::ReadFIFO(){
ReadRegister(ADXL355_RA_FIFO_ENTRIES, 1);
fifoCount = buffer[0];
ReadFIFOInternal();
return;
}
void ADXL355_SPIF::ReadFIFOInternal(){
SPI.beginTransaction(SPISettings(10000000, MSBFIRST, SPI_MODE0));
*sensorPort &= ~sensorBitValue;
uint8_t spiCommand = ADXL355_RA_FIFO_DATA << 1 | ADXL355_READ;
SPI.transfer(spiCommand);
int i = 0;
unsigned long tempV;
unsigned long value;
while(i < fifoCount){
for (int ptr = 0; ptr < 3; ++ptr){
buffer[0] = SPI.transfer(0x0);
value = buffer[0];
value <<= 12;
tempV = SPI.transfer(0x0);
tempV <<= 4;
value |= tempV;
tempV = SPI.transfer(0x0);
tempV >>=4;
value |= tempV;
if (buffer[0] & 0x80) {
value |= 0xFFF00000;
}
long lValue = static_cast<long>(value);
sensorFIFO[i][ptr] = scaleFactor * lValue;
}
i += 3;
}
SPI.endTransaction();
*sensorPort |= sensorBitValue;
return;
}
这里是WriteFIFOToFile
:
void ADXL355_SPIF::WriteFIFOToFile(){
if (fifoCount > 0){
sensorFile.write(reinterpret_cast<const char *>(&sensorFIFO), 4 * fifoCount);
}
sensorWriteCount += fifoCount;
if (sensorWriteCount >= 100){
sensorFile.flush();
sensorWriteCount = 0;
}
}
允许 运行 一段时间后,文件大小始终为 0。我尝试了一个简单的二进制写入功能,只是为了测试卡。它看起来像这样并且有效。
#include <SD.h>
#define cardSelectPin 4
const float pi=3.14159;
File oFile;
void setup() {
// put your setup code here, to run once:
Serial.begin(9600);
while(!Serial){
// wait for serial
}
SD.begin(cardSelectPin);
oFile = SD.open("Test.bin", FILE_WRITE);
Serial.println(sizeof(int));
Serial.println(sizeof(float));
float testFloat[32][3];
for (int i = 0; i < 32; ++i){
for (int j = 0; j < 3; ++j){
testFloat[i][j] = pi * (i + 1) + j;
}
}
oFile.write(reinterpret_cast<const char *>(&testFloat), sizeof(float) * 96);
oFile.close();
Serial.println("Finished writing file.");
}
void loop() {
// put your main code here, to run repeatedly:
}
非工作草图和工作草图之间的唯一区别是 sd 卡的关闭。必须关闭 SD 卡,我遇到了同样的问题,我假设文件在文件关闭调用时将其边界写入其文件系统。
要解决您的问题,请使用按钮。当你按下它时,它会关闭文件并停止 reading/processing 个传感器。您也可以使用此按钮再次开始读取和记录 SD 卡上的传感器数据(切换)。
问题是 flush
没有被正确调用。我已经创建了一个缓冲区来保存来自 FIFO 的数据,当它足够满时它会刷新卡,以至于后续读取会溢出。那时它会调用flush
。这就是变量 sensorWriteCount
的用途。这个变量是 uint8_t
类型,而它应该是 uint16_t
.
更改为正确的类型解决了问题。我会删除这个问题,因为它归结为一个打字错误,但是一旦发布了答案,系统就不允许这样做。
我有一个连接到 Adafruit Feather Adalogger 的 ADXL355 加速度计。我可以配置和读取传感器。我还可以将二进制值写入 SD 卡。当我尝试从传感器读取数据然后将该数据写入 SD 卡时出现问题。我唯一能想到的就是我以某种方式搞乱了 SPI 通信,但我看不到哪里。我查看了 pins_arduino.h
我的电路板,SD 卡(引脚 4)与引脚 10 在不同的寄存器上,所以我看不出我是如何破坏东西的。
我的操作是这样进行的。全局传感器创建,Serial.begin
,SD.begin
,SPI.begin
,测试传感器连接,在 SD 卡上创建输出文件,初始化传感器,读取传感器 FIFO,写入文件,永远重复最后 2 个。
文件已创建,但文件大小仍为 0,即实际上没有任何内容写入卡。
传感器可以以 4 kHz 的频率运行,这使用 digitalWrite
函数很难实现,所以我转而使用 Feather 上的端口寄存器。我是这样做的:
#include <SM_ADXL355_SPI_fast.h>
#include <SPI.h>
#include <SD.h>
#define cardSelect 4
ADXL355_SPIF adxl355(&DDRB, &PORTB, _BV(6)); // values taken from pins_arduino.h, tested and working on pin 10
void setup() {
Serial.begin(57600);
while(!Serial){
// wait for Serial
}
SD.begin(cardSelect);
SPI.begin();
while(!adxl355.TestConnection()){
delay(1000);
}
adxl355.OpenFile("TestSPI.bin");
adxl355.Initialize(1, 10, 0); // set range to 2g's, frequency to 4 Hz and filter to off
}
void loop() {
while(true){ // avoid Arduino overhead of their loop function
adxl355.ReadFIFO();
adxl355.WriteFIFOToFile();
}
}
这是 ADXL 构造函数
ADXL355_SPIF::ADXL355_SPIF(volatile uint8_t * outReg, volatile uint8_t * outPort, uint8_t bitValue) : sensorOutReg(outReg), sensorPort(outPort), sensorBitValue(bitValue){
*sensorOutReg |= sensorBitValue;
*sensorPort |= sensorBitValue;
sensorWriteCount = 0;
}
TestConnection
测试 DeviceID 读取 0xAD
。 Initialize
设置 G 范围、以 Hz 为单位的采样率和滤波器。我已经用串行输出测试了它们,它们工作正常。
OpenFile
看起来像这样:
bool ADXL355_SPIF::OpenFile(const String& fileName){
sensorFile = SD.open(fileName, FILE_WRITE);
if (!sensorFile){
Serial.print("Could not create file: ");
Serial.println(fileName);
return false;
}
return true;
}
在 运行 之后,SD 卡上确实创建了一个名为 "TESTSPI.BIN" 的文件,文件大小为 0。
ReadFIFO
读取 FIFO 中的条目数,存储为 fifoCount
,然后使用 FIFO 中的值填充缓冲区 (sensorFIFO[32][3]
)。我已将此缓冲区打印到 Serial 以表明它正在工作。这是那个函数
void ADXL355_SPIF::ReadFIFO(){
ReadRegister(ADXL355_RA_FIFO_ENTRIES, 1);
fifoCount = buffer[0];
ReadFIFOInternal();
return;
}
void ADXL355_SPIF::ReadFIFOInternal(){
SPI.beginTransaction(SPISettings(10000000, MSBFIRST, SPI_MODE0));
*sensorPort &= ~sensorBitValue;
uint8_t spiCommand = ADXL355_RA_FIFO_DATA << 1 | ADXL355_READ;
SPI.transfer(spiCommand);
int i = 0;
unsigned long tempV;
unsigned long value;
while(i < fifoCount){
for (int ptr = 0; ptr < 3; ++ptr){
buffer[0] = SPI.transfer(0x0);
value = buffer[0];
value <<= 12;
tempV = SPI.transfer(0x0);
tempV <<= 4;
value |= tempV;
tempV = SPI.transfer(0x0);
tempV >>=4;
value |= tempV;
if (buffer[0] & 0x80) {
value |= 0xFFF00000;
}
long lValue = static_cast<long>(value);
sensorFIFO[i][ptr] = scaleFactor * lValue;
}
i += 3;
}
SPI.endTransaction();
*sensorPort |= sensorBitValue;
return;
}
这里是WriteFIFOToFile
:
void ADXL355_SPIF::WriteFIFOToFile(){
if (fifoCount > 0){
sensorFile.write(reinterpret_cast<const char *>(&sensorFIFO), 4 * fifoCount);
}
sensorWriteCount += fifoCount;
if (sensorWriteCount >= 100){
sensorFile.flush();
sensorWriteCount = 0;
}
}
允许 运行 一段时间后,文件大小始终为 0。我尝试了一个简单的二进制写入功能,只是为了测试卡。它看起来像这样并且有效。
#include <SD.h>
#define cardSelectPin 4
const float pi=3.14159;
File oFile;
void setup() {
// put your setup code here, to run once:
Serial.begin(9600);
while(!Serial){
// wait for serial
}
SD.begin(cardSelectPin);
oFile = SD.open("Test.bin", FILE_WRITE);
Serial.println(sizeof(int));
Serial.println(sizeof(float));
float testFloat[32][3];
for (int i = 0; i < 32; ++i){
for (int j = 0; j < 3; ++j){
testFloat[i][j] = pi * (i + 1) + j;
}
}
oFile.write(reinterpret_cast<const char *>(&testFloat), sizeof(float) * 96);
oFile.close();
Serial.println("Finished writing file.");
}
void loop() {
// put your main code here, to run repeatedly:
}
非工作草图和工作草图之间的唯一区别是 sd 卡的关闭。必须关闭 SD 卡,我遇到了同样的问题,我假设文件在文件关闭调用时将其边界写入其文件系统。
要解决您的问题,请使用按钮。当你按下它时,它会关闭文件并停止 reading/processing 个传感器。您也可以使用此按钮再次开始读取和记录 SD 卡上的传感器数据(切换)。
问题是 flush
没有被正确调用。我已经创建了一个缓冲区来保存来自 FIFO 的数据,当它足够满时它会刷新卡,以至于后续读取会溢出。那时它会调用flush
。这就是变量 sensorWriteCount
的用途。这个变量是 uint8_t
类型,而它应该是 uint16_t
.
更改为正确的类型解决了问题。我会删除这个问题,因为它归结为一个打字错误,但是一旦发布了答案,系统就不允许这样做。