Reading and writing a 24LC32A eeprom memory using the LPCOpen framework for the LPC1549 chip

In order for myself to understand how to use the I2C module in the LPC1549 chip using the LPCOpen framework and the LPCXpresso1549 board for bigger projects, I started a simple one consisting of reading/writing  from/to a well known device: a 24LC32A eeprom memory (or alike).

I like to write device drivers, so my goal, after understanding the I2C module, is to write a functional and useful device driver for this kind of memory. Sadly that is not what you’ll find here (for now). Why? Because most people want the fast road to get the things done, not a complete driver. Besides, keeping things simple is better for newbies (like myself, as you might guess).

This example is based upon an example in such framework, with no interrupts (inside LPCXpresso 7.5.0 in Linux Mint) . And beforehand, sorry for the comments written in spanish. I wrote them as I was coding. Nonetheless, I think the code speakes by itself.

The first routine reads n bytes from the eeprom memory:

uint32_t E2PROM_Read(uint8_t slave_address, uint16_t address, uint16_t bytes_to_read, uint8_t * in_buffer)
{
    const uint16_t bytes_to_write = 2;
    // el comando de lectura de la e2prom sabe que debe transmitir exactamente
    // dos bytes: la parte alta de la dirección, y la parte baja
    
    uint8_t out_buffer[2] = {0x00, 0x00};
    // out_buffer[0] es la parte alta de la dirección que se desea leer
    // out_buffer[1] es la parte baja de la dirección que se desea leer
    
    I2CM_XFER_T  i2cmXferRec;

    out_buffer[0] = (uint8_t)(address >> 8);
    out_buffer[1] = (uint8_t)(address & 0x00FF);

    i2cmXferRec.slaveAddr = slave_address;
    i2cmXferRec.status    = 0;
    i2cmXferRec.txSz      = bytes_to_write;
    i2cmXferRec.txBuff    = out_buffer;
    i2cmXferRec.rxSz      = bytes_to_read;
    i2cmXferRec.rxBuff    = in_buffer;

    Chip_I2CM_XferBlocking(LPC_I2C0, &i2cmXferRec);
    // esta llamada se bloquea, por lo tanto el valor devuelto no importa, sino
    // el valor contenido en el campo .status

    return i2cmXferRec.status;
    // .status = 0 si la operación terminó correctamente
}

The second routine writes n bytes into the eeprom memory. This is a little bit tricky in the sense that we need a buffer that is capable of storing the size of the largest buffer we want to write, plus two extra bytes. So be careful when dimensioning the buffer that has been declared inside this rutine.

uint32_t E2PROM_Write(uint8_t slave_address, uint16_t address, uint16_t bytes_to_write, uint8_t * out_buffer)
{

 I2CM_XFER_T i2cmXferRec;
 uint8_t _out_buffer[10];
 uint16_t i = 0;

 _out_buffer[0] = (uint8_t)(address >> 8);
 _out_buffer[1] = (uint8_t)(address & 0x00FF);

 for (i = 0; i < bytes_to_write; i++) {
     _out_buffer[2+i] = out_buffer[i];
 }

 i2cmXferRec.slaveAddr = slave_address;
 i2cmXferRec.status    = 0;
 i2cmXferRec.txSz      = 2 + bytes_to_write;
 i2cmXferRec.txBuff    = _out_buffer;
 i2cmXferRec.rxSz      = 0;
 i2cmXferRec.rxBuff    = NULL;
 Chip_I2CM_XferBlocking(LPC_I2C0, &i2cmXferRec);

 return i2cmXferRec.status;
}

Finally, we have the driver program to test the previous routines. Remember that this is my first attempt towards a functional device driver (or Abstract Data Type for the eeprom memory):

int main(void) {
 uint8_t slave_address = I2C_24LC32_ADDR_7BIT;
 uint16_t bytes_to_write = 2;
 uint8_t out_buffer[2] = {0x33, 0x99};
 uint16_t bytes_to_read = 4;
 uint8_t in_buffer[4] = {0xAA, 0x55, 0xAA, 0x55};

 uint32_t ret = 0xff;

#if defined (__USE_LPCOPEN)
#if !defined(NO_BOARD_LIB)
 // Read clock settings and update SystemCoreClock variable
 SystemCoreClockUpdate();
 // Set up and initialize all required blocks and
 // functions related to the board hardware
 Board_Init();
 // Set the LED to the state of "On"
 Board_LED_Set(0, false);
#endif
#endif

 Init_I2C_PinMux();
 // multiplexa los pines de I2C

 setupI2CMaster();
 // inicializa al módulo I2C

 NVIC_DisableIRQ(I2C0_IRQn);
 // deshabilita las interrupciones para la I2C

 // SysTick_Config(SystemCoreClock / TICKRATE_HZ);
 // habilita al SysTick Timer

 ret = E2PROM_Write(slave_address, 0x0001, bytes_to_write, out_buffer);
 ret = E2PROM_Read(slave_address, 0x0000, bytes_to_read, in_buffer);

 while (1)
     ;

 return 0 ;
}

Hope this routines are helpful for your projects. And as always, any comments are appreciated.

Anuncios

Responder

Introduce tus datos o haz clic en un icono para iniciar sesión:

Logo de WordPress.com

Estás comentando usando tu cuenta de WordPress.com. Cerrar sesión / Cambiar )

Imagen de Twitter

Estás comentando usando tu cuenta de Twitter. Cerrar sesión / Cambiar )

Foto de Facebook

Estás comentando usando tu cuenta de Facebook. Cerrar sesión / Cambiar )

Google+ photo

Estás comentando usando tu cuenta de Google+. Cerrar sesión / Cambiar )

Conectando a %s