Hello there,
A bit rusty, looking for assistance with the following. I'm using a Arduino MEGA 2560 clone with a 3.5"TFT SDCard combo, LoRa radio and RTC - this is the receiver ofcourse. Receiving packets no problem, saving to SDcard no problem, running the JPG though JPEG Decoder and displaying the BMP onto the TFT no problem. With my limited skillset, i have previously utilised the Whatchdog function in previous projects using the UNO and Nano, seems i cant get the watchdog to reliably reset whilst in the loop using this 2560. The watchdog will reset if utilsed within void setup(), i.e with no SD card preset, but no joy whilst in the the main loop. Ive also tried the Digitalwrite pull down direct to the reset line which also makes the program hang on the second pass, needing a power cycle to start over successfully.
FYI - I have soldered the 2560 SPI pins MOSI, MISO and SCLK to 11, 12 and 13 pins to enable the TFT SD Card function, worked first time therefore not tried the bit bang soft spi route. I have the SPI lines MISO and CS of LoRa and SD card wired up to a tristate buffer and the LoRa SPI lines are running through a Logic converter. Also, i have the TFT pin LCD RST wired to 5V as I want to maintain the previous BMP as a background for the second pass and so on, if i can get the code to run continously i will change it, as mentioned above I was planning on the force reset route.
Yes, it takes a few minutes to recieve a 640x480 jpg, its for a High Altitude Balloon therefore acceptable.
Its all runing spot on, until i reset the arduino using one of the above methods the LoRA module fails, when trying to run continously i.e create a new file and return; for a second pass the JPG render draws the top line of the BMP then hangs. Any assistance gratefully received.
Best regards,
L.
#include <SPI.h>
#include <SD.h>
#include <Wire.h>
#include <RH_RF95.h>
#include <ds3231.h>
#include <JPEGDecoder.h>
//#include <avr/wdt.h>
#define RF95_FREQ 434.23
#define BLACK 0x0000
#define BLUE 0x001F
#define RED 0xF800
#define GREEN 0x07E0
#define CYAN 0x07FF
#define MAGENTA 0xF81F
#define YELLOW 0xFFE0
#define WHITE 0xFFFF
#include <MCUFRIEND_kbv.h>
MCUFRIEND_kbv tft;
#define minimum(a,b) (((a) < (b)) ? (a) : (b))
const int RFM95_CS = 53;
const int RFM95_RST = 48;
const int RFM95_INT = 19;
const int RXSIZE = 64;
const int chipSelect = 10 ; // SD card
const uint8_t ackData[] = {0xAA, 0xCC}; // ack TX
RH_RF95 rf95(RFM95_CS, RFM95_INT);
struct ts t;
char fileName[] = "00000000";
char folderName[] = "000000";
char foldfile[16];
uint8_t crcerr = 0; // CRC disabled for now
uint8_t pckterr = 0;
uint16_t packet_count = 0;
uint16_t packetNumber = 0;
struct PACKET
{
uint16_t packet_count;
uint32_t numBytes;
byte data[RXSIZE];
//uint32_t crc;
};
File my_file;
void setup()
{
Serial.begin(19200);
// ****** Force Reset ******
digitalWrite(38, HIGH); // Reset attempt
pinMode(38, OUTPUT);
// ****** Clock Startup ******
Wire.begin(); // RTC
// ****** TFT Setup ******
uint16_t identifier;
identifier = 0x9486; //TFT ID
tft.begin(identifier);
//tft.fillScreen(BLACK);
tft.setRotation(3);
tft.setTextColor(WHITE, BLUE);
tft.setTextSize(1);
// ****** SD Module Check ******
if (!SD.begin(chipSelect)) { //SD card present?
//Serial.println(F("SD Failed!"));
tft.setTextColor(WHITE, RED);
tft.setCursor(5, 25);
tft.print(F("SD Failed! - Reset in 3 secs..."));
//wdt_enable(WDTO_4S);
//delay(6000);
digitalWrite(38, LOW);
}
else
{
//Serial.println(F("SD OK!"));
tft.setCursor(5, 25);
tft.print(F("SD OK!"));
}
// ****** LoRa Module Reset ******
pinMode(RFM95_RST, OUTPUT); // Reset Radio
digitalWrite(RFM95_RST, LOW);
delay(1000);
digitalWrite(RFM95_RST, HIGH);
delay(100);
// ****** LoRa Module Check ******
if (!rf95.init()) { //Radio initialise
//Serial.println(F("LoRa failed!"));
tft.setTextColor(WHITE, RED);
tft.setCursor(5, 15);
tft.print(F("LoRa Failed! - Reset in 3 secs..."));
digitalWrite(38, LOW);
//wdt_enable(WDTO_4S);
//delay(6000);
}
else {
//Serial.println(F("LoRa OK!"));
tft.setCursor(5, 15);
tft.print(F("LoRa OK!"));
}
// ****** LoRa Module Setup ******
rf95.setModemConfig(RH_RF95::Bw125Cr45Sf128); // Radio settings
//Bw500Cr45Sf128, Bw31_25Cr48Sf512, Bw125Cr48Sf4096
//Bw125Cr45Sf128
rf95.setFrequency(RF95_FREQ);
rf95.setTxPower(5);
//delay(1000);
//lcd.clear();
// ****** Time and File/Folder ******
DS3231_get(&t); // Get time from RTC
// Serial.print(t.mday);
// Serial.print(t.mon);
// Serial.print(t.year);
// Serial.print(t.hour);
// Serial.print(t.min);
folderName[0] = '2'; // Set folder and filename
folderName[1] = t.year % 10 + '0';
folderName[2] = t.mon / 10 + '0';
folderName[3] = t.mon % 10 + '0';
folderName[4] = t.mday / 10 + '0';
folderName[5] = t.mday % 10 + '0';
fileName[0] = t.hour / 10 + '0';
fileName[1] = t.hour % 10 + '0';
fileName[2] = t.min / 10 + '0';
fileName[3] = t.min % 10 + '0';
fileName[4] = '.';
fileName[5] = 'j';
fileName[6] = 'p';
fileName[7] = 'g';
foldfile[0] = '\0';
SD.mkdir(folderName);
strcat (foldfile, folderName);
strcat (foldfile, "/");
strcat (foldfile, fileName);
//Serial.println(foldfile);
tft.setCursor(5, 5);
tft.print(foldfile);
}
void loop()
{
uint8_t buf[sizeof(PACKET)];
uint8_t len = sizeof(buf);
if (rf95.recv(buf, &len)) // RX packet
{
//if (len >= 8) { Need AES for multiple devices
PACKET *rxPacket = (PACKET*)buf;
printPacket((PACKET*)buf);
writefile(rxPacket->data, rxPacket->numBytes);
if (rxPacket->packet_count != packetNumber) // Error detect
{
pckterr ++;
tft.setTextColor(WHITE, RED);
tft.setCursor(420, 15);
tft.print(F("ERR: "));
tft.print(pckterr);
// tft.setCursor(420, 25);
// tft.print(F("EXP: "));
// tft.print(packetNumber);
// tft.setCursor(420, 35);
// tft.print(F("SPE: "));
// tft.print(rxPacket->packet_count);
packetNumber = rxPacket->packet_count;
tft.setTextColor(WHITE, BLUE);
}
packetNumber++;
rf95.send(ackData, sizeof(ackData)); // ACK Ping
//rf95.waitPacketSent();
return;
//} For AES
}
}
void printPacket(PACKET * p) // TFT print
{
tft.setCursor(420, 5);
tft.print(F("PKT: "));
tft.print(p->packet_count);
// Serial.print(F("PCKT "));
//Serial.println(p->packet_count);
// Serial.print(F(" "));
// Serial.print(p->numBytes);
// Serial.println(F("B"));
}
void writefile(byte * data, uint16_t len) // Save Packet
{
my_file = SD.open(foldfile, FILE_WRITE);
if (my_file)
{
my_file.write(data, len);
my_file.close();
if (len <= 63) { // Will sort a definitive end packet later
my_file.write(data, len);
my_file.close();
//wdt_enable(WDTO_8S);
//my_file = SD.open(foldfile, FILE_READ);
if ( !( my_file = SD.open(foldfile, FILE_READ))) { // If something wrong
tft.setTextColor(WHITE, RED);
tft.setCursor(200, 200);
tft.print(F("JPG file not found!"));
tft.setTextColor(WHITE, BLUE);
//wdt_enable(WDTO_4S);
delay(5000);
digitalWrite(38, LOW);
return;
}
JpegDec.decodeSdFile(my_file); // Analyse data
//jpegInfo();
tft.fillScreen(BLACK);
renderJPEG(0, 0); // Convert JPG to BMP
my_file.close();
//wdt_enable(WDTO_4S);
delay(10000);
digitalWrite(38, LOW);
return;
//loop();
}
}
}
void renderJPEG(int xpos, int ypos) { // Need to understand how to reset the follwing without hard ressetting the 2560, hangs when rendering second received JPG.
// retrieve infomration about the image
uint16_t *pImg;
pImg = 0;
uint16_t mcu_w = JpegDec.MCUWidth;
uint16_t mcu_h = JpegDec.MCUHeight;
uint32_t max_x = JpegDec.width;
uint32_t max_y = JpegDec.height;
// Determine the width and height of the right and bottom edge image blocks
uint32_t min_w = minimum(mcu_w, max_x % mcu_w);
uint32_t min_h = minimum(mcu_h, max_y % mcu_h);
// save the current image block size
uint32_t win_w = mcu_w;
uint32_t win_h = mcu_h;
// save the coordinate of the right and bottom edges to assist image cropping
// to the screen size
max_x += xpos;
max_y += ypos;
char str[100];
// read each MCU block until there are no more
while ( JpegDec.read()) {
//wdt_reset();
// save a pointer to the image block
pImg = JpegDec.pImage;
// calculate where the image block should be drawn on the screen
int mcu_x = JpegDec.MCUx * mcu_w + xpos;
int mcu_y = JpegDec.MCUy * mcu_h + ypos;
// check if the image block size needs to be changed for the right and bottom edges
if (mcu_x + mcu_w <= max_x) win_w = mcu_w;
else win_w = min_w;
if (mcu_y + mcu_h <= max_y) win_h = mcu_h;
else win_h = min_h;
// calculate how many pixels must be drawn
uint32_t mcu_pixels = win_w * win_h;
// draw image block if it will fit on the screen
if ( ( mcu_x + win_w) <= tft.width() && ( mcu_y + win_h) <= tft.height()) {
for (int jj = mcu_y; jj < mcu_y + win_h; jj++)
{
for (int ii = mcu_x; ii < mcu_x + win_w ; ii++)
{
tft.drawPixel(ii, jj, *pImg++ );
}
}
}
else if ( ( mcu_y + win_h) >= tft.height()) JpegDec.abort();
}
Serial.println(F("==============="));
}
type or paste code here