Hello Renesas Community,
I am having an issue with my AT25SL641 flash memory chip in that it works completely except for the Page Program command (0x02). I am using a Maxim Integrated MAX32660 MCU and trying to write and read data from the AT25SL641 chip. I follow these steps:
When I read my RX data from the Read Command, it is filled with all 0xFF bytes, as if the memory has not been written. I have used an oscilloscope to confirm that the timings and signals are correct. I can see all three commands, can see that chip select is pulled low and return to high, and can individually see where each bit is to know all of them have been sent by the MCU.
Solutions tried:
I have included my main.c file and an image of what my tx data and rx data look like. If anyone has any suggestions please let me know. Nothing has been able to fix this!
/******************************* * @file main.c * @brief Peripheral code *******************************/ /***** MAXIM SDK Includes *****/ #include <stdio.h> #include <stdint.h> #include <stdbool.h> #include <math.h> #include <stdlib.h> #include "mxc_device.h" #include "mxc_delay.h" #include "mxc_sys.h" #include "mxc_errors.h" #include "mxc_pins.h" #include "led.h" #include "board.h" #include "gpio.h" #include "nvic_table.h" #include "i2c_regs.h" #include "i2c.h" #include "tmr.h" #include "flc.h" #include "flc_regs.h" #include "gcr_regs.h" #include "icc.h" #include "spi.h" #include "spimss.h" /***** Custom Includes *****/ #include "Wire.h" #include "millis.h" #include "MXC4005XC_I2C.h" /***** Definitions *****/ #define I2C_MASTER MXC_I2C1 #define I2C_FREQ 100000 #define I2C_FILLER 0xAA #define SPI_MASTER MXC_SPI0 #define SPI_FREQ 100000 #define SPI_IRQ SPI0_IRQn #define DATA_LEN 32 // eLED being the external transmitting LED #define MXC_GPIO_PORT_OUT MXC_GPIO0 #define eLED_PIN MXC_GPIO_PIN_4 mxc_gpio_cfg_t eLED; // iLED being the LED on the MCU maki roll #define iLED_PIN MXC_GPIO_PIN_5 mxc_gpio_cfg_t iLED; // typedef enum{ // FAILED, // PASSED // }test_t; /***** Globals *****/ uint8_t config[DATA_LEN]; // Placeholder for BLE messaging uint8_t rxdata[DATA_LEN]; // To get response from BLE uint8_t txdata[DATA_LEN]; // To send to SPI uint8_t readout[DATA_LEN]; volatile uint32_t isr_cnt; volatile uint32_t isr_flags; int error; bool startMsgRx = false; // To break loops in app() uint32_t StartTime; int ADDRESS; bool accel_flag, BLE_flag, arduino_flag; /***** Function Declarations *****/ void delay(int milliseconds); void writeLEDLow(); void writeLEDHigh(); void writeI_LEDLow(); void writeI_LEDHigh(); static void sendBLEMessage(uint8_t *message, uint8_t sizeOfMessage); // Primary Functions void setup(void); void Setup_SPI(void); // Helper Functions void Send_SPI_Command(uint8_t hex_com); void Write_Enable(void); void Write_Page(void); void Read_Page(void); void Chip_Erase(void); void Setup_IRQs(void); short Float32toFloat16(float input); void Download_Data(uint32_t address); void Send_To_Arduino(void); void Setup_LEDs(void); enum BLE_COMMAND { GET_DATA_FROM_NODE_NUM = 0x29, UPDATE_TEMP_CHAR_DATA = 0x40, UPDATE_LIGHT_CHAR_DATA = 0x41, UPDATE_ACCEL_CHAR_DATA = 0x42, UPDATE_PPG_CHAR_DATA = 0x43, ON_OFF_LED_STATE = 0x14, SYNCH_START_MSG = 0xBB, RESTART_LOOP = 0xDD, DOWNLOAD_MSG = 0xCC, }; /**************************************************/ /*** Defining Hex Address for Fiber Peripherals ***/ #define ACCEL_SENSOR 0x15 #define BLE_SENSOR 0x30 #define LIGHT_SENSOR 0x39 // TSL2584TSV #define MCU_READOUT_SENSOR 0x50 #define ARDUINO 0x55 // Slave address of Arduino /*************************** Main ***************************/ int main(void) { setup(); // Setup peripherals and I2C Setup_SPI(); // Setup SPI peripheral NVIC_EnableIRQ(SPI_IRQ); Write_Enable(); Write_Page(); Read_Page(); while (true) { printf("main completed, looping forever...\n"); delay(10000); } } /*************************** Setup ***************************/ void setup(void) { printf("\n\n\n************************* SPI TEST *************************\n"); printf("\nStarting setup...\n"); int error; // Initializing timer and interrupts MXC_NVIC_SetVector(TMR2_IRQn, ContinuousTimerHandler); NVIC_EnableIRQ(TMR2_IRQn); ContinuousTimer(); delay(1000); // Setup LEDs and set to High on start. Setup_LEDs(); writeI_LEDHigh(); writeLEDHigh(); delay(1000); /**********************************************************************/ /***** Check I2C Connections *****/ // error = Wire_begin(); // if (error != E_NO_ERROR) // while (1) // { // printf("Failed to initiate I2C controller port.\n"); // writeI_LEDLow(); // delay(1000); // NVIC_SystemReset(); // Reset MCU // } // printf("I2C initiated.\n"); /***** Check SPI Connections *****/ error = SPI_Begin(); if (error != E_NO_ERROR) while (1) { printf("Failed to initiate SPI: %d\n", error); writeI_LEDLow(); delay(1000); NVIC_SystemReset(); // Reset MCU } printf("SPI initiated.\n"); /**********************************************************************/ } void Setup_SPI(void) { // Configure the peripheral error = MXC_SPI_Init(SPI_MASTER, 1, 0, 1, 0, SPI_FREQ); if (error != E_NO_ERROR) { printf("\nSPI Master Init Error: %d\n", error); return; } error = MXC_SPI_SetDataSize(SPI_MASTER, 8); // number of bits if (error != E_NO_ERROR) { printf("\nSPI SET DATASIZE ERROR: %d\n", error); return; } error = MXC_SPI_SetWidth(SPI_MASTER, SPI_WIDTH_STANDARD); if (error != E_NO_ERROR) { printf("\nSPI SET WIDTH ERROR: %d\n", error); return; } NVIC_EnableIRQ(SPI_IRQ); printf("SPI Setup complete.\n\n"); } void Send_SPI_Command(uint8_t hex_com) { memset(&rxdata, 0x0, DATA_LEN * sizeof(uint8_t)); // Rx Start Byte memset(&txdata, 0x0, DATA_LEN * sizeof(uint8_t)); txdata[0] = hex_com; mxc_spi_req_t req; req.spi = SPI_MASTER; req.txData = (uint8_t *)txdata; req.rxData = (uint8_t *)rxdata; req.txLen = DATA_LEN; req.rxLen = DATA_LEN; req.ssIdx = 0; req.ssDeassert = 1; req.txCnt = 0; req.rxCnt = 0; req.completeCB = (spi_complete_cb_t)SPI_Callback; error = MXC_SPI_MasterTransaction(&req); if (error != E_NO_ERROR) printf("Error: %d\n", error); printf("SPI Command 0x%X, rxdata:\n", hex_com); for (int i = 0; i < DATA_LEN; i++) { printf("%X ", rxdata[i]); } printf("\n\n"); delay(100); } void Write_Page(void) { memset(&rxdata, 0x0, DATA_LEN * sizeof(uint8_t)); memset(&txdata, 0x0, DATA_LEN * sizeof(uint8_t)); txdata[0] = 0x02; // Write command txdata[1] = 0xAB; // address bytes txdata[2] = 0xCD; txdata[3] = 0x0F; txdata[4] = 0x11; // bytes to be written txdata[5] = 0x22; txdata[6] = 0x33; txdata[7] = 0x44; txdata[8] = 0x55; txdata[9] = 0x66; txdata[10] = 0x77; txdata[11] = 0x88; txdata[12] = 0x99; txdata[13] = 0xAA; txdata[14] = 0xBB; txdata[15] = 0xCC; txdata[16] = 0xDD; txdata[17] = 0xEE; txdata[18] = 0xFF; printf("write page txdata:\n"); for (int i = 0; i < DATA_LEN; i++) { printf("%X ", txdata[i]); } printf("\n"); mxc_spi_req_t req; req.spi = SPI_MASTER; req.txData = (uint8_t *)txdata; req.rxData = (uint8_t *)rxdata; req.txLen = DATA_LEN; req.rxLen = DATA_LEN; req.ssIdx = 0; req.ssDeassert = 1; req.txCnt = 0; req.rxCnt = 0; req.completeCB = (spi_complete_cb_t)SPI_Callback; error = MXC_SPI_MasterTransaction(&req); if (error != E_NO_ERROR) printf("Error: %d\n", error); printf("write page rxdata:\n"); for (int i = 0; i < DATA_LEN; i++) { printf("%X ", rxdata[i]); } printf("\n\n"); } void Write_Enable(void) { memset(&rxdata, 0x0, DATA_LEN * sizeof(uint8_t)); // Rx Start Byte memset(&txdata, 0x0, DATA_LEN * sizeof(uint8_t)); txdata[0] = 0x06; // Write Enable command for PmodSF3 mxc_spi_req_t req; req.spi = SPI_MASTER; req.txData = (uint8_t *)txdata; req.rxData = (uint8_t *)rxdata; req.txLen = DATA_LEN; req.rxLen = DATA_LEN; req.ssIdx = 0; req.ssDeassert = 1; req.txCnt = 0; req.rxCnt = 0; req.completeCB = (spi_complete_cb_t)SPI_Callback; error = MXC_SPI_MasterTransaction(&req); if (error != E_NO_ERROR) printf("Write Enable Error: %d\n", error); printf("Write Enable command sent.\n\n"); } void Read_Page(void) { memset(&rxdata, 0x0, DATA_LEN * sizeof(uint8_t)); memset(&txdata, 0x0, DATA_LEN * sizeof(uint8_t)); txdata[0] = 0x03; txdata[1] = 0xAB; // address txdata[2] = 0xCD; txdata[3] = 0x0F; // txdata[0] = 0x9F; // Read Manufactor ID, 0x1F printf("read page txdata:\n"); for (int i = 0; i < DATA_LEN; i++) { printf("%X ", txdata[i]); } printf("\n"); mxc_spi_req_t req; req.spi = SPI_MASTER; req.txData = (uint8_t *)txdata; req.rxData = (uint8_t *)rxdata; req.txLen = DATA_LEN; req.rxLen = DATA_LEN; req.ssIdx = 0; req.ssDeassert = 1; req.txCnt = 0; req.rxCnt = 0; req.completeCB = (spi_complete_cb_t)SPI_Callback; error = MXC_SPI_MasterTransaction(&req); if (error != E_NO_ERROR) printf("Error: %d\n", error); printf("rxdata:\n"); for (int i = 0; i < DATA_LEN; i++) { printf("%X ", rxdata[i]); } printf("\n\n"); } void Chip_Erase(void) { memset(&rxdata, 0x0, DATA_LEN * sizeof(uint8_t)); // Rx Start Byte memset(&txdata, 0x0, DATA_LEN * sizeof(uint8_t)); txdata[0] = 0x60; // Erase chip command for Renesas chip mxc_spi_req_t req; req.spi = SPI_MASTER; req.txData = (uint8_t *)txdata; req.rxData = (uint8_t *)rxdata; req.txLen = DATA_LEN; req.rxLen = DATA_LEN; req.ssIdx = 0; req.ssDeassert = 1; req.txCnt = 0; req.rxCnt = 0; req.completeCB = (spi_complete_cb_t)SPI_Callback; error = MXC_SPI_MasterTransaction(&req); } void Send_To_Arduino(void) { delay(1000); // Wait two seconds as a buffer uint32_t address = 0x12000; uint8_t buffer; while (address < 0x40000) { MXC_FLC_Read(address, &buffer, 1); Wire_beginTransmission(ARDUINO); Wire_write(&buffer, 1); Wire_endTransmission(); address += 1; delay(1); } } unsigned short x1_, y1_, z1_, x2_, y2_, z2_; uint32_t xbits, ybits, zbits; // int Write_Data(uint32_t address) // { // int err = 0; // // Get two readings with delay based on sampling rate // x1_ = Float32toFloat16( (float)MXC4005XC_readX_Axis() ); // y1_ = Float32toFloat16( (float)MXC4005XC_readY_Axis() ); // z1_ = Float32toFloat16( (float)MXC4005XC_readZ_Axis() ); // delay(20); // x2_ = Float32toFloat16( (float)MXC4005XC_readX_Axis() ); // y2_ = Float32toFloat16( (float)MXC4005XC_readY_Axis() ); // z2_ = Float32toFloat16( (float)MXC4005XC_readZ_Axis() ); // // Copy two 16 bit values to one 32 bit value // xbits = (x1_ << 16) | (x2_ & 0xFFFF); // ybits = (y1_ << 16) | (y2_ & 0xFFFF); // zbits = (z1_ << 16) | (z2_ & 0xFFFF); // err = MXC_FLC_Write32(address, xbits); // X Axis Write // if (err!=0) { return err; } // address += 4; // err = MXC_FLC_Write32(address, ybits); // Y Axis Write // if (err!=0) { return err; } // address += 4; // err = MXC_FLC_Write32(address, zbits); // Z Axis Write // if (err!=0) { return err; } // return err; // } void Download_Data(uint32_t address) { while (address < 0x40000) { memset(&config, I2C_FILLER, sizeof(config)); config[0] = UPDATE_ACCEL_CHAR_DATA; uint8_t buffer; for (int j = 1; j < 31; j++) // Iterate over buffer size { MXC_FLC_Read(address, &buffer, 1); config[j] = buffer; address += 1; } sendBLEMessage(&config[0], sizeof(config)); // Requires a delay of 100 for some reason or else DA14531 doesn't pick up the data properly delay(150); } } /********************************************************************** * Converts a float (32 bits) into memory space of short type (int16) **********************************************************************/ short Float32toFloat16(float input) { // Copy Float bits into Int32 uint32_t input_bits; memcpy(&input_bits, &input, sizeof(input)); // StackOverflow Magic to convert Float32 to Float16 using fast operations unsigned short fltInt16; fltInt16 = (input_bits >> 31) << 5; unsigned short tmp = (input_bits >> 23) & 0xff; tmp = (tmp - 0x70) & ((unsigned int)((int)(0x70 - tmp) >> 4) >> 27); fltInt16 = (fltInt16 | tmp) << 10; fltInt16 |= (input_bits >> 13) & 0x3ff; return fltInt16; } /******************************************************************************* * Message pointer to an array * Will continue to re-send messages with 100ms delay until BLE ACK's properly *******************************************************************************/ static void sendBLEMessage(uint8_t *message, uint8_t sizeOfMessage) { Wire_beginTransmission(BLE_SENSOR); Wire_write(message, sizeOfMessage); int error = Wire_endTransmission(); if (error != 0) while(1) { Wire_beginTransmission(BLE_SENSOR); Wire_write(message, sizeOfMessage); error = Wire_endTransmission(); delay(50); } } void FLC0_IRQHandler(void) { uint32_t temp; isr_cnt++; temp = MXC_FLC0->intr; if (temp & MXC_F_FLC_INTR_DONE) { MXC_FLC0->intr &= ~MXC_F_FLC_INTR_DONE; } if (temp & MXC_F_FLC_INTR_ACCESS_FAIL) { MXC_FLC0->intr &= ~MXC_F_FLC_INTR_ACCESS_FAIL; } isr_flags = temp; } void Setup_IRQs(void) { /********************************************************************** * All functions modifying flash contents are set to execute out of RAM * with the (section(".flashprog")) attribute. Therefore, * * If: * - An FLC function is in the middle of execution (from RAM) * ... and... * - An interrupt triggers an ISR which executes from Flash * * ... Then a hard fault will be triggered. * * FLC functions should be: * 1) Executed from a critical code block (interrupts disabled) * or * 2) ISRs should be set to execute out of RAM with NVIC_SetRAM() * * This example demonstrates method #1. Any code modifying * flash is executed from a critical block, and the FLC * interrupts will trigger afterwards. **********************************************************************/ // NVIC_SetRAM(); // Execute ISRs out of SRAM (for use with #2 above) MXC_NVIC_SetVector(FLC_IRQn, FLC0_IRQHandler); // Assign ISR NVIC_EnableIRQ(FLC_IRQn); // Enable interrupt __enable_irq(); // Clear and enable flash programming interrupts MXC_FLC_EnableInt(MXC_F_FLC_INTR_DONE_IE | MXC_F_FLC_INTR_ACCESS_FAIL_IE); isr_flags = 0; isr_cnt = 0; } /*********************** LED and Timer Helper Functions ***********************/ void delay(int milliseconds) { MXC_Delay(milliseconds * 1000); return; } void writeLEDLow() { MXC_GPIO_OutClr(eLED.port, eLED.mask); } void writeLEDHigh() { MXC_GPIO_OutSet(eLED.port, eLED.mask); } void writeI_LEDLow() { MXC_GPIO_OutClr(iLED.port, iLED.mask); } void writeI_LEDHigh() { MXC_GPIO_OutSet(iLED.port, iLED.mask); } void Setup_LEDs() { /**********************************/ /* Setup external LED output pin. */ eLED.port = MXC_GPIO_PORT_OUT; eLED.mask = eLED_PIN; eLED.pad = MXC_GPIO_PAD_NONE; eLED.func = MXC_GPIO_FUNC_OUT; MXC_GPIO_Config(&eLED); writeLEDLow(); /* Setup internal LED output pin. */ iLED.port = MXC_GPIO_PORT_OUT; iLED.mask = iLED_PIN; iLED.pad = MXC_GPIO_PAD_NONE; iLED.func = MXC_GPIO_FUNC_OUT; MXC_GPIO_Config(&iLED); writeI_LEDLow(); /**********************************/ }