From bc6d3d5c3edb7c05aeda1a1af98028e50e8f2212 Mon Sep 17 00:00:00 2001 From: beegee-tokyo Date: Wed, 5 Jun 2024 12:20:54 +0800 Subject: [PATCH] Update FRAM examples, Add simple LoRa P2P example --- ..._board_bootloader-0.4.3_s140_6.1.1.uf2.zip | Bin 0 -> 25367 bytes .../LoRa-P2P-Simple-Ard.ino | 254 ++++++++ .../RAK15006_FRAM_Read_Write_MB85RS4MT.ino | 352 +++++------ .../RAK15007_FRAM_Read_Write_CY15B108QN.ino | 564 +++++++++--------- 4 files changed, 712 insertions(+), 458 deletions(-) create mode 100644 bootloader/RAK4630/Latest/wiscore_rak4631_board_bootloader-0.4.3_s140_6.1.1.uf2.zip create mode 100644 examples/RAK4630/communications/LoRa/LoRaP2P/LoRa-P2P-Simple-Ard/LoRa-P2P-Simple-Ard.ino diff --git a/bootloader/RAK4630/Latest/wiscore_rak4631_board_bootloader-0.4.3_s140_6.1.1.uf2.zip b/bootloader/RAK4630/Latest/wiscore_rak4631_board_bootloader-0.4.3_s140_6.1.1.uf2.zip new file mode 100644 index 0000000000000000000000000000000000000000..1f63ebe7da2e5d31224ff287f21979d0edac60c7 GIT binary patch literal 25367 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 U>*;?FXpb%QvG@M3{Kb?10aYx0WB>pF literal 0 HcmV?d00001 diff --git a/examples/RAK4630/communications/LoRa/LoRaP2P/LoRa-P2P-Simple-Ard/LoRa-P2P-Simple-Ard.ino b/examples/RAK4630/communications/LoRa/LoRaP2P/LoRa-P2P-Simple-Ard/LoRa-P2P-Simple-Ard.ino new file mode 100644 index 00000000..119e63de --- /dev/null +++ b/examples/RAK4630/communications/LoRa/LoRaP2P/LoRa-P2P-Simple-Ard/LoRa-P2P-Simple-Ard.ino @@ -0,0 +1,254 @@ +/** + * @file LoRa-P2P-Simple-Ard.ino + * @author Bernd Giesecke (bernd@giesecke.tk) + * @brief Simple LoRa P2P example with CAD + * @version 0.1 + * @date 2024-06-05 + * + * @copyright Copyright (c) 2024 + * + */ +#include +#ifdef _VARIANT_RAK4630_ +#include +#endif +#include +#include + +// Function declarations +void OnTxDone(void); +void OnRxDone(uint8_t *payload, uint16_t size, int16_t rssi, int8_t snr); +void OnTxTimeout(void); +void OnRxTimeout(void); +void OnRxError(void); +void OnCadDone(bool cadResult); + +// Define LoRa parameters +#define RF_FREQUENCY 916100000 // Hz +#define TX_OUTPUT_POWER 22 // dBm +#define LORA_BANDWIDTH 0 // [0: 125 kHz, 1: 250 kHz, 2: 500 kHz, 3: Reserved] +#define LORA_SPREADING_FACTOR 7 // [SF7..SF12] +#define LORA_CODINGRATE 1 // [1: 4/5, 2: 4/6, 3: 4/7, 4: 4/8] +#define LORA_PREAMBLE_LENGTH 8 // Same for Tx and Rx +#define LORA_SYMBOL_TIMEOUT 0 // Symbols +#define LORA_FIX_LENGTH_PAYLOAD false // No fixed payload length +#define LORA_IQ_INVERSION false // No IQ inversion +#define TX_TIMEOUT_VALUE 120000 +#define RX_TIMEOUT_VALUE 30000 +#define BUFFER_SIZE 64 // Define the payload size here + +static RadioEvents_t RadioEvents; +static uint16_t BufferSize = BUFFER_SIZE; +static uint8_t RcvBuffer[BUFFER_SIZE]; +static uint8_t TxdBuffer[BUFFER_SIZE]; + +time_t cadTime; + +/** + * @brief Arduino setup function. Called once after power-up or reset + * + */ +void setup() +{ + pinMode(LED_GREEN, OUTPUT); + digitalWrite(LED_GREEN, LOW); + pinMode(LED_BLUE, OUTPUT); + digitalWrite(LED_BLUE, LOW); + + time_t serial_timeout = millis(); + // On nRF52840 the USB serial is not available immediately + while (!Serial) + { + if ((millis() - serial_timeout) < 5000) + { + delay(100); + digitalWrite(LED_GREEN, !digitalRead(LED_GREEN)); + } + else + { + break; + } + } + digitalWrite(LED_GREEN, LOW); + + Serial.println("====================================="); + Serial.println("SX126x LoRa P2P test"); + Serial.println("====================================="); + + // Initialize the LoRa chip + Serial.println("Starting lora_hardware_init"); + +#ifdef _VARIANT_RAK4630_ + lora_rak4630_init(); +#endif +#ifdef _VARIANT_RAK11200_ + lora_rak13300_init(); +#endif +#ifdef _VARIANT_RAK11300_ + lora_rak11300_init(); +#endif + + // Initialize the Radio callbacks + RadioEvents.TxDone = OnTxDone; + RadioEvents.RxDone = OnRxDone; + RadioEvents.TxTimeout = OnTxTimeout; + RadioEvents.RxTimeout = OnRxTimeout; + RadioEvents.RxError = OnRxError; + RadioEvents.CadDone = OnCadDone; + + // Initialize the Radio + Radio.Init(&RadioEvents); + + // Set Radio channel + Radio.SetChannel(RF_FREQUENCY); + + // Set Radio TX configuration + Radio.SetTxConfig(MODEM_LORA, TX_OUTPUT_POWER, 0, LORA_BANDWIDTH, + LORA_SPREADING_FACTOR, LORA_CODINGRATE, + LORA_PREAMBLE_LENGTH, LORA_FIX_LENGTH_PAYLOAD, + true, 0, 0, LORA_IQ_INVERSION, TX_TIMEOUT_VALUE); + + // Set Radio RX configuration + Radio.SetRxConfig(MODEM_LORA, LORA_BANDWIDTH, LORA_SPREADING_FACTOR, + LORA_CODINGRATE, 0, LORA_PREAMBLE_LENGTH, + LORA_SYMBOL_TIMEOUT, LORA_FIX_LENGTH_PAYLOAD, + 0, true, 0, 0, LORA_IQ_INVERSION, true); + + // Start LoRa + Serial.println("Starting Radio.Rx"); + Radio.Rx(0); +} + +/** + * @brief Arduino loop function. Sleeps until semaphore is given by timer. + * Then starts sending a packet by starting CAD (channel activity detection) + * + */ +void loop() +{ + // Sleep until we are woken up by an event + delay(5000); + + /******************************************************************************/ + /* Recommended, instead of just sending, use CAD (channel activity detection) */ + /** The packet will be sent if CAD returns no activity in the CAD callback */ + /** OnCadDone */ + /******************************************************************************/ + // Check if our channel is available for sending + Radio.Standby(); + Radio.SetCadParams(LORA_CAD_08_SYMBOL, LORA_SPREADING_FACTOR + 13, 10, LORA_CAD_ONLY, 0); + cadTime = millis(); + Radio.StartCad(); + + /***************************************************************************/ + /* Optional, just send data, can lead to collisions and loss of data */ + /***************************************************************************/ + // // Send the next PING frame + // TxdBuffer[0] = 'P'; + // TxdBuffer[1] = 'I'; + // TxdBuffer[2] = 'N'; + // TxdBuffer[3] = 'G'; + // TxdBuffer[4] = 0x00; + + // Radio.Send(TxdBuffer, 5); + + digitalWrite(LED_GREEN, HIGH); +} + +/**@brief Function to be executed on Radio Tx Done event + */ +void OnTxDone(void) +{ + Serial.println("OnTxDone"); + + // Back to RX + Radio.Rx(0); +} + +/**@brief Function to be executed on Radio Rx Done event + */ +void OnRxDone(uint8_t *payload, uint16_t size, int16_t rssi, int8_t snr) +{ + Serial.println("OnRxDone"); + + delay(10); + BufferSize = size; + memcpy(RcvBuffer, payload, BufferSize); + + Serial.printf("RssiValue=%d dBm, SnrValue=%d\n", rssi, snr); + + for (int idx = 0; idx < size; idx++) + { + Serial.printf("%02X ", RcvBuffer[idx]); + } + Serial.println(""); + + digitalWrite(LED_GREEN, LOW); + + // Back to RX + Radio.Rx(0); +} + +/**@brief Function to be executed on Radio Tx Timeout event + */ +void OnTxTimeout(void) +{ + // Radio.Sleep(); + Serial.println("OnTxTimeout"); + + digitalWrite(LED_GREEN, LOW); + + // Back to RX + Radio.Rx(0); +} + +/**@brief Function to be executed on Radio Rx Timeout event + */ +void OnRxTimeout(void) +{ + Serial.println("OnRxTimeout"); + + digitalWrite(LED_GREEN, LOW); + + // Back to RX + Radio.Rx(0); +} + +/**@brief Function to be executed on Radio Rx Error event + */ +void OnRxError(void) +{ + Serial.println("OnRxError"); + + digitalWrite(LED_GREEN, LOW); + + // Back to RX + Radio.Rx(0); +} + +/**@brief Function to be executed on CAD Done event + */ +void OnCadDone(bool cadResult) +{ + time_t duration = millis() - cadTime; + if (cadResult) + { + Serial.printf("CAD returned channel busy after %ldms\n", duration); + + // Back to RX + Radio.Rx(0); + } + else + { + Serial.printf("CAD returned channel free after %ldms\n", duration); + + // Send the next PING frame + TxdBuffer[0] = 'P'; + TxdBuffer[1] = 'I'; + TxdBuffer[2] = 'N'; + TxdBuffer[3] = 'G'; + TxdBuffer[4] = 0x00; + + Radio.Send(TxdBuffer, 5); + } +} diff --git a/examples/common/sensors/RAK15006-FRAM-4MBit-MB85RS4MT/RAK15006_FRAM_Read_Write_MB85RS4MT/RAK15006_FRAM_Read_Write_MB85RS4MT.ino b/examples/common/sensors/RAK15006-FRAM-4MBit-MB85RS4MT/RAK15006_FRAM_Read_Write_MB85RS4MT/RAK15006_FRAM_Read_Write_MB85RS4MT.ino index ba447390..bf7bc05a 100644 --- a/examples/common/sensors/RAK15006-FRAM-4MBit-MB85RS4MT/RAK15006_FRAM_Read_Write_MB85RS4MT/RAK15006_FRAM_Read_Write_MB85RS4MT.ino +++ b/examples/common/sensors/RAK15006-FRAM-4MBit-MB85RS4MT/RAK15006_FRAM_Read_Write_MB85RS4MT/RAK15006_FRAM_Read_Write_MB85RS4MT.ino @@ -1,176 +1,176 @@ -/** - @file RAK15006_FRAM_Read_Write_MB85RS4MT.ino - @author rakwireless.com - @brief FRAM_4M Read And Write Test - @version 0.1 - @date 2022-06-06 - @copyright Copyright (c) 2022 -**/ - -#include -#include "Adafruit_FRAM_SPI.h" //http://librarymanager/All#Adafruit_FRAM_SPI version:2.4.1 http://librarymanager/All#Adafruit_BusIO version:1.11.6 - -#define FRAM_WP_PIN WB_IO1 //SlotA installation, please do not use it on SLOTB -//#define FRAM_WP_PIN WB_IO3 //SlotC installation. -//#define FRAM_WP_PIN WB_IO5 //SlotD installation. - -#define FRAM_4M_SIZE 0x80000 - -/* Example code for the Adafruit SPI FRAM breakout */ -uint8_t FRAM_CS = SS; - -Adafruit_FRAM_SPI fram = Adafruit_FRAM_SPI(FRAM_CS, &SPI, 10000000); // use hardware SPI - -uint8_t FRAM_SCK = SCK; -uint8_t FRAM_MISO = MISO; -uint8_t FRAM_MOSI = MOSI; -//Or use software SPI, any pins! -//Adafruit_FRAM_SPI fram = Adafruit_FRAM_SPI(FRAM_SCK, FRAM_MISO, FRAM_MOSI, FRAM_CS); - - -/* - Writing protect block for WRITE command is configured by the value of BP0 and BP1 in the status register - data={ - 0x00 None - 0x04 60000H to 7FFFFH (upper 1/4) - 0x08 40000H to 7FFFFH (upper 1/2) - 0x0C 00000H to 7FFFFH (all) - } -*/ -void writeBlockProtect(uint8_t data) -{ - fram.writeEnable(true); - fram.setStatusRegister(data); - fram.writeEnable(false); -} - -/* - @brief Comparing whether the read and write content is consistent. - Can be used to test the probability of FRAM read and write errors. -*/ -void readWriteTest(void) -{ - char wBuf[32] = "<<>>"; - char rBuf[32] = {0}; - uint32_t successCount = 0; - uint32_t failCount = 0; - - float progress = 0; - time_t interval = millis(); - - fram.writeEnable(true); - for (uint32_t i = 0; i < FRAM_4M_SIZE; i += sizeof(wBuf) / sizeof(char)) - { - fram.write(i, (uint8_t*)wBuf , sizeof(wBuf) / sizeof(char)); - fram.read( i, (uint8_t*)rBuf , sizeof(rBuf) / sizeof(char)); - - if (memcmp(wBuf , rBuf , sizeof(rBuf)) == 0) - { - successCount++; - } - else - { - failCount++; - } - if ((millis() - interval) > 100) - { - interval = millis(); - Serial.printf("Test progress: %5.2f%% , successCount: %ld , failCount:%ld \n", progress, successCount, failCount); - } - progress = (float)(i + sizeof(wBuf) / sizeof(char)) * 100 / FRAM_4M_SIZE; - memset(rBuf , '0' , sizeof(rBuf) / sizeof(char)); - delay(1); - } - fram.writeEnable(false); - Serial.printf("Test progress: %5.2f%% , successCount: %ld , failCount:%ld \n", progress, successCount, failCount); -} - -/* - @brief Read the contents of the entire chip. -*/ -void readEntireChip(void) -{ - char readBuf[32] = {0}; - Serial.println(); - fram.writeEnable(true); - for (uint32_t i = 0; i < FRAM_4M_SIZE; i += sizeof(readBuf)) - { - fram.read( i, (uint8_t*)readBuf , sizeof(readBuf)); - Serial.print("0x"); - Serial.print(i, HEX); - Serial.print("\t"); - for (uint32_t j = 0; j < sizeof(readBuf); j++) - { - Serial.print("0x"); - Serial.print(readBuf[j], HEX); - Serial.print(' '); - } - Serial.println(); - } - fram.writeEnable(false); -} - - -void setup(void) { - pinMode(WB_IO2, OUTPUT); - digitalWrite(WB_IO2, HIGH); // Enable power supply. - delay(300); - Serial.begin(115200); - - time_t serial_timeout = millis(); - while (!Serial) - { - if ((millis() - serial_timeout) < 5000) - { - delay(100); - } - else - { - break; - } - } - Serial.println("RAK15006 FRAM_4M Read And Write Test "); - if (fram.begin()) { - Serial.println("Found SPI FRAM"); - } else { - Serial.println("No SPI FRAM found ... check your connections\r\n"); - while (1) - { - delay(500); - } - } - writeBlockProtect(0x00); -} - -void loop(void) { - - char wData[25] = "RAK15006 FRAM_4M TEST"; - char rDate[25] = {0}; - Serial.println("reading and writing test"); - fram.writeEnable(true); - fram.write(0x0000, (uint8_t*)wData , sizeof(wData) / sizeof(char)); - delay(1); - fram.read( 0x0000, (uint8_t*)rDate , sizeof(rDate) / sizeof(char)); - Serial.println(rDate); - - delay(10); - char wDataAgain[30] = "RAK15006 FRAM_4M TEST Again"; - char rDataAgain[30] = {0}; - fram.write(0x0000, (uint8_t*)wDataAgain , sizeof(wDataAgain) / sizeof(char)); - fram.read( 0x0000, (uint8_t*)rDataAgain , sizeof(rDataAgain) / sizeof(char)); - Serial.println(rDataAgain); - fram.writeEnable(false); - Serial.println(); - - Serial.println("Comparing whether the read and write content is consistent."); - readWriteTest(); - Serial.println(); - - Serial.println("Read the contents of the entire chip."); - readEntireChip(); - Serial.println("Read complete,if you want to test again,please reset the module"); - while (1) - { - delay(500); - } -} +/** + @file RAK15006_FRAM_Read_Write_MB85RS4MT.ino + @author rakwireless.com + @brief FRAM_4M Read And Write Test + @version 0.1 + @date 2022-06-06 + @copyright Copyright (c) 2022 +**/ + +#include +#include "Adafruit_FRAM_SPI.h" //http://librarymanager/All#Adafruit_FRAM_SPI version:2.4.1 http://librarymanager/All#Adafruit_BusIO version:1.11.6 + +//#define FRAM_WP_PIN WB_IO1 //SlotA installation, please do not use it on SLOTB +//#define FRAM_WP_PIN WB_IO3 //SlotC installation. +#define FRAM_WP_PIN WB_IO5 //SlotD installation. + +#define FRAM_4M_SIZE 0x80000 + +/* Example code for the Adafruit SPI FRAM breakout */ +uint8_t FRAM_CS = SS; + +Adafruit_FRAM_SPI fram = Adafruit_FRAM_SPI(FRAM_CS, &SPI, 10000000); // use hardware SPI + +uint8_t FRAM_SCK = SCK; +uint8_t FRAM_MISO = MISO; +uint8_t FRAM_MOSI = MOSI; +//Or use software SPI, any pins! +//Adafruit_FRAM_SPI fram = Adafruit_FRAM_SPI(FRAM_SCK, FRAM_MISO, FRAM_MOSI, FRAM_CS); + + +/* + Writing protect block for WRITE command is configured by the value of BP0 and BP1 in the status register + data={ + 0x00 None + 0x04 60000H to 7FFFFH (upper 1/4) + 0x08 40000H to 7FFFFH (upper 1/2) + 0x0C 00000H to 7FFFFH (all) + } +*/ +void writeBlockProtect(uint8_t data) +{ + fram.writeEnable(true); + fram.setStatusRegister(data); + fram.writeEnable(false); +} + +/* + @brief Comparing whether the read and write content is consistent. + Can be used to test the probability of FRAM read and write errors. +*/ +void readWriteTest(void) +{ + char wBuf[32] = "<<>>"; + char rBuf[32] = {0}; + uint32_t successCount = 0; + uint32_t failCount = 0; + + float progress = 0; + time_t interval = millis(); + + fram.writeEnable(true); + for (uint32_t i = 0; i < FRAM_4M_SIZE; i += sizeof(wBuf) / sizeof(char)) + { + fram.write(i, (uint8_t*)wBuf , sizeof(wBuf) / sizeof(char)); + fram.read( i, (uint8_t*)rBuf , sizeof(rBuf) / sizeof(char)); + + if (memcmp(wBuf , rBuf , sizeof(rBuf)) == 0) + { + successCount++; + } + else + { + failCount++; + } + if ((millis() - interval) > 100) + { + interval = millis(); + Serial.printf("Test progress: %5.2f%% , successCount: %ld , failCount:%ld \n", progress, successCount, failCount); + } + progress = (float)(i + sizeof(wBuf) / sizeof(char)) * 100 / FRAM_4M_SIZE; + memset(rBuf , '0' , sizeof(rBuf) / sizeof(char)); + delay(1); + } + fram.writeEnable(false); + Serial.printf("Test progress: %5.2f%% , successCount: %ld , failCount:%ld \n", progress, successCount, failCount); +} + +/* + @brief Read the contents of the entire chip. +*/ +void readEntireChip(void) +{ + char readBuf[32] = {0}; + Serial.println(); + fram.writeEnable(true); + for (uint32_t i = 0; i < FRAM_4M_SIZE; i += sizeof(readBuf)) + { + fram.read( i, (uint8_t*)readBuf , sizeof(readBuf)); + Serial.print("0x"); + Serial.print(i, HEX); + Serial.print("\t"); + for (uint32_t j = 0; j < sizeof(readBuf); j++) + { + Serial.print("0x"); + Serial.print(readBuf[j], HEX); + Serial.print(' '); + } + Serial.println(); + } + fram.writeEnable(false); +} + + +void setup(void) { + pinMode(WB_IO2, OUTPUT); + digitalWrite(WB_IO2, HIGH); // Enable power supply. + delay(300); + Serial.begin(115200); + + time_t serial_timeout = millis(); + while (!Serial) + { + if ((millis() - serial_timeout) < 5000) + { + delay(100); + } + else + { + break; + } + } + Serial.println("RAK15006 FRAM_4M Read And Write Test "); + if (fram.begin()) { + Serial.println("Found SPI FRAM"); + } else { + Serial.println("No SPI FRAM found ... check your connections\r\n"); + while (1) + { + delay(500); + } + } + writeBlockProtect(0x00); +} + +void loop(void) { + + char wData[25] = "RAK15006 FRAM_4M TEST"; + char rDate[25] = {0}; + Serial.println("reading and writing test"); + fram.writeEnable(true); + fram.write(0x0000, (uint8_t*)wData , sizeof(wData) / sizeof(char)); + delay(1); + fram.read( 0x0000, (uint8_t*)rDate , sizeof(rDate) / sizeof(char)); + Serial.println(rDate); + + delay(10); + char wDataAgain[30] = "RAK15006 FRAM_4M TEST Again"; + char rDataAgain[30] = {0}; + fram.write(0x0000, (uint8_t*)wDataAgain , sizeof(wDataAgain) / sizeof(char)); + fram.read( 0x0000, (uint8_t*)rDataAgain , sizeof(rDataAgain) / sizeof(char)); + Serial.println(rDataAgain); + fram.writeEnable(false); + Serial.println(); + + Serial.println("Comparing whether the read and write content is consistent."); + readWriteTest(); + Serial.println(); + + Serial.println("Read the contents of the entire chip."); + readEntireChip(); + Serial.println("Read complete,if you want to test again,please reset the module"); + while (1) + { + delay(500); + } +} diff --git a/examples/common/sensors/RAK15007-FRAM-8Mbit-CY15B108QN/RAK15007_FRAM_Read_Write_CY15B108QN/RAK15007_FRAM_Read_Write_CY15B108QN.ino b/examples/common/sensors/RAK15007-FRAM-8Mbit-CY15B108QN/RAK15007_FRAM_Read_Write_CY15B108QN/RAK15007_FRAM_Read_Write_CY15B108QN.ino index 41b226b8..12e230f4 100644 --- a/examples/common/sensors/RAK15007-FRAM-8Mbit-CY15B108QN/RAK15007_FRAM_Read_Write_CY15B108QN/RAK15007_FRAM_Read_Write_CY15B108QN.ino +++ b/examples/common/sensors/RAK15007-FRAM-8Mbit-CY15B108QN/RAK15007_FRAM_Read_Write_CY15B108QN/RAK15007_FRAM_Read_Write_CY15B108QN.ino @@ -1,282 +1,282 @@ -/** - @file RAK15007_FRAM_Read_Write_CY15B108QN.ino - @author rakwireless.com - @brief FRAM_8M Read And Write Test - @version 0.1 - @date 2022-06-15 - @copyright Copyright (c) 2022 -**/ -#include "RAK15007_CY15B108QN.h" //http://librarymanager/All#RAK15007_CY15B108QN - -#define FRAM_WP_PIN WB_IO1 //SlotA installation, please do not use it on SLOTB -//#define FRAM_WP_PIN WB_IO3 //SlotC installation. -//#define FRAM_WP_PIN WB_IO5 //SlotD installation. - -#define FRAM_8M_SIZE 0x100000 -uint8_t fram_cy15b108_CS = SS; -RAK_FRAM_CY15B108QN fram_cy15b108 = RAK_FRAM_CY15B108QN(fram_cy15b108_CS); - -/* - @brief Comparing whether the read and write content is consistent. - Can be used to test the probability of FRAM read and write errors. -*/ -void readWriteTest(void) -{ - char wBuf[32] = "<<>>"; - char rBuf[32] = {0}; - uint32_t successCount = 0; - uint32_t failCount = 0; - - float progress = 0; - time_t interval = millis(); - - for (uint32_t addr = 0; addr < FRAM_8M_SIZE; addr += sizeof(wBuf) / sizeof(char)) - { - fram_cy15b108.writeEnable(true); - fram_cy15b108.write(addr, (uint8_t*)wBuf , sizeof(wBuf) / sizeof(char)); - fram_cy15b108.read( addr, (uint8_t*)rBuf , sizeof(rBuf) / sizeof(char)); - fram_cy15b108.writeEnable(false); - - if (memcmp(wBuf , rBuf , sizeof(rBuf)) == 0) - { - successCount++; - } - else - { - failCount++; - } - if ((millis() - interval) > 100) - { - interval = millis(); - Serial.printf("Test progress: %5.2f%% , successCount: %ld , failCount:%ld \n", progress, successCount, failCount); - } - progress = (float)(addr + sizeof(wBuf) / sizeof(char)) * 100 / FRAM_8M_SIZE; - memset(rBuf , '0' , sizeof(rBuf) / sizeof(char)); - delay(1); - } - Serial.printf("Test progress: %5.2f%% , successCount: %ld , failCount:%ld \n", progress, successCount, failCount); -} - -/* - @brief Read the contents of the entire chip. -*/ -void readEntireChip(void) -{ - char readBuf[32] = {0}; - Serial.println(); - - for (uint32_t addr = 0; addr < FRAM_8M_SIZE; addr += sizeof(readBuf)) - { - fram_cy15b108.read( addr, (uint8_t*)readBuf , sizeof(readBuf)); - Serial.print("0x"); - Serial.print(addr, HEX); - Serial.print("\t"); - for (uint32_t bufCount = 0; bufCount < sizeof(readBuf); bufCount++) - { - Serial.print("0x"); - Serial.print(readBuf[bufCount], HEX); - Serial.print(' '); - } - Serial.println(); - } -} - - -/* - Writing protect block for WRITE command is configured by the value of BP0 and BP1 in the status register - data={ - 0x00 None - 0x04 C0000h to FFFFFh (upper 1/4) - 0x08 80000h to FFFFFh (upper 1/2) - 0x0C 00000h to FFFFFh (all) - } -*/ -void writeBlockProtect(uint8_t data) -{ - fram_cy15b108.writeEnable(true); - fram_cy15b108.setStatusRegister(data); - fram_cy15b108.writeEnable(false); -} - -/* - @brief Comparing whether the read and write special sector content is consistent. - Can be used to test the probability of FRAM read and write errors. -*/ -void specialSectorWriteAndReadTest(void) -{ - char specialSector_wBuf[32] = ""; - char specialSector_rBuf[32] = {0}; - uint32_t successCount = 0; - uint32_t failCount = 0; - - float progress = 0; - - for (uint32_t addr = 0; addr < 0xFF; addr += sizeof(specialSector_wBuf) / sizeof(char)) - { - fram_cy15b108.writeEnable(true); - fram_cy15b108.specialSectorWrite(addr, (uint8_t*)specialSector_wBuf , sizeof(specialSector_wBuf) / sizeof(char)); - fram_cy15b108.specialSectorRead( addr, (uint8_t*)specialSector_rBuf , sizeof(specialSector_rBuf) / sizeof(char)); - fram_cy15b108.writeEnable(false); - - if (memcmp(specialSector_wBuf , specialSector_rBuf , sizeof(specialSector_rBuf)) == 0) - { - successCount++; - } - else - { - failCount++; - } - Serial.printf("Special Sector Write And Read Test Progress: %5.2f%% , successCount: %ld , failCount:%ld \n", progress, successCount, failCount); - progress = (float)(addr + sizeof(specialSector_wBuf) / sizeof(char)) * 100 / 0xff; - memset(specialSector_rBuf , '0' , sizeof(specialSector_rBuf) / sizeof(char)); - delay(100); - } -} - -/** - The CY15X108QN supports a FAST READ opcode (0Bh) that is provided for opcode compatibility with serial flash devices -*/ -void fastReadOperationTest(void) -{ - char readBuf[32] = {0}; - Serial.println(); - - for (uint32_t addr = 0; addr < FRAM_8M_SIZE; addr += sizeof(readBuf)) - { - fram_cy15b108.fastReadOperation( addr, (uint8_t*)readBuf , sizeof(readBuf)); - Serial.print("0x"); - Serial.print(addr, HEX); - Serial.print("\t"); - for (uint32_t bufCount = 0; bufCount < sizeof(readBuf); bufCount++) - { - Serial.print("0x"); - Serial.print(readBuf[bufCount], HEX); - Serial.print(' '); - } - Serial.println(); - } -} - - -void setup(void) { - pinMode(WB_IO2, OUTPUT); - digitalWrite(WB_IO2, HIGH); // Enable power supply. - delay(300); - pinMode(FRAM_WP_PIN, OUTPUT); - digitalWrite(FRAM_WP_PIN, HIGH); - Serial.begin(115200); - - time_t serial_timeout = millis(); - while (!Serial) - { - if ((millis() - serial_timeout) < 5000) - { - delay(100); - } - else - { - break; - } - } - Serial.println("RAK15007 FRAM_CY15B108QN TEST"); - if (fram_cy15b108.begin()) { - Serial.println("Found FRAM_CY15B108QN"); - } else { - Serial.println("FRAM_CY15B108QN is not connected, Please check your connections\r\n"); - while (1) - { - delay(500); - } - } - writeBlockProtect(0x00); - delay(1000); - - uint32_t fram_size = fram_cy15b108.getFramSize(); - if (fram_size != 0) - { - Serial.print("FRAM_CY15B108QN address size is "); - Serial.print(fram_size); - Serial.println(" bytes"); - Serial.println("The capacity of the FRAM is"); - Serial.print(fram_size); Serial.println(" bytes"); - Serial.print(fram_size / 1024); Serial.println(" kilobytes"); - Serial.print((fram_size * 8) / 1024); Serial.println(" kilobits"); - if (fram_size >= ((1024 * 1024) / 8)) { - Serial.print((fram_size * 8) / (1024 * 1024)); - Serial.println(" megabits"); - } - } - else - { - Serial.println("Unable to identify the device,Please check your connections"); - while (1) - { - delay(100); - } - } - Serial.println(); - fram_cy15b108.writeEnable(true); - fram_cy15b108.writeByte(0x00, 0x01); - uint8_t wByte = fram_cy15b108.readByte(0x00); - if (wByte == 0x01) - { - Serial.println("write byte successful "); - } - fram_cy15b108.writeEnable(false); -} - - -void loop(void) { - - uint8_t serialNumberBuf[8] = {0x00}; - fram_cy15b108.getSerialNumber(serialNumberBuf, sizeof(serialNumberBuf) / sizeof(uint8_t)); - Serial.print("serialNumberBuf=0x"); - for (uint8_t serialCount = 0; serialCount < 8; serialCount++) - { - Serial.printf("%02x", serialNumberBuf[serialCount]); // The factory default value for the 8-byte Serial Number is ‘0000000000000000h’. - } - Serial.println(); - delay(1000); - - char wData[25] = "RAK15007 FRAM_8M TEST"; - char rDate[25] = {0}; - Serial.println("reading and writing test"); - fram_cy15b108.writeEnable(true); - fram_cy15b108.write(0x0000, (uint8_t*)wData , sizeof(wData) / sizeof(char)); - delay(1); - fram_cy15b108.read( 0x0000, (uint8_t*)rDate , sizeof(rDate) / sizeof(char)); - Serial.println(rDate); - fram_cy15b108.writeEnable(false); - delay(1); - - char wDataAgain[30] = "RAK15007 FRAM_8M TEST Again"; - char rDataAgain[30] = {0}; - fram_cy15b108.writeEnable(true); - fram_cy15b108.write(0x0000, (uint8_t*)wDataAgain , sizeof(wDataAgain) / sizeof(char)); - fram_cy15b108.read( 0x0000, (uint8_t*)rDataAgain , sizeof(rDataAgain) / sizeof(char)); - Serial.println(rDataAgain); - fram_cy15b108.writeEnable(false); - Serial.println(); - - Serial.println("Comparing whether the read and write special sector content is consistent."); - specialSectorWriteAndReadTest(); - Serial.println(); - - Serial.println("Comparing whether the read and write content is consistent."); - readWriteTest(); - Serial.println(); - - delay(2000); - Serial.println("FAST Read the contents of the entire chip."); - fastReadOperationTest(); - Serial.println(); - - delay(2000); - Serial.println("Read the contents of the entire chip."); - readEntireChip(); - Serial.println("Read complete,if you want to test again,please reset the module"); - while (1) - { - delay(500); - } -} +/** + @file RAK15007_FRAM_Read_Write_CY15B108QN.ino + @author rakwireless.com + @brief FRAM_8M Read And Write Test + @version 0.1 + @date 2022-06-15 + @copyright Copyright (c) 2022 +**/ +#include "RAK15007_CY15B108QN.h" //http://librarymanager/All#RAK15007_CY15B108QN + +//#define FRAM_WP_PIN WB_IO1 //SlotA installation, please do not use it on SLOTB +//#define FRAM_WP_PIN WB_IO3 //SlotC installation. +#define FRAM_WP_PIN WB_IO5 //SlotD installation. + +#define FRAM_8M_SIZE 0x100000 +uint8_t fram_cy15b108_CS = SS; +RAK_FRAM_CY15B108QN fram_cy15b108 = RAK_FRAM_CY15B108QN(fram_cy15b108_CS); + +/* + @brief Comparing whether the read and write content is consistent. + Can be used to test the probability of FRAM read and write errors. +*/ +void readWriteTest(void) +{ + char wBuf[32] = "<<>>"; + char rBuf[32] = {0}; + uint32_t successCount = 0; + uint32_t failCount = 0; + + float progress = 0; + time_t interval = millis(); + + for (uint32_t addr = 0; addr < FRAM_8M_SIZE; addr += sizeof(wBuf) / sizeof(char)) + { + fram_cy15b108.writeEnable(true); + fram_cy15b108.write(addr, (uint8_t*)wBuf , sizeof(wBuf) / sizeof(char)); + fram_cy15b108.read( addr, (uint8_t*)rBuf , sizeof(rBuf) / sizeof(char)); + fram_cy15b108.writeEnable(false); + + if (memcmp(wBuf , rBuf , sizeof(rBuf)) == 0) + { + successCount++; + } + else + { + failCount++; + } + if ((millis() - interval) > 100) + { + interval = millis(); + Serial.printf("Test progress: %5.2f%% , successCount: %ld , failCount:%ld \n", progress, successCount, failCount); + } + progress = (float)(addr + sizeof(wBuf) / sizeof(char)) * 100 / FRAM_8M_SIZE; + memset(rBuf , '0' , sizeof(rBuf) / sizeof(char)); + delay(1); + } + Serial.printf("Test progress: %5.2f%% , successCount: %ld , failCount:%ld \n", progress, successCount, failCount); +} + +/* + @brief Read the contents of the entire chip. +*/ +void readEntireChip(void) +{ + char readBuf[32] = {0}; + Serial.println(); + + for (uint32_t addr = 0; addr < FRAM_8M_SIZE; addr += sizeof(readBuf)) + { + fram_cy15b108.read( addr, (uint8_t*)readBuf , sizeof(readBuf)); + Serial.print("0x"); + Serial.print(addr, HEX); + Serial.print("\t"); + for (uint32_t bufCount = 0; bufCount < sizeof(readBuf); bufCount++) + { + Serial.print("0x"); + Serial.print(readBuf[bufCount], HEX); + Serial.print(' '); + } + Serial.println(); + } +} + + +/* + Writing protect block for WRITE command is configured by the value of BP0 and BP1 in the status register + data={ + 0x00 None + 0x04 C0000h to FFFFFh (upper 1/4) + 0x08 80000h to FFFFFh (upper 1/2) + 0x0C 00000h to FFFFFh (all) + } +*/ +void writeBlockProtect(uint8_t data) +{ + fram_cy15b108.writeEnable(true); + fram_cy15b108.setStatusRegister(data); + fram_cy15b108.writeEnable(false); +} + +/* + @brief Comparing whether the read and write special sector content is consistent. + Can be used to test the probability of FRAM read and write errors. +*/ +void specialSectorWriteAndReadTest(void) +{ + char specialSector_wBuf[32] = ""; + char specialSector_rBuf[32] = {0}; + uint32_t successCount = 0; + uint32_t failCount = 0; + + float progress = 0; + + for (uint32_t addr = 0; addr < 0xFF; addr += sizeof(specialSector_wBuf) / sizeof(char)) + { + fram_cy15b108.writeEnable(true); + fram_cy15b108.specialSectorWrite(addr, (uint8_t*)specialSector_wBuf , sizeof(specialSector_wBuf) / sizeof(char)); + fram_cy15b108.specialSectorRead( addr, (uint8_t*)specialSector_rBuf , sizeof(specialSector_rBuf) / sizeof(char)); + fram_cy15b108.writeEnable(false); + + if (memcmp(specialSector_wBuf , specialSector_rBuf , sizeof(specialSector_rBuf)) == 0) + { + successCount++; + } + else + { + failCount++; + } + Serial.printf("Special Sector Write And Read Test Progress: %5.2f%% , successCount: %ld , failCount:%ld \n", progress, successCount, failCount); + progress = (float)(addr + sizeof(specialSector_wBuf) / sizeof(char)) * 100 / 0xff; + memset(specialSector_rBuf , '0' , sizeof(specialSector_rBuf) / sizeof(char)); + delay(100); + } +} + +/** + The CY15X108QN supports a FAST READ opcode (0Bh) that is provided for opcode compatibility with serial flash devices +*/ +void fastReadOperationTest(void) +{ + char readBuf[32] = {0}; + Serial.println(); + + for (uint32_t addr = 0; addr < FRAM_8M_SIZE; addr += sizeof(readBuf)) + { + fram_cy15b108.fastReadOperation( addr, (uint8_t*)readBuf , sizeof(readBuf)); + Serial.print("0x"); + Serial.print(addr, HEX); + Serial.print("\t"); + for (uint32_t bufCount = 0; bufCount < sizeof(readBuf); bufCount++) + { + Serial.print("0x"); + Serial.print(readBuf[bufCount], HEX); + Serial.print(' '); + } + Serial.println(); + } +} + + +void setup(void) { + pinMode(WB_IO2, OUTPUT); + digitalWrite(WB_IO2, HIGH); // Enable power supply. + delay(300); + pinMode(FRAM_WP_PIN, OUTPUT); + digitalWrite(FRAM_WP_PIN, HIGH); + Serial.begin(115200); + + time_t serial_timeout = millis(); + while (!Serial) + { + if ((millis() - serial_timeout) < 5000) + { + delay(100); + } + else + { + break; + } + } + Serial.println("RAK15007 FRAM_CY15B108QN TEST"); + if (fram_cy15b108.begin()) { + Serial.println("Found FRAM_CY15B108QN"); + } else { + Serial.println("FRAM_CY15B108QN is not connected, Please check your connections\r\n"); + while (1) + { + delay(500); + } + } + writeBlockProtect(0x00); + delay(1000); + + uint32_t fram_size = fram_cy15b108.getFramSize(); + if (fram_size != 0) + { + Serial.print("FRAM_CY15B108QN address size is "); + Serial.print(fram_size); + Serial.println(" bytes"); + Serial.println("The capacity of the FRAM is"); + Serial.print(fram_size); Serial.println(" bytes"); + Serial.print(fram_size / 1024); Serial.println(" kilobytes"); + Serial.print((fram_size * 8) / 1024); Serial.println(" kilobits"); + if (fram_size >= ((1024 * 1024) / 8)) { + Serial.print((fram_size * 8) / (1024 * 1024)); + Serial.println(" megabits"); + } + } + else + { + Serial.println("Unable to identify the device,Please check your connections"); + while (1) + { + delay(100); + } + } + Serial.println(); + fram_cy15b108.writeEnable(true); + fram_cy15b108.writeByte(0x00, 0x01); + uint8_t wByte = fram_cy15b108.readByte(0x00); + if (wByte == 0x01) + { + Serial.println("write byte successful "); + } + fram_cy15b108.writeEnable(false); +} + + +void loop(void) { + + uint8_t serialNumberBuf[8] = {0x00}; + fram_cy15b108.getSerialNumber(serialNumberBuf, sizeof(serialNumberBuf) / sizeof(uint8_t)); + Serial.print("serialNumberBuf=0x"); + for (uint8_t serialCount = 0; serialCount < 8; serialCount++) + { + Serial.printf("%02x", serialNumberBuf[serialCount]); // The factory default value for the 8-byte Serial Number is ‘0000000000000000h’. + } + Serial.println(); + delay(1000); + + char wData[25] = "RAK15007 FRAM_8M TEST"; + char rDate[25] = {0}; + Serial.println("reading and writing test"); + fram_cy15b108.writeEnable(true); + fram_cy15b108.write(0x0000, (uint8_t*)wData , sizeof(wData) / sizeof(char)); + delay(1); + fram_cy15b108.read( 0x0000, (uint8_t*)rDate , sizeof(rDate) / sizeof(char)); + Serial.println(rDate); + fram_cy15b108.writeEnable(false); + delay(1); + + char wDataAgain[30] = "RAK15007 FRAM_8M TEST Again"; + char rDataAgain[30] = {0}; + fram_cy15b108.writeEnable(true); + fram_cy15b108.write(0x0000, (uint8_t*)wDataAgain , sizeof(wDataAgain) / sizeof(char)); + fram_cy15b108.read( 0x0000, (uint8_t*)rDataAgain , sizeof(rDataAgain) / sizeof(char)); + Serial.println(rDataAgain); + fram_cy15b108.writeEnable(false); + Serial.println(); + + Serial.println("Comparing whether the read and write special sector content is consistent."); + specialSectorWriteAndReadTest(); + Serial.println(); + + Serial.println("Comparing whether the read and write content is consistent."); + readWriteTest(); + Serial.println(); + + delay(2000); + Serial.println("FAST Read the contents of the entire chip."); + fastReadOperationTest(); + Serial.println(); + + delay(2000); + Serial.println("Read the contents of the entire chip."); + readEntireChip(); + Serial.println("Read complete,if you want to test again,please reset the module"); + while (1) + { + delay(500); + } +}