I have an ultra low power application that runs on three different boards, 2 use TM4C123GH6PGEI 144 pin and the latest uses TM4C123GH6PMIR 64pin. I2C0 is on the same pin mux pins.
The application requires external low power memory to store volatile state variables and things like 'sample num'. Onchip EEPROM is not an option as we are well over the rated 500K write cycles with deployments that last over a year. I have tried the HIB module RAM, however, we wish to store more than the HIB RAM can hold hence our use of FRAM.
The first two boards use Cypress FRAM FM24CL04B which has a single byte register address and the latest board uses a much larger Fujitsu MB85RC1MTPNF FRAM as we plan to cache sample data and then write to external NAND flash or microSD in a burst block fashion.
The i2c driver for for the smaller 4KB FRAM works fine. My question is how to write two bytes of address for the bigger 128KB Fujitsu FRAM. The image shows the i2c byte sequence.
My i2c driver for Cypress has one call to ROM_i2cmasterdataput... What i'd like to do is something like the following:
// Place the address to be written in the data register.
#if FUJITSU_BIGFRAM == 1
ROM_I2CMasterDataPut(I2C0_BASE, (uint8_t)(ucStart_addr/256));
#endif
ROM_I2CMasterDataPut(I2C0_BASE, (uint8_t)ucStart_addr);
This is incorrect (as it does not work), but I'm not seeing a 16 bit (2 byte) API. Please advise on how to do the two byte address. I've seen other posts in the e2e forum but not an answer.
Thanks
void fram_test(void) { int indx; uprintf("\r\n1st block of 128, write 127 to 0\r\n"); for(indx=0; indx<128; indx++) // 0->127 framBuf[indx] = 127-indx; i2c0_write(I2C_FRAM_ADDR, framBuf, 128, 0x00); for(indx=0; indx<128; indx++) { uprintf("%02x ", framBuf[indx]); if(indx%16 == 0x0f) uprintf("\r\n"); } uprintf("\r\n2nd block of 128, write 0 to 127\r\n"); for(indx=0; indx<128; indx++) framBuf[indx] = indx; i2c0_write(I2C_FRAM_ADDR, framBuf, 128, 128); for(indx=0; indx<128; indx++) { uprintf("%02x ", framBuf[indx]); if(indx%16 == 0x0f) uprintf("\r\n"); } wait_consoleTx(); uprintf("\r\n3rd block of 128, write 255 to 128\r\n"); for(indx=0; indx<128; indx++) framBuf[indx] = 255-indx; i2c0_write(I2C_FRAM_ADDR, framBuf, 128, 256); for(indx=0; indx<128; indx++) { uprintf("%02x ", framBuf[indx]); if(indx%16 == 0x0f) uprintf("\r\n"); } uprintf("\r\n4th block of 128, write 128 to 255\r\n"); for(indx=0; indx<128; indx++) framBuf[indx] = 128+indx; i2c0_write(I2C_FRAM_ADDR, framBuf, 128, 384); for(indx=0; indx<128; indx++) { uprintf("%02x ", framBuf[indx]); if(indx%16 == 0x0f) uprintf("\r\n"); } wait_consoleTx(); for(indx=0; indx<128; indx++) framBuf[indx] = 0x55; uprintf("\r\n1st block of 128, read:\r\n"); i2c0_read(I2C_FRAM_ADDR, framBuf, 128, 0, FALSE); for(indx=0; indx<128; indx++) { uprintf("%02x ", framBuf[indx]); if(indx%16 == 0x0f) uprintf("\r\n"); } uprintf("\r\n2nd block of 128, read:\r\n"); i2c0_read(I2C_FRAM_ADDR, framBuf, 128, 128, FALSE); for(indx=0; indx<128; indx++) { uprintf("%02x ", framBuf[indx]); if(indx%16 == 0x0f) uprintf("\r\n"); } wait_consoleTx(); uprintf("\r\n3rd block of 128, read:\r\n"); //i2c0_read(I2C_FRAM_ADDR|0x01, framBuf, 128, 256, FALSE); i2c0_read(I2C_FRAM_ADDR, framBuf, 128, 256, FALSE); for(indx=0; indx<128; indx++) { uprintf("%02x ", framBuf[indx]); if(indx%16 == 0x0f) uprintf("\r\n"); } uprintf("\r\n4th block of 128, read:\r\n"); i2c0_read(I2C_FRAM_ADDR, framBuf, 128, 384, FALSE); for(indx=0; indx<128; indx++) { uprintf("%02x ", framBuf[indx]); if(indx%16 == 0x0f) uprintf("\r\n"); } wait_consoleTx(); } /****************************************************************************** * Initialize and configure I2C module in TIVA tm4c123gh6pge * MFET uses I2C0_BASE on PB2/PB3, the other i2c periph base addr are not used * * Parameters: * ui32Base: I2Cx base address. The address is one of the following values: * I2C0_BASE, I2C1_BASE, I2C2_BASE, I2C3_BASE. * * bFast: * true : I2C will run in fast mode (400kbps) * false: I2C will run in standard mode (100kbps) * * Return: none *****************************************************************************/ void i2c0_init(bool bFast) { //ROM_SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOB); // this is done prior in init.c //enable onchip I2C peripheral ROM_SysCtlPeripheralEnable(SYSCTL_PERIPH_I2C0); //reset I2C module ROM_SysCtlPeripheralReset(SYSCTL_PERIPH_I2C0); // Configure the pin muxing for I2C0 functions on port PB2(SCL) and PB3(SDA). ROM_GPIOPinConfigure(GPIO_PB2_I2C0SCL); // This is the same on 144 pin part and 64pin part ROM_GPIOPinConfigure(GPIO_PB3_I2C0SDA); // Configure the appropriate pins to be I2C instead of GPIO. ROM_GPIOPinTypeI2C(GPIO_PORTB_BASE, GPIO_PIN_2 | GPIO_PIN_3); //GPIOPinTypeI2CSCL(GPIO_PORTB_BASE, GPIO_PIN_2); //GPIOPinTypeI2C(GPIO_PORTB_BASE, GPIO_PIN_3); ROM_GPIOPadConfigSet(GPIO_PORTB_BASE, GPIO_PIN_2, GPIO_STRENGTH_2MA, GPIO_PIN_TYPE_STD); ROM_GPIOPadConfigSet(GPIO_PORTB_BASE, GPIO_PIN_3, GPIO_STRENGTH_2MA, GPIO_PIN_TYPE_OD); // Initialize the I2C master - Transfer speed is defined depend on variable bFast ROM_I2CMasterInitExpClk(I2C0_BASE, SysCtlClockGet(), bFast); //clear I2C FIFOs HWREG(I2C0_BASE + I2C_O_FIFOCTL) = 80008000; ROM_I2CMasterEnable(I2C0_BASE); //I2C is ready to use } /****************************************************************************** * Write multiple bytes to a slave device * * Parameters: * uiSlave_addr : the slave address * *ucData : the data that are going to be sent * uiCount : number of byte will be sent * ucStart_addr : register address you want to write or a control byte * * Return: none * Useful info: https://github.com/sosandroid/FRAM_MB85RC_I2C *****************************************************************************/ void i2c0_write(unsigned char uiSlave_addr, unsigned char *ucData, uint16_t uiCount, uint16_t ucStart_addr) //void i2c0_write(unsigned char uiSlave_add, unsigned char *ucData, uint16_t uiCount, unsigned char ucStart_add) { unsigned int temp = 1; IntMasterDisable(); // Set the slave address and setup for a transmit operation. ROM_I2CMasterSlaveAddrSet(I2C0_BASE, uiSlave_addr, false); // Place the address to be written in the data register. #if FUJITSU_BIGFRAM == 1 // This does not work, need to find a two byte API ROM_I2CMasterDataPut(I2C0_BASE, (uint8_t)(ucStart_addr/256)); #endif ROM_I2CMasterDataPut(I2C0_BASE, (uint8_t)ucStart_addr); while (ROM_I2CMasterBusy(I2C0_BASE)); if (uiCount == 0) // Initiate send of character from Master to Slave ROM_I2CMasterControl(I2C0_BASE, I2C_MASTER_CMD_SINGLE_SEND); else { // Start the burst cycle, writing the address as the first byte. ROM_I2CMasterControl(I2C0_BASE, I2C_MASTER_CMD_BURST_SEND_START); // Write the next byte to the data register. while (ROM_I2CMasterBusy(I2C0_BASE)); ROM_I2CMasterDataPut(I2C0_BASE, ucData[0]); for( ; temp < uiCount; temp++) //Loop to send data if not the last byte { // Continue the burst write. ROM_I2CMasterControl(I2C0_BASE, I2C_MASTER_CMD_BURST_SEND_CONT); // Write the next byte to the data register. while (ROM_I2CMasterBusy(I2C0_BASE)); ROM_I2CMasterDataPut(I2C0_BASE, ucData[temp]); } // Finish the burst write. ROM_I2CMasterControl(I2C0_BASE, I2C_MASTER_CMD_BURST_SEND_FINISH); } while (ROM_I2CMasterBusy(I2C0_BASE)); IntMasterEnable(); } /****************************************************************************** * Read multiple bytes from slave device * * Parameters: * uiSlave_addr: the slave address * *ucRec_Data: a variable to save the data received * uiCount : number of byte will be received * ucStart_addr: register address you want to read or a control byte (Bug fix 9/9/2022: NanoFET has large 128KB FRAM, according to Fujitsu datasheet, large FRAM requires 2 bytes of address) * * Return: none *****************************************************************************/ void i2c0_read(unsigned char uiSlave_addr, unsigned char *ucRec_Data, uint16_t uiCount, uint16_t ucStart_addr, bool bDummyRead) //void I2C_Read(uint32_t ui32Base, unsigned char uiSlave_add, unsigned char *ucRec_Data, uint16_t uiCount, unsigned char ucStart_add, bool bDummyRead) { unsigned int uitemp = 0; // Set the slave address and setup for a transmit operation. IntMasterDisable(); ROM_I2CMasterSlaveAddrSet(I2C0_BASE, uiSlave_addr, false); // Place the address to be written in the data register. #if FUJITSU_BIGFRAM == 1 // This does not work, need to find a two byte API ROM_I2CMasterDataPut(I2C0_BASE, (uint8_t)(ucStart_addr/256)); #endif ROM_I2CMasterDataPut(I2C0_BASE, (uint8_t)ucStart_addr); // Start the burst cycle, writing the address as the first byte. ROM_I2CMasterControl(I2C0_BASE, I2C_MASTER_CMD_BURST_SEND_START); while (ROM_I2CMasterBusy(I2C0_BASE)) ; //while (!(ROM_I2CMasterErr(ui32Base) == I2C_MASTER_ERR_NONE)); ROM_I2CMasterSlaveAddrSet(I2C0_BASE, uiSlave_addr, true); if (uiCount == 1) { ROM_I2CMasterControl(I2C0_BASE, I2C_MASTER_CMD_SINGLE_RECEIVE); while (ROM_I2CMasterBusy(I2C0_BASE)); ucRec_Data[0] = ROM_I2CMasterDataGet(I2C0_BASE); if (bDummyRead) { while (ROM_I2CMasterBusy(I2C0_BASE)); ucRec_Data[0] = ROM_I2CMasterDataGet(I2C0_BASE); } } else { ROM_I2CMasterControl(I2C0_BASE, I2C_MASTER_CMD_BURST_RECEIVE_START); if (bDummyRead) { while (ROM_I2CMasterBusy(I2C0_BASE)) ; ucRec_Data[0] = ROM_I2CMasterDataGet(I2C0_BASE); } while (ROM_I2CMasterBusy(I2C0_BASE)) ; ucRec_Data[uitemp++] = ROM_I2CMasterDataGet(I2C0_BASE); for ( ; uitemp < (uiCount - 1); uitemp++) { ROM_I2CMasterControl(I2C0_BASE, I2C_MASTER_CMD_BURST_RECEIVE_CONT); while (ROM_I2CMasterBusy(I2C0_BASE)) ; ucRec_Data[uitemp] = ROM_I2CMasterDataGet(I2C0_BASE); } ROM_I2CMasterControl(I2C0_BASE, I2C_MASTER_CMD_BURST_RECEIVE_FINISH); while (ROM_I2CMasterBusy(I2C0_BASE)) ; ucRec_Data[uitemp] = ROM_I2CMasterDataGet(I2C0_BASE); } while (ROM_I2CMasterBusy(I2C0_BASE)) ; IntMasterEnable(); }