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łączenie funkcji wyprowadzeń 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łączenie sygnału zegarowego dla kontrolera I2C; bity 14 i 15 PCLK_I2C0 LPC_SC->PCLKSEL0 &=~(1<<15); // włączenie sygnału zegarowego dla kontrolera I2C; bity 14 i 15 PCLK_I2C0 /* wartoś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łodszy (np. z pary bitów PCLK_I2C0 to bit 14) */ NVIC_EnableIRQ(I2C0_IRQn); // włączenie generowania przerwań 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ędkosc na 100 kbps) // zmienne pomocnicze // zmienne przechowujące wartośći zegarów uint32_t MainOscFreq = 0; // czestotliwość taktowania głównego oscylatora "XTAL" - kwarcu zewnętrznego uint32_t PLL0Freq = 0; // częśtotliwość taktowania na wyjściu pętli PLL0 uint32_t CoreFreq = 0; // częstotliwość taktowania rdzenia procesora ARM uint32_t APB0Freq = 0; // częśtotliwość taktowania magistrali APB0 (do której podłączony jest UART0 i UART1) // zmienne przechowujące wartości dzielników preslalerów poszczególnych częstotliwości taktownia // zmienne przechowujące wartość dzielnika i mnożnika w pętli PLL0 uint16_t PLL0Div = 0; // dzielnik N w pętli PLL0 uint16_t PLL0Mult = 0; // mnożnik M w pętli PLL0 // zmienna przechowująca wartość dzielnika częstotliwości taktowania rdzenia procesora ARM uint8_t CoreDiv = 0; // dzielnik częstotliwości pętli PLL0 dla taktowania rdzenia procesora ARM // zmienna przechowująca wartość dzielnika częstotliwości taktowania magistrali systemowej APB0 (Advanced Peripherial Bus) uint8_t APB0Div = 0; // dzielnik magistrali APB0 dla kontrolerów UART0 i UART1 (ta sama wartość) // obliczenie częstotliwości poszczególnych zegarów // wartość czestotliwości taktowania głównego oscylatora "XTAL" - kwarcu zewnętrznego MainOscFreq = 12000000; // wartość częśtotliwości na wyjściu pętli PLL0 PLL0Mult = (((LPC_SC->PLL0CFG) & 0x00007FFF) + 1); // wartość mnożnika pę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ść dzielnika pętli PLL0 bity 16-23 NSEL0: N-1; maska 0000 0000 0000 0000 0000 1111 1111 (8 bitów) // i wcześniej przesuniecie bitowe o 16 bitów w prawo PLL0Freq = (2 * PLL0Mult * MainOscFreq) / (PLL0Div); // wzór ze str. 41 dokumentacji // wartość częstotliwości taktowaniardzenia procesora ARM CoreDiv = (LPC_SC->CCLKCFG) + 1; // wartość dzielnika częstotliwości pętli PLL0 dla taktowania rdzenia procesora ARM CoreFreq = PLL0Freq/CoreDiv; // wartość częstotliwości taktowania rdzenia procesora ARM // wartość częśtotliwości taktowania magistrali APB0 (do której podłą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ś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 |
// 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 } } |
#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); } |