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.beginSD.beginSPI.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 读取 0xADInitialize 设置 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.

更改为正确的类型解决了问题。我会删除这个问题,因为它归结为一个打字错误,但是一旦发布了答案,系统就不允许这样做。