Lpc1768 - i2c 0

cancel
Showing results for 
Show  only  | Search instead for 
Did you mean: 

Lpc1768 - i2c 0

3,210 Views
lpcware
NXP Employee
NXP Employee
Content originally posted in LPCWare by teslabox on Thu Mar 22 07:44:14 MST 2012
Hello everyone,

I try to connect to the LIS3DH accelerometer thru the I2C bus.
In the LIS3DH datasheet there is written that it has the I2C digital output (16 bits resolution).
First I initialized I2C for set clock timing at Standard Drive Speed Mode (100 kbps) but there is no clock signal on the SCL0 line (all the time is the high level) - I checked it by oscilloscope.
Below I send my C code:
    LPC_SC->PCONP         |= (1<<7);        // wlaczenie zasilania i sygnalu zegarowego dla kontrolera magistrali I2C 0

    LPC_PINCON->PINSEL0 &=~(1<<22);        // ustawienie wyprowadzenia P0.27 jako GPIO
    LPC_PINCON->PINSEL0 &=~(1<<23);        // ustawienie wyprowadzenia P0.27 jako GPIO
    LPC_PINCON->PINSEL0 &=~(1<<24);        // ustawienie wyprowadzenia P0.28 jako GPIO
    LPC_PINCON->PINSEL0 &=~(1<<25);        // ustawienie wyprowadzenia P0.28 jako GPIO

    // prze&#322;&#261;czenie funkcji wyprowadze&#324; z GPIO na SDA0 dla I2C 0
    LPC_PINCON->PINSEL0 |= (1<<22);        // ustawienie wyprowadzenia P0.27 jako SDA0
    LPC_PINCON->PINSEL0 &=~(1<<23);        // ustawienie wyprowadzenia P0.27 jako SDA0
    LPC_PINCON->PINSEL0 |= (1<<24);        // ustawienie wyprowadzenia P0.28 jako SCL0
    LPC_PINCON->PINSEL0 &=~(1<<25);        // ustawienie wyprowadzenia P0.28 jako SCL0

    LPC_SC->PCLKSEL0     &=~(1<<14);        // w&#322;&#261;czenie sygna&#322;u zegarowego dla kontrolera I2C; bity 14 i 15 PCLK_I2C0
    LPC_SC->PCLKSEL0     &=~(1<<15);        // w&#322;&#261;czenie sygna&#322;u zegarowego dla kontrolera I2C; bity 14 i 15 PCLK_I2C0
                                            /* warto&#347;ci: 00 - PCLK UART0 = CCLK/4
                                             *           01 - PCLK UART0 = CCLK
                                             *           10 - PCLK UART0 = CCLK/2
                                             *           11 - PCLK UART0 = CCLK/8
                                             * gdzie:    x  - bit starszy (np. z pary bitów PCLK_I2C0 to bit 15)
                                             *               x - bit m&#322;odszy (np. z pary bitów PCLK_I2C0 to bit 14)
                                             */
       NVIC_EnableIRQ(I2C0_IRQn);            // w&#322;&#261;czenie generowania przerwa&#324; od kontrolera magistrali I2C 0

       LPC_I2C0->I2CONSET         |= (1<<5)|(1<<6);    // bit STA: START flag sending, bit I2CEN: I2C interface enable -> MASTER MODE
       LPC_PINCON->I2CPADCFG     &=~(1<<0)|(1<<1)|(1<<2)|(1<<3); // Standard Drive Mode (pr&#281;dkosc na 100 kbps)

       // zmienne pomocnicze

           // zmienne przechowuj&#261;ce warto&#347;&#263;i zegarów
           uint32_t MainOscFreq     = 0;    // czestotliwo&#347;&#263; taktowania g&#322;ównego oscylatora "XTAL" - kwarcu zewn&#281;trznego
           uint32_t PLL0Freq         = 0;    // cz&#281;&#347;totliwo&#347;&#263; taktowania na wyj&#347;ciu p&#281;tli PLL0
           uint32_t CoreFreq         = 0;    // cz&#281;stotliwo&#347;&#263; taktowania rdzenia procesora ARM
           uint32_t APB0Freq         = 0;    // cz&#281;&#347;totliwo&#347;&#263; taktowania magistrali APB0 (do której pod&#322;&#261;czony jest UART0 i UART1)

           // zmienne przechowuj&#261;ce warto&#347;ci dzielników preslalerów poszczególnych cz&#281;stotliwo&#347;ci taktownia

           // zmienne przechowuj&#261;ce warto&#347;&#263; dzielnika i mno&#380;nika w p&#281;tli PLL0
           uint16_t PLL0Div         = 0;    // dzielnik N w p&#281;tli PLL0
           uint16_t PLL0Mult         = 0;    // mno&#380;nik  M w p&#281;tli PLL0

           // zmienna przechowuj&#261;ca warto&#347;&#263; dzielnika cz&#281;stotliwo&#347;ci taktowania rdzenia procesora ARM
           uint8_t CoreDiv            = 0;     // dzielnik cz&#281;stotliwo&#347;ci p&#281;tli PLL0 dla taktowania rdzenia procesora ARM

           // zmienna przechowuj&#261;ca warto&#347;&#263; dzielnika cz&#281;stotliwo&#347;ci taktowania magistrali systemowej APB0 (Advanced Peripherial Bus)
           uint8_t APB0Div         = 0;    // dzielnik magistrali APB0 dla kontrolerów UART0 i UART1 (ta sama warto&#347;&#263;)

       // obliczenie cz&#281;stotliwo&#347;ci poszczególnych zegarów

           // warto&#347;&#263; czestotliwo&#347;ci taktowania g&#322;ównego oscylatora "XTAL" - kwarcu zewn&#281;trznego
           MainOscFreq = 12000000;

           // warto&#347;&#263; cz&#281;&#347;totliwo&#347;ci na wyj&#347;ciu p&#281;tli PLL0
           PLL0Mult = (((LPC_SC->PLL0CFG)       & 0x00007FFF) + 1);    // warto&#347;&#263; mno&#380;nika  p&#281;tli PLL0 bity 0 -14 MSEL0: M-1; maska 0000 0000 0000 0111 1111 1111 1111 (15 bitów)
           PLL0Div  = (((LPC_SC->PLL0CFG >> 16) & 0x000000FF) + 1);    // warto&#347;&#263; dzielnika p&#281;tli PLL0 bity 16-23 NSEL0: N-1; maska 0000 0000 0000 0000 0000 1111 1111 (8 bitów)
                                                                       // i wcze&#347;niej przesuniecie bitowe o 16 bitów w prawo
           PLL0Freq = (2 * PLL0Mult * MainOscFreq) / (PLL0Div);        // wzór ze str. 41 dokumentacji

           // warto&#347;&#263; cz&#281;stotliwo&#347;ci taktowaniardzenia procesora ARM
           CoreDiv  = (LPC_SC->CCLKCFG) + 1;                            // warto&#347;&#263; dzielnika cz&#281;stotliwo&#347;ci p&#281;tli PLL0 dla taktowania rdzenia procesora ARM
           CoreFreq = PLL0Freq/CoreDiv;                                // warto&#347;&#263; cz&#281;stotliwo&#347;ci taktowania rdzenia procesora ARM

           // warto&#347;&#263; cz&#281;&#347;totliwo&#347;ci taktowania magistrali APB0 (do której pod&#322;&#261;czony jest CAN1 i CAN2)
           APB0Div  = ((LPC_SC->PCLKSEL0 >> 6) & 0x00000003);            // dzielnik magistrali APB0 dla kontrolera magistrali UART0 bity 6 i 7 PCLK_UART0
                                                                       // maska 0000 0000 0000 0000 0000 0000 0000 0011 i wcze&#347;niej przesuniecie bitowe o 6 bitów w prawo
               if (APB0Div == 0x00)        // dzielnik = 4;
               {
                   APB0Freq = CoreFreq/4;
               }
               else if (APB0Div == 0x01)        // dzielnik = 1;
               {
                   APB0Freq = CoreFreq/1;
               }
               else if (APB0Div == 0x02)        // dzielnik = 2;
               {
                   APB0Freq = CoreFreq/2;
               }
               else if (APB0Div == 0x03)        // dzielnik = 8;
               {
                   APB0Freq = CoreFreq/8;
               }

               LPC_I2C0->I2SCLH = (APB0Freq/100000)/2;    // 100000 - 100 kpbs (Standard I2C Drive Speed Mode)
               LPC_I2C0->I2SCLL = (APB0Freq/100000)/2; // 100000 - 100 kpbs (Standard I2C Drive Speed Mode)
               // divider is 2; it gives I2C period Duty Cycle = 50 % at 100 kbps speed
0 Kudos
Reply
7 Replies

2,342 Views
lpcware
NXP Employee
NXP Employee
Content originally posted in LPCWare by daniel.widyanto on Mon Oct 15 00:11:17 MST 2012
Check with your oscilloscope if your I2C slave is working.

The sequence should be
[LIST=1]
[1]0x08 -> START bit sent
[2]0x18 -> I2C slave address sent and slave responds with ACK (or)
[2a]0x20 -> I2C slave address sent and slave responds with NACK (or)
[2b]0x38 -> Only happen in multi-master I2C bus (or)
[2c]0x68 -> Only happen in multi-master I2C bus
[/LIST]

I suppose you are addressing incorrect I2C slave, and hence receiving 0x20 (instead of 0x18) as I2C mode, because the I2C slave didn't respond (NACK received) to the slave address.
0 Kudos
Reply

2,342 Views
lpcware
NXP Employee
NXP Employee
Content originally posted in LPCWare by teslabox on Thu Oct 11 02:29:50 MST 2012
Hi,

Ok, there is a complete ZIP folder with project files.
I will be grateful for help in this case ;).
0 Kudos
Reply

2,342 Views
lpcware
NXP Employee
NXP Employee
Content originally posted in LPCWare by serge on Thu Oct 11 00:08:59 MST 2012
Could you export en post your (partial) project here?:p
So we can have a look at the complete picture.
0 Kudos
Reply

2,342 Views
lpcware
NXP Employee
NXP Employee
Content originally posted in LPCWare by teslabox on Wed Oct 10 00:47:15 MST 2012
Hello,

I came back to this staff. I need to use 256 kb EEPROM memory (ATMEL AT24C256) to storage some data using again I2C with LPCXpresso LPC1769.

I carefully read the LPC1769 datasheet about the I2C bus and I wrote some C code for I2C as below:

// Function for the initialization I2C0 bus
void I2C0_InitMasterMode (void)
{
    // Set I2C bus active
    LPC_SC->PCONP         |= (1<<7);          // Set the I2C0 bus power
    LPC_SC->PCLKSEL0     &=~(1<<14)|(1<<15);  // Set PCLK clock for I2C0 bus
                                              // bits 14 and 15 = 0 -> PCLK_peripheral = CCLK/4
                                              // CCLK = 100 MHz, PCLK = 100 MHz/4 = 25 MHz for bitrate frequency

    // First configure pins P0.27 and P0.28 as normal GPIO pins
    LPC_PINCON->PINSEL1 &=~(1<<22);           // Set pin P0.27 as GPIO
    LPC_PINCON->PINSEL1 &=~(1<<23);           // Set pin P0.27 as GPIO
    LPC_PINCON->PINSEL1 &=~(1<<24);           // Set pin P0.28 as GPIO
    LPC_PINCON->PINSEL1 &=~(1<<25);           // Set pin P0.28 as GPIO

    // Now configure pins P0.27 and P0.28 as I2C0 bus pins
    LPC_PINCON->PINSEL1 |= (1<<22);           // Set pin P0.27 as SDA0 I2C0
    LPC_PINCON->PINSEL1 &=~(1<<23);           // Set pin P0.27 as SDA0 I2C0
    LPC_PINCON->PINSEL1 |= (1<<24);           // Set pin P0.28 as SCL0 I2C0
    LPC_PINCON->PINSEL1 &=~(1<<25);           // Set pin P0.28 as SCL0 I2C0

    // Reset (clear) the STAC andSIC bits for configure the Master Mode I2C0 bus
    LPC_I2C0->I2CONCLR =  (1<<3);              // Reset (clear) SIC  bit (I2C interrupt)
    LPC_I2C0->I2CONCLR =  (1<<5);              // Reset (clear) STAC bit (START flag)

    /* Calculate and set the proper value of I2C0 clock registers for 100 kHz bitrate frequency
     * I2C0_Freq = PCLK/(SCLH + SCLL)
     * SCLH + SCLL = 25000 kHz/100 kHz = 250
     * SCLH = SCLL = 125 => 50% duty cycle
    */
    LPC_I2C0->I2SCLH    = 125;                 // SCL prescaler High register
    LPC_I2C0->I2SCLL    = 125;                 // SCL prescaler Low register

    // Configure I2C0 pin in the Standard Drive Mode
    LPC_PINCON->I2CPADCFG &=~(1<<0)|(1<<1)|(1<<2)|(1<<3);   // Standard Drive Mode (100 kbps)
                                                            // bit 0 reset to 0 - The SDA0 pin is in the standard drive mode
                                                            // bit 1 reset to 0 - The SDA0 pin has I2C glitch filtering and slew rate control enabled
                                                            // bit 2 reset to 0 - The SCL0 pin is in the standard drive mode
                                                            // bit 3 reset to 0 - The SCL0 pin has I2C glitch filtering and slew rate control enabled

    NVIC_EnableIRQ (I2C0_IRQn);                // Set the I2C0 Interrupts in the Global Interrupts; active
    LPC_I2C0->I2CONSET |= (1<<6);              // Enable the I2C0; bus bit 6
}

// The function for generate START condition
void I2C0_Start (void)
{
    LPC_I2C0->I2CONSET = (1<<5);      // Set the STA bit; bit 5
}

// I2C0 Interrupt function; Each Status Register change will cause enter into the I2C0_IRQHandler function
void I2C0_IRQHandler (void)
{
    LPC_GPIO0->FIOSET |= (1<<22);    // Turn the LED 1 P0.22 on

    switch (LPC_I2C0->I2STAT)        // Read value of the I2C0 Status Register
    {
        // I2C0 Status register value '0x08' meaning: 'A START condition has been transmitted'
        // Next step to do: 'SLA+W will be transmitted; ACK bit will be received'
        case 0x08:
            // Send on the I2C0 "Slave Device Address" = 160 (b0 = 0 -> Write to the Slave device)
            LPC_I2C0->I2DAT     = 160;       // Slave Address is '1010 00X' where X is Read (R=1) or Write (W=1) bit
            LPC_I2C0->I2CONSET  = (1<<2);    // Set the AA bit (Assert Acknowledge)
            LPC_I2C0->I2CONCLR  = (1<<3);    // Reset the SI bit
            LPC_GPIO2->FIOSET   |=(1<<2);    // Turn the LED on P2.2 on
        break;                               // Go out of the switch cases

        // Status value meaning: 'SLA+W has been transmitted; ACK has been received'
        // Next step to do: 'Data byte will be transmitted; ACK bit will be received'
        case 0x18:
            // Send on the I2C0 "First Word Data" = 0
            LPC_I2C0->I2DAT     =  0;
            LPC_I2C0->I2CONSET  = (1<<2);    // Set the AA bit (Assert Acknowledge)
            LPC_I2C0->I2CONCLR  = (1<<3);    // Reset the SI bit
            LPC_GPIO2->FIOSET   |=(1<<3);    // Turn the LED on P2.3 on
        break;                               // Go out of the switch cases

        // Status value meaning: 'Data byte in I2DAT has been transmitted; ACK has been received'
        // Next step to do: 'Data byte will be transmitted; ACK bit will be received'
        case 0x28:
            // Send on the I2C0 "Second Word Data" = 0
            LPC_I2C0->I2DAT     =  0;    
            LPC_I2C0->I2CONSET  = (1<<2);    // Set the AA bit (Assert Acknowledge)
            LPC_I2C0->I2CONCLR  = (1<<3);    // Reset the SI bit
            LPC_GPIO2->FIOSET   =(1<<4);     // Turn the LED on P2.4 on
        break;                               // Go out of the switch cases

        // When I2C0 Status register will give other values then show this value on the LEDs 2-6 and turn the LED 1 off
        default:
            LPC_GPIO0->FIOCLR |= (1<<22);                               // Turn the LED 1 P0.22 off
            LPC_GPIO2->FIOSET |= (1<<7);                                // Turn the LED 7 P2.7 on
            LPC_GPIO2->FIOCLR |= (1<<2)|(1<<3)|(1<<4)|(1<<5)|(1<<6);    // Turn the LED 6-2 P2.2-P2.6 off
            LPC_GPIO2->FIOSET |= ((LPC_I2C0->I2STAT) >> 3);             // Shift 3 bits right I2C0 Status Register
                                                                        // 5 bits 7-3 give the actual status information about the I2C interface
        break;
    }
}

// ---------------------------------------------------------------------------------------------------------------------------------------------------------- //
// ---------------------------------------------------------------------- MAIN PROGRAM ---------------------------------------------------------------------- //
// ---------------------------------------------------------------------------------------------------------------------------------------------------------- //

/* 7 LEDs meaning:
 * LED 1 on the pin P0.22 - is turned on only if the program enters into the I2C0 Interrupt (START condition) (apart of enters into the 'default');
 * LED 2 on the pin P2.2  - is turned on only if the program enters into the I2C0 Interrupt and enters into the "case" with 0x08 value;
 * LED 3 on the pin P2.3  - is turned on only if the program enters into the I2C0 Interrupt and enters into the "case" with 0x28 value;
 * LED 5 on the pin P2.5  - is not used as a single LED;
 * LED 6 on the pin P2.6  - is not used as a single LED;
 * LED 7 on the pin P2.7  - is turned on only if the program enters into the I2C0 Interrupt and enters into the "default": then 'I2C Status Register' value (bits 7-3)
 *                          is displayed on the five LEDs (b7-LED5, b6-LED5, b5-LED4, b4-LED3, b3-LED2) so turning on LEDs combination like: 00000X gives 0x08, 
 *                          000X0X gives 0x28, etc. Just write three zeros on the right side.
 *                        - is toggling only if the program goes out of the I2C0 Interrupt and enters into the main 'for (;;)' loop in the main program;
*/

// Main program
int main (void)
{
    // Set the pins P2.3-P2.7 as the I2STAT register mirror in LEDs lights
    LPC_GPIO2->FIODIR |= (1<<2)|(1<<3)|(1<<4)|(1<<5)|(1<<6)|(1<<7);
    LPC_GPIO2->FIOCLR |= (1<<2)|(1<<3)|(1<<4)|(1<<5)|(1<<6)|(1<<7);

    // Set the pin P0.22 as output with LED
    LPC_GPIO0->FIODIR |= (1<<22);        // Pin GPIO P0.22 as an output
    LPC_GPIO0->FIOCLR |= (1<<22);        // An output in low state

    // Initialization the I2C0 bus
    I2C0_InitMasterMode ();              // Initialization the I2C0 bus with 100 kbps bitrate frequency
    I2C0_Start ();                       // Generate the START condition, if START bit is set then program goes into "I2C0_IRQHandler"

    uint8_t a = 0;                       // A temporary 8-bit variable just for using 'for (;;)' loop below

    // Toggle the LED 7 on the pin P2.7
    for (a=0; a<255; a++)
    {
        LPC_GPIO2->FIOPIN     ^= (1<<7); // Turn the LED on P2.7 on
        delay (100);                     // Just wait for 100 ms
    }
}
First I send START condidtion and the program enters into the I2C0 Interrupt (LED 1 turns on), next the '0x08' value of Status register is set (LED 2 turns on) but in the next step the program leaves  I2C0 Iterrupt (LED 7 is toogling) and there is no '0x28' value of the Status register and I don't know why it happen... I took a look at Rob65's C code on the http://hg.bikealive.nl/Platform1754/file/ae0834ece8c9/Drivers/lpc17xx/i2c.c and in my opinion the basic/root steps are simillar. Any idea what is wrong in my C code?
0 Kudos
Reply

2,342 Views
lpcware
NXP Employee
NXP Employee
Content originally posted in LPCWare by teslabox on Fri Mar 23 02:44:48 MST 2012
I wrote a part of code for my start. IN the beginig SCL line is in HI level and when I write START bit it goes on the LOW and when I write Slave Address to the bus nothing shows on the osciloscope (LOW level on thew SDA).

#define LIS3DH_SAD_W    0x30    // SAD_W - Slave Address and Write to the slave,  SAD[0]=SA0=0 (GND)
#define LIS3DH_SAD_R    0x31    // SAD_R - SLave Address and Read from the slave, SAD[0]=SA0=0 (GND)

// main program
int main (void)
{
    All_LEDs_ResetandToogle ();            // toogle LEDs connected as shown in the definitions above

    LPC_SC->PCONP |= (1<<7);            // turn on Power and Clock for I2C 0

    LPC_PINCON->PINSEL1 &=~(1<<22)|(1<<23);        // set P0.27 as GPIO
    LPC_PINCON->PINSEL1 &=~(1<<24)|(1<<25);        // set P0.28 as GPIO

    // set from GPIO to SDA0 and SCL for I2C 0
    LPC_PINCON->PINSEL1 |= (1<<22);        // set P0.27 as SDA0
    LPC_PINCON->PINSEL1 |= (1<<24);        // set P0.28 as SCL0

    LPC_SC->PCLKSEL0 &=~(1<<14);        // set Clock signal for I2C0; bits 14 i 15 PCLK_I2C0
    LPC_SC->PCLKSEL0 &=~(1<<15);        // set Clock signal for I2C0; bits 14 i 15 PCLK_I2C0
                                        /* values: 00 - PCLK UART0 = CCLK/4 - this option is selected
                                         *         01 - PCLK UART0 = CCLK
                                         *         10 - PCLK UART0 = CCLK/2
                                         *         11 - PCLK UART0 = CCLK/8
                                         * where:  x  - MSb; PCLK_I2C0 - bit 15
                                         *             x - LSb; PCLK_I2C0 - bit 14
                                         */
    LPC_I2C0->I2CONCLR |= (1<<2)|(1<<3)|(1<<5)|(1<<6);    // clear flags: Assert acknowledge
                                                        //              I2C interrupt
                                                        //                 START condition flag
                                                        //              I2C bus enable

       LPC_PINCON->I2CPADCFG &=~(1<<0)|(1<<1)|(1<<2)|(1<<3); // Standard Drive Mode (100 kbps)

    // PCLK_I2C0=CCLK/4=100MHz/4=25MHz->25000kHz/100kHz=250=I2SCLH+I2SCLL
    // for 50 & Duty Cycle => 125 + 125
    LPC_I2C0->I2SCLH = 125;    // 100000 - 100 kpbs (Standard I2C Drive Speed Mode)
    LPC_I2C0->I2SCLL = 125; // 100000 - 100 kpbs (Standard I2C Drive Speed Mode)
    // divider is 2; it gives I2C period Duty Cycle = 50 % at 100 kbps speed

       NVIC_EnableIRQ(I2C0_IRQn);        // enable interrupting from I2C 0

    LPC_I2C0->I2CONSET |= (1<<6);    // bit I2CEN: I2C interface enable, Master mode

    delay (300);

    // MASTER IS WRITTING
    // send configuration to LIS3DH
    LPC_I2C0->I2CONSET |= (1<<5);    // set START bit
    LPC_I2C0->I2DAT = LIS3DH_SAD_W;    // write Slave Address (SAD)
    LPC_I2C0->I2CONCLR |= (1<<5);    // clear START bit after write SAD



    for (;;)
    {
            // do nothing for now
    }
    return (0);
}
0 Kudos
Reply

2,342 Views
lpcware
NXP Employee
NXP Employee
Content originally posted in LPCWare by Rob65 on Thu Mar 22 23:03:14 MST 2012
There are a number of I2C examples floating around.
Here is my I2C driver (look in Drivers/lpc17xx) - an enhanced version of the NXP one. Unfortunately still without example or documentation on how to use it ... I might fix that this weekend.

Regards,
[INDENT]Rob
[/INDENT]
0 Kudos
Reply

2,342 Views
lpcware
NXP Employee
NXP Employee
Content originally posted in LPCWare by serge on Thu Mar 22 07:59:11 MST 2012
As long as you don't send (or read) any data the SCL line should be high.
I had no time to really check out your code (my polish is not good enough (dzien dobry)) but does the SCL line stay high when trying to send data?
0 Kudos
Reply