SD card on ESP32 with radiohead

I was trying to work out the sd card on heltec lora board together with lora and GPS.
The device need to:
1. get geo info from GPS.
2. Send out through lora.
3. record in sd card.

I have done the 1 and 2, but blocked on 3. since sd and lora both use spi interface.

I was not so familiar with SPI interface, nor how sw lib was written. It took me a while to make sd card read write works on heltec board.
https://ldsrc.blogspot.tw/2018/02/micro-sd-card-for-esp32.html

Now, how to make both work?
I think I have solved the questions on pins:
SPI   SCK     MISO    MOSI      CS
Lora   05          19          27         18    (with reset at 14)
SD      05          19          27         21

when I tested SD, I pull up 18 to high, to make lora unselected, so that they stay tri state on MISO....this works both on hard wired, or using digital write.

I start to search on how to make 2 spi devices works together on a same bus.
Here is a very good example here:
https://www.circuitsathome.com/mcu/running-multiple-slave-devices-on-arduino-spi-bus/

To understand a little bit on SPI, there is a clock line from master, which is idle if not used, and CS is normally high, and write low by master to signal device to work. when CS is high, the device "should keep on tri-state", which means it does not influence other lines.
So need to find out how to arrange CS, not sure if each lib arrange correctly.
But according to toturial, you need to declair it as out put.

Beside the CS, there are some parameters in SPI spec.
good tutorial here:http://tronixstuff.com/2011/05/13/tutorial-arduino-and-the-spi-bus/
1. Frequency
2. Bit order
3. mode

So, have to check the above 3 items used in radiohead lib and sd lib.
I'm not so familiar with C lib, and the radio head lib seems to be more complicated.

Frequency:

SD part:
In the Arduino_projects\hardware\espressif\esp32\libraries\SD\src\SD.h
there is:
    bool begin(uint8_t ssPin=SS, SPIClass &spi=SPI, uint32_t frequency=4000000, const char * mountpoint="/sd");
which indicate me that the frequency of sd lib is 4M

RadioHead:
from RH_RF95.cpp:
RH_RF95::RH_RF95(uint8_t slaveSelectPin, uint8_t interruptPin, RHGenericSPI& spi)
did not see any varable to assign frequency, but did found a default value in RHHardwareSPI.cpp the default seems to be 1000000

Bit order and mode:

I did not found any in SD lib, but in the esp32\libraries\spi\scr\SPI.cpp
it seems to have default value at: MODE0 and MSBFIRST
  _spi = spiStartBus(_spi_num, _div, SPI_MODE0, SPI_MSBFIRST);
    if(!_spi) {
        return;
    }
From  RH_RF95_h I found it include <RHSPIDriver.h>
then it include
#include <RHGenericDriver.h>
#include <RHHardwareSPI.h>
In the RHHardwareSPI.cpp there are several platform dependant setting about setDataMode, setBitOrder, setFrequency, but I could not find ESp32, only esp8266
which has defaut case in swith option:
default:
     SPI.setDataMode ( SPI_MODE0 );
// bitorder
     SPI.setBitOrder(_bitOrder == BitOrderLSBFirst ? LSBFIRST : MSBFIRST);
default:
     SPI.setFrequency(1000000);

So, combine the above infomation, it seems that only the frequency is different, and sd lib can adjust frequency to 1000000, it seems that keep RH lib and modi(or not the sd lib could be a solution)

I took the example of  radiohead RF95 client example and add/modi as following:

#include <SPI.h> 
#include <RH_RF95.h>

#include "FS.h"
#include "SD.h"

#define RFM95_CS 18 //
#define RFM95_RST 14 
#define RFM95_INT 26

// Change to 434.0 or other frequency, must match RX's freq!
#define RF95_FREQ 433E6 //915.0

// Singleton instance of the radio driver
RH_RF95 rf95(RFM95_CS, RFM95_INT);

void setup() 
{
  Serial.begin(115200);
  delay(100);
 // manual reset
  digitalWrite(RFM95_RST, LOW);
  delay(10);
  digitalWrite(RFM95_RST, HIGH);
  delay(10);
  while (!rf95.init()) {
    Serial.println("LoRa radio init failed");
    while (1);
  }
  Serial.println("LoRa radio init OK!");

    pinMode(RFM95_CS, OUTPUT);
  digitalWrite(RFM95_CS, HIGH);
  
 if (SD.begin(21,SPI,1000000)) { //spi on heltec lora oled, with 21 for sd cs, 
    Serial.println("SD initialization OK");  
    }else{
    Serial.println("SD initialization failed");    
            }
  // Defaults after init are 434.0MHz, modulation GFSK_Rb250Fd250, +13dbM
  if (!rf95.setFrequency(RF95_FREQ)) {
    Serial.println("setFrequency failed");
    while (1);
  }
  Serial.print("Set Freq to: "); Serial.println(RF95_FREQ);
    // Defaults after init are 434.0MHz, 13dBm, Bw = 125 kHz, Cr = 4/5, Sf = 128chips/symbol, CRC on
  // The default transmitter power is 13dBm, using PA_BOOST.
  // If you are using RFM95/96/97/98 modules which uses the PA_BOOST transmitter pin, then 
  // you can set transmitter powers from 5 to 23 dBm:
  rf95.setTxPower(23, false);
  Serial.println("Sending to rf95_server");
}
int16_t packetnum = 0;  // packet counter, we increment per xmission
void loop()
{
  // Send a message to rf95_server
    char radiopacket[20] = "Hello World #      ";
  itoa(packetnum++, radiopacket+13, 10); // convert int to string
  Serial.print("Sending "); Serial.println(radiopacket);
  radiopacket[19] = 0;
   Serial.println("Sending..."); delay(10);
  rf95.send((uint8_t *)radiopacket, 20);
  Serial.println("Waiting for packet to complete..."); delay(10);
  rf95.waitPacketSent();
   Serial.println("packet Sent");
/*
  // Now wait for a reply
  uint8_t buf[RH_RF95_MAX_MESSAGE_LEN];
  uint8_t len = sizeof(buf);

  Serial.println("Waiting for reply..."); delay(10);
  if (rf95.waitAvailableTimeout(1000))
  { 
    // Should be a reply message for us now   
    if (rf95.recv(buf, &len))
   {
      Serial.print("Got reply: ");
      Serial.println((char*)buf);
      Serial.print("RSSI: ");
      Serial.println(rf95.lastRssi(), DEC);    
    }
    else
    {
      Serial.println("Receive failed");
    }
  }
  else
  {
    Serial.println("No reply, is there a listener around?");
  }

  */
 // sd_logging();
  delay(1000);
  while(packetnum > 10){ }//
}

Init of both devices return OK,and lora sending seems ok. But I did not get any data on the receiver side.
summary:
I write lora chip select to high and inited the sd card, it returns ok, and then set lora frequency and sending. not thing report failed, but I did not get any thing on the receiver side.
update: It turns out that I change the frequency in a stupid way. the tutorial of adfruit use 915.0, and I set to 433E6, the lib does not reply with error, but seems wrong on setting frequency. Maybe I should try 433.0

After understanding this mistake from my part, I decided to fist use the default frequency for testing which is 434.0
with SD card inited, the sending and receiving are both correct.

Then I play with the SD_test functions, this lib provide several functions:

   // createDir(SD, "/mydir");
   // listDir(SD, "/", 0);
  //  removeDir(SD, "/mydir");
  //  listDir(SD, "/", 2);
   // writeFile(SD, "/test.txt", "12345");
   // writeFile(SD, "/test.txt", "02");
   // appendFile(SD, "/test.txt", "World!\n");
  //  readFile(SD, "/hello.txt");
  //  deleteFile(SD, "/test.txt");
  //  renameFile(SD, "/hello.txt", "/foo.txt");
    readFile(SD, "/test.txt");
   listDir(SD, "/", 0);
 //   testFileIO(SD, "/test.txt");

if I use write.File, it will clear the file and write your string, and this lastest one is the one to stay on card.
So, for a series of logging, it would be right to use append. if the file name does not exist the first time, it create for you.
The I managed to make a demo on sending data through lora then log into sd card.(rf95_client_esp32_SD_3.ino)

留言

這個網誌中的熱門文章

Install Network Time Protocol(NTP) on BeagleBone with Angstrom linux and set local time zone

AIS0. understanding AIS NMEA 0183: How it's coded

GeoSetter how to add geotag on to pictures, and export to google earth as kmz