Write String to permanent flash memory of Arduino ESP32 - arduino

I want to write some text into the flash memory of an Arduino ESP32. It works kinda but not as I want it to.
void writeString(const char* toStore, int startAddr) {
int i = 0;
for (; i < LENGTH(toStore); i++) {
EEPROM.write(startAddr + i, toStore[i]);
}
EEPROM.write(startAddr + i, '\0');
EEPROM.commit();
}
My call
writeString("TEST_STRING_TO_WRITE", 0);
only writes TEST into the memory. I do not understand why. Is that because of the _? Or am I missing something different?
Here is the used LENGTH macro
#define LENGTH(x) (sizeof(x)/sizeof(x[0]))
and the method I use to read the string from the memory again (which seems to work correctly):
String readStringFromFlash(int startAddr) {
char in[128];
char curIn;
int i = 0;
curIn = EEPROM.read(startAddr);
for (; i < 128; i++) {
curIn = EEPROM.read(startAddr + i);
in[i] = curIn;
}
return String(in);
}

Where on earth did you get that LENGTH macro from? It’s surreal.
sizeof will not do what you want here. It’s a compile-time function that computes the storage requirements of its argument. In this case it should return the length in bytes of a character pointer, not the string it points to.
You want to use strlen(), assuming your char* is a properly terminated C string. Add one to make sure the ‘\0’ at the end gets stored, too.
#define LENGTH(x) (strlen(x) + 1)

Below is the code to demonstrate the storing as well as retrieving of the string ssid in the EEPROM (permanent storage).
#include "EEPROM.h"
int addr = 0;
#define EEPROM_SIZE 64
// the sample text which we are storing in EEPROM
char ssid[64] = "CARNIVAL OF RUST";
void setup() {
Serial.begin(115200);
Serial.println("starting now...");
if (!EEPROM.begin(EEPROM_SIZE)) {
Serial.println("failed to init EEPROM");
while(1);
}
// writing byte-by-byte to EEPROM
for (int i = 0; i < EEPROM_SIZE; i++) {
EEPROM.write(addr, ssid[i]);
addr += 1;
}
EEPROM.commit();
// reading byte-by-byte from EEPROM
for (int i = 0; i < EEPROM_SIZE; i++) {
byte readValue = EEPROM.read(i);
if (readValue == 0) {
break;
}
char readValueChar = char(readValue);
Serial.print(readValueChar);
}
}
void loop() {
}

Related

How to write 16bit integer to SRAM via Arduino?

The base of the problem: I have an Arduino Due and a MPU6050 accelerometer and an 23lcv512. MPU gives me 16bit signed integer. I would like to save the datas to the SRAM and after the measurement read them back and via Serial send it to PC. Sending to PC is not a problem. The problem is that this SRAM has 128k pcs 8bit address. My numbers are 16 bit. I can't write them directly. Here is my code. I tested the RAM with this code:
`
void loop() {
int i = 0;
Serial.print("Write Byte: ");
for (i = 0; i < 70000; i++) {
//Serial.print("Write Byte: ");
//Serial.print(i);
//Serial.println();
SRAM.writeByte(START_ADDRESS, i);
START_ADDRESS = START_ADDRESS + 1;
}
Serial.print("Write End");
i = 0;
START_ADDRESS = 0;
for (i = 0; i < 300; i++) {
Serial.print("Read Byte: ");
Serial.print(SRAM.readByte(START_ADDRESS));
Serial.println();
Serial.println();
START_ADDRESS = START_ADDRESS + 1;
delay(100);
}
}`
I added the 23LC library. If it's run reads back the numbers from the RAM but after 255 it starts to read 0 again. I know why does it happen. But I don't know howto solve the problem.
I tried to use the writeBlock command but it only works for me with char variables. Char variable requires more space than integers. I have not too much.
Is there anyone who can write a sample code which can write 16 bit signed integer to sram?
I've commented the most obvious problems in your original code below:
void loop() {
int i = 0;
Serial.print("Write Byte: ");
for (i = 0; i < 70000; i++) { // since i is a 16bit int, 70,000 is out of range.
SRAM.writeByte(START_ADDRESS, i); // cool you wrote 1 byte, where is the other write?
START_ADDRESS = START_ADDRESS + 1; // try to keep all caps names for constants.
// this will make your code easier to read, trust me!
}
Serial.print("Write End");
i = 0;
START_ADDRESS = 0;
for (i = 0; i < 300; i++) {
Serial.print("Read Byte: ");
Serial.print(SRAM.readByte(START_ADDRESS)); // you read 1 byte, you can't expect a 16 bit
// value out of that.
Serial.println();
Serial.println();
START_ADDRESS = START_ADDRESS + 1;
delay(100);
}
}
Here's a more sound approach, it stores unsigned ints, but that can easily be changed to signed ints.
#define SRAM_SIZE (128UL << 10) // we have 128K of SRAM available.
// The U and L make this value an unsigned long.
// ALWAYS use unsigned values for addresses.
void loop()
{
Serial.print(F("Writing sequential numbers into SRAM...")); // _always_ store string constants in flash.
// save your RAM for more interesting stuff.
for (unsigned long i = 0; i < SRAM_SIZE; i += 2) // filling SRAM
{
// this is the (truncated from 0-65535) value we'll write.
unsigned int value = static_cast<unsigned int>(i & 0xFFFF);
SRAM.writeByte(i, value & 0xFF); // write lowest 8 bits
SRAM.writeByte(i + 1, (value >> 8) & 0xFF); // write next 8 bits.
}
Serial.println(F("done."));
// read back
Serial.println(F("SRAM contents (16-bits unsigned values):"));
for (unsigned long i = 0; i < SRAM_SIZE; i += 2) // reading all SRAM in 16-bit chunks.
{
Serial.print(i, HEX);
Serial.print(F(": "));
// read two consecutive bytes and pack them into a 16-bit integer.
unsigned int value = SRAM.readByte(i) + (static_cast<unsigned int>(SRAM.readByte(i+1)) << 8); // the cast is necessary.
Serial.println(value);
}
delay(100);
}

Arduino global array not modified when accessed over serial?

I'm working on a home automation system, one part of which includes an Arduino Mega2560 connected via USB to a RaspberryPi 3 Model B. The Arduino receives two short, simple commands over serial from the Pi; the first command sets 'regions' of led lights, and the second sets colors on the regions previously described. Syntax is as follows for both commands, where bracketed items are single bytes, len+off are 3 ascii bytes interpreted as base-10, and r+g+b are 2 ascii bytes each interpreted as hex. The color set command supports a variable number of regions as shown:
Region Set Command
!c[regionId][stripId][len2][len1][len0][off2][off1][off0]\r
Color Set Command
!b[r1][r0][g1][g0][b1][b0][numRegions][regionId0]([regionId1]...)\r
Each command sends positive/negative acknowledgements so you'd think I'd be able to tell what's going wrong, but I get unexpected behavior when I try to set light colors with the second command, however, despite getting acknowledgements as expected. So far, the only reasonable conclusion I can come to is that for the global array regions discards changes and stays zero always. For example, this exchange results in no lights lit (comments are not in the actual exchange)
Pi sends: !c00144000\r // create regionId 0 on stripId 0; length 144 offset 0
Pi recieves: O // positive confirmation?
Pi sends: !b00009910\r // set regionId 0 to color 0x000099 (blue)
Pi recieves: O // positive confirmation, but no lights?
Pi sends: !x\r // invalid command; triggers default in switch
Pi recieves: X // as expected, all lights turn red
Here's the stripped down source for the Arduino:
#include "Arduino.h"
#include "FastLED.h"
#define WAIT while(!Serial.available()) ;;
// Forward Declarations
const int max_strips = 2;
const int max_strip_length = 300;
const int max_leds = max_strips * max_strip_length;
CRGB leds[max_strips][max_strip_length];
const int max_regions = 20;
int regions[max_regions][3];
const int baud_rate = 9600;
unsigned char buffer[64];
unsigned char currentByte = 0;
unsigned char incommingByte;
unsigned char startChar = '!';
unsigned char endChar = '\r';
bool store = false;
// Helper Functions
void set(CRGB c) {
for(int i = 0; i < max_strips; i++) {
for(int j = 0; j < max_strip_length; j++) {
leds[i][j] = c;
}
}
}
void set(int stripId, int length, int offset, CRGB c) {
for(int i = offset; i < offset+length; i++) {
leds[stripId][i] = c;
}
}
void setup() {
Serial.begin(baud_rate);
for(int i = 0; i < max_strips; i++) {
switch(i) {
case 0: {
FastLED.addLeds<WS2812B, 2, GRB>(leds[0], max_strip_length);
} break;
case 1: {
FastLED.addLeds<WS2812B, 3, GRB>(leds[1], max_strip_length);
} break;
}
}
set(CRGB::Black);
}
void loop() {
if(Serial.available() > 0) {
unsigned char incomingByte = Serial.read();
if(incomingByte == startChar) {
currentByte = 0;
store = true;
}
if(store) {
if(incomingByte == endChar) {
buffer[currentByte++] = incomingByte;
store = false;
switch(buffer[1]) {
case 'b': {
int red = (buffer[2] - '0')*16 + (buffer[3] - '0');
int green = (buffer[4] - '0')*16 + (buffer[5] - '0');
int blue = (buffer[6] - '0')*16 + (buffer[7] - '0');
int numRegions = buffer[8] - '0';
for(int i = 0; i < numRegions; i++) {
int regionId = buffer[9+i] - '0';
if(regionId >= max_regions) {
Serial.write('S');
return;
}
// Never sets anything
set(regions[regionId][0], regions[regionId][1], regions[regionId][2], CRGB(red, green, blue));
}
Serial.write('O');
} break;
case 'c': {
int regionId = buffer[2] - '0';
int stripId = buffer[3] - '0';
int length = (buffer[4] - '0')*100 + (buffer[5] - '0')*10 + (buffer[6] -'0');
int offset = (buffer[7] - '0')*100 + (buffer[8] - '0')*10 + (buffer[9] -'0');
if(regionId >= max_regions) {
Serial.write('R');
return;
}
if(stripId >= max_strips) {
Serial.write('S');
return;
}
regions[regionId][0] = stripId; // WE LOSE THESE VALUES??
regions[regionId][1] = length; // ??
regions[regionId][2] = offset; // ??
Serial.write('O');
} break;
default: {
set(CRGB::Red);
Serial.write('X');
} break;
}
currentByte = 0;
}else if(currentByte > 64){
store = false;
currentByte = 0;
} else {
buffer[currentByte++] = incomingByte;
}
}
}
FastLED.show();
}
I'd appreciate any advice as to what I'm missing here, and regardless, thanks for reading this far!
This was occurring because I have a lot of garbage showing up on the serial interface for the Arduino I'm testing on. Slowing the baud rate down to 2400bps resolves the issue on this device. Other Arduinos in the system do fine with much higher serial rates -- I suspect there's a hardware problem with the crystal on this particular Arduino so clock speeds aren't matching up correctly between the two sides of the serial connection.

How to use buffer to read and write using serial port in 8051 MCU

I am using keil c51 compiler. I transmit data from my pc to MCU using serial port it works best.
When I transmit data from my MCU to PC then also it works best.
But when I transmit data to MCU and then store it to buffer character pointer and again from that character pointer buffer I transmit return to PC then it does not work and give garbage values?
My code for both function as below.
#include <REG51.H>
#include "uart.c"
void delay_ms(unsigned int x) // delays x msec (at fosc=11.0592MHz)
{
unsigned char j=0;
while(x-- > 0)
{
for (j=0; j<125; j++){;}
}
}
sbit SW = P3^2;
sbit LED = P3^3;
bit x = 0;
void main ()
{
char *buf;
int len=0;
int len1 = 0;
uart_init();
while(1){
if(RI == 1){
UART_RxString(buf,&len);
buf -= (len-1) ;
x = 1;
}
if(x == 1 && SW == 0){
UART_TxString(buf,&len1);
x = 0;
}
}
}
And below are the functions.
1.
void UART_TxString(char *string_ptr, int *l)
{
int count = 0;
while(*string_ptr){
UART_TxChar(*string_ptr++);
count++;
}
*l = count;
}
void UART_RxString(char *string_ptr, int *l)
{
char ch;
int count = 0;
while(1)
{
ch=UART_RxChar(); //Reaceive a char
//UART_TxChar(ch); //Echo back the received char
count++;
if((ch=='\r') || (ch=='\n')) //read till enter key is pressed
{ //once enter key is pressed
*string_ptr=0; //null terminate the string
break; //and break the loop
}
*string_ptr=ch; //copy the char into string.
string_ptr++; //and increment the pointer
}
*l = count;
}

Arduino : Check byte array for chars one at a time

I communicate with Arduino via Serial using a program that sends a series of bytes.
In order for the Arduino to realize it is receiving a message rather than junk, I have tagged the start of my byte array with the chars 'S' 'T' 'A' 'R' 'T'. After this will eventually follow a series of bytes that will be assigned to internal variables (not yet implemented).
The Arduino must read each byte sequentially and compare it to the byte array and if all are present in the correct order it will continue with the next part of the program, otherwise it will should discard current byte and wait for more bytes to arrive.
I am trying to implement it in the most efficient and readable way rather than using a series of nested if statements.
So far I have got:
byte inByte = 0;
byte handShake[] = {'S','T','A','R','T'};
void setup() {
Serial.begin(9600);
}
void loop()
{
while (Serial.available())
{
for (int x =0; x < sizeof(handShake) ; x++)
{
inByte = Serial.read();
Serial.println(x);
if (inByte == handShake[x])
{
if (x == (sizeof(handShake)-1)) {setArduino();}
}
else break;
}
}
}
void setArduino () {
Serial.println("Ready To Set Parameters");
}
This however doesn't seem to get past the second byte and I'm not sure why.
Worked it out :
Here is the answer:
byte inByte = 0;
char handShake[] = {'S','T','A','R','T'};
void setup() {
Serial.begin(9600);
}
void loop()
{
while (Serial.available())
{
for (int x =0; x < sizeof(handShake) ; x++)
{
inByte = Serial.read();
Serial.println(x);
if (inByte == handShake[x])
{
if (x == (sizeof(handShake)-1)) {setArduino();}
while(!Serial.available()) {delay(1);}
}
else {break;}
}
}
}
void setArduino () {
Serial.println("Ready To Set Parameters");
}
This may not be the most efficient way perhaps, but I can't see a problem with it currently.
Better answer : This allows the rest of the loop to iterate while waiting for the message to finish and if the full handshake message isn't received the counter will reset.
byte inByte = 0;
char handShake[] = {'S','T','A','R','T'};
int messageIndex = 0;
void setup() {
Serial.begin(9600);
}
void loop()
{
while (Serial.available())
{
inByte = Serial.read();
Serial.println(messageIndex);
if (inByte == handShake[messageIndex])
{
messageIndex++;
if (messageIndex == sizeof(handShake)) {messageIndex = 0; setArduino();}
}
else {messageIndex=0;}
}
// Other code while waiting for message to finish
Serial.println("tick");
}
void setArduino () {
Serial.println("Ready To Set Parameters");
}
You could try to calculate your message. CRC is old and good solution. I use it and it works perfect for me. I am not sure what kind of device are you communicating with.
//define
const uint32_t Polynomial = 0xEDB88320;
const uint16_t NumBytes = 256;
uint8_t data[NumBytes];
/// compute CRC32
uint32_t crc32_bitwise(const void* data, uint16_t length, uint32_t previousCrc32 = 0)
{
uint32_t crc = ~previousCrc32; // same as previousCrc32 ^ 0xFFFFFFFF
uint8_t* current = (uint8_t*) data;
while (length--)
{
crc ^= *current++;
for (uint8_t j = 0; j < 8; j++)
{
uint8_t lowestBit = crc & 1;
crc >>= 1;
if (lowestBit)
crc ^= Polynomial;
}
}
return ~crc; // same as crc ^ 0xFFFFFFFF
}
void setup() {
// put your setup code here, to run once:
}
void loop() {
// put your main code here, to run repeatedly:
}
when you need to calculate CRC
uint32_t crc = crc32_bitwise(data_bytes, sizeof(data_bytes));
data_bytes is byte array.
Then you can get all settings or message in byte data[x] and calculate CRC. Then you can add CRC to the message and send message byte data[x+sizeof(CRC)]
P.S. Use byte instead of int. For ex. for(byte x =0; x<sizeof(handShake); x++)

Writing data to the Arduino's onboard EEPROM

I am currently trying to write a function to store data to the EEPROM on my Arduino. So far I am just writing a specified string and then reading it back when the program first runs. I am trying to store the length of the string as the first byte and my code is as follows;
#include <EEPROM.h>
#include <LiquidCrystal.h>
LiquidCrystal lcd(8, 13, 9, 4, 5, 6, 7);
char string[] = "Test";
void setup() {
lcd.begin( 16, 2 );
for (int i = 1; i <= EEPROM.read(0); i++){ // Here is my error
lcd.write(EEPROM.read(i));
}
delay(5000);
EEPROM_write(string);
}
void loop() {
}
void EEPROM_write(char data[])
{
lcd.clear();
int length = sizeof(data); // I think my problem originates here!
for (int i = 0; i <= length + 2; i++){
if (i == 0){
EEPROM.write(i, length); // Am I storing the length correctly?
lcd.write(length);
}
else{
byte character = data[i - 1];
EEPROM.write(i, character);
lcd.write(character);
}
}
}
The problem I am having is when I read the first byte of the EEPROM, I get the supposed length value. However, the loop only runs three times. I have commented some points of interest in my code, but where is the error?
You are indeed correct, on many counts, I think. Try this for writing:
// Function takes a void pointer to data, and how much to write (no other way to know)
// Could also take a starting address, and return the size of the reach chunk, to be more generic
void EEPROM_write(void * data, byte datasize) {
int addr = 0;
EEPROM.write(addr++, datasize);
for (int i=0; i<datasize; i++) {
EEPROM.write(addr++, data[i]);
}
}
You would call it like this:
char[] stringToWrite = "Test";
EEPROM_write(stringToWrite, strlen(stringToWrite));
To read then:
int addr = 0;
byte datasize = EEPROM.read(addr++);
char stringToRead[0x20]; // allocate enough space for the string here!
char * readLoc = stringToRead;
for (int i=0;i<datasize; i++) {
readLoc = EEPROM.read(addr++);
readLoc++;
}
Note that this is not using the String class developed for Arduino: reading and writing that would be different. But the above should work for char array strings.
Note however, that while EEPROM_write() looks generic now, it isn't really, since addr is harcoded. It can only write data to the beginning of EEPROM.

Resources