I²C communication on the LPC810 (without using the ROM API)

取消
显示结果 
显示  仅  | 搜索替代 
您的意思是: 

I²C communication on the LPC810 (without using the ROM API)

135 次查看
LPC81x1114
Contributor I

I wish to establish I²C communication with NXP's LM75A temperature sensor using an LPC810 microcontroller for educational purposes, without utilising the ROM API.

I have managed to send I²C commands unilaterally and display text on an LCD, for instance, but I am unsure how to write code for communicating with a slave device like the LM75A, which requires read operations. I have attached my current source code below; at present, I cannot read the temperature from the LM75A.
■ Overview
・I/O ports assigned for I2C functionality
・Communication via polling, without interrupts

■ Main Queries
When wishing to return an ACK signal in master receive mode, it appears the LPC810 lacks such a register (only registers for the three conditions: START, CONTINUE, STOP). Can this be read using the attached code? If possible, I would appreciate a concrete example of source code.

 

#ifdef __USE_CMSIS

#include "LPC8xx.h"

#endif

 

#include <cr_section_macros.h>

#include "romI2C.h" //本コードはROMAPIを使用してないので、I2Cの定数定義部分のみ

#include "I2C_DEFINE.h"

 

 

#define LM75AAddr (0x48) //温度センサ アドレス

#define I2C_RW_W (0x00) //RW(LSB)はLCDは常に0

 

#define LM75TempRegi_pointer (0x00) //Tempレジスタポイタ

//Command:RS=0,Data:RS=1

#define LM75ConfRegi_pointer (0x01) //Configuration registerポインタ

 

 

int waiting=0;

 

void SwitchMatrix_Init();

void IOCON_Init();

void I2C_Init();

 

//void I2C_one_Byte_Write(uint8_t data);

void I2C_Multiple_Write(uint8_t Addr,uint8_t WriteByte,uint8_t *i2c_data);

void Systick_Init();

void I2C_Addr_WSend(uint8_t Addr);

void I2C_Addr_RSend(uint8_t Addr);

void Temp_SenceInit();

uint8_t I2C_Multiple_Read(uint8_t Addr,uint8_t ReadByte);

uint16_t ReadTemperture_LM75A(uint8_t Addr);

void mon_CFG(); //I2Cデータモニタ用関数

//void I2C_Stop();

 

//Systick

void SysTick_Handler(){

waiting=0;

}

 

 

static void wait_ms(uint32_t ms){

waiting=1;

SysTick_Config(SystemCoreClock/1000*ms);

while(waiting);

}

 

 

 

int main(void) {

int LED_C;

uint16_t temp=0;

LPC_GPIO_PORT->DIR0 |=(1<<1);

SystemCoreClockUpdate();

// Enter an infinite loop, just incrementing a counter

IOCON_Init();

SwitchMatrix_Init();

 

while(1){

temp=ReadTemperture_LM75A(LM75AAddr);

}

return 0 ;

}//main

 

 

void I2C_Init(){

LPC_SYSCON->PRESETCTRL &= ~(0x1<<6); //Assert Reset

LPC_SYSCON->PRESETCTRL |= (0x1<<6); //Clear Resett

//Set i2c clock DIV

LPC_I2C->DIV = 0x0001; //PCLK I2C Clock 

LPC_I2C->MSTTIME=0; //Mater SCL Low Timee

 

LPC_I2C->CFG = I2C_CFG_MSTEN | 0x04; //マスターモード モニタイネーブル クロックストレッチ

}

 

void Temp_SenceInit(){ //温度センサ初期設定

uint8_t Config[3]={LM75AAddr,LM75ConfRegi_pointer,0x00}; //

 

I2C_Multiple_Write(LM75AAddr, 3, Config);

}

 

void I2C_Addr_WSend(uint8_t Addr){

while(!(LPC_I2C->STAT & I2C_STAT_MSTPENDING));

if((LPC_I2C->STAT & I2C_STAT_MSTSTATE) != I2C_STAT_MSTST_IDLE);

LPC_I2C->MSTDAT = (Addr<<1|0); // address and 0 for RWn bit

LPC_I2C->MSTCTL = I2C_MSTCTL_MSTSTART; // send start

while(!(LPC_I2C->STAT & I2C_STAT_MSTPENDING));

if((LPC_I2C->STAT & I2C_STAT_MSTSTATE) != I2C_STAT_MSTST_TX);

}

 

void I2C_Addr_RSend(uint8_t Addr){

while(!(LPC_I2C->STAT & I2C_STAT_MSTPENDING));

if((LPC_I2C->STAT & I2C_STAT_MSTSTATE) != I2C_STAT_MSTST_IDLE);

LPC_I2C->MSTDAT = (Addr<<1)|1; // address and 0 for RWn bit

LPC_I2C->MSTCTL = I2C_MSTCTL_MSTSTART; // send start

while(!(LPC_I2C->STAT & I2C_STAT_MSTPENDING));

if((LPC_I2C->STAT & I2C_STAT_MSTSTATE) != I2C_STAT_MSTST_RX);

 

}

 

void I2C_Multiple_Write(uint8_t Addr,uint8_t WriteByte,uint8_t *i2c_data){

//LPC_I2C->CFG = I2C_CFG_MSTEN; //マスターモード

I2C_Addr_WSend(Addr);

for (int i = 1; i < WriteByte; ++i){

while(!(LPC_I2C->STAT & I2C_STAT_MSTPENDING));

if((LPC_I2C->STAT & I2C_STAT_MSTSTATE) != I2C_STAT_MSTST_IDLE);//

LPC_I2C->MSTDAT = *(i2c_data+i); // send data

wait_ms(100); //wait

while(!(LPC_I2C->STAT & I2C_STAT_MSTPENDING));

LPC_I2C->MSTCTL = I2C_MSTCTL_MSTCONTINUE; // continue transaction

while(!(LPC_I2C->STAT & I2C_STAT_MSTPENDING));

if((LPC_I2C->STAT & I2C_STAT_MSTSTATE) != I2C_STAT_MSTST_TX); //break(); //abort();

while(!(LPC_I2C->STAT & I2C_STAT_MSTPENDING));

if((LPC_I2C->STAT & I2C_STAT_MSTSTATE) != I2C_STAT_MSTST_IDLE); //break();*/

 

}

LPC_I2C->MSTCTL = I2C_MSTCTL_MSTSTOP; //

while(!(LPC_I2C->STAT & I2C_STAT_MSTPENDING));

//if((LPC_I2C->STAT & I2C_STAT_MSTSTATE) != I2C_STAT_MSTST_IDLE);

}

 

 

//温度センサからの温度データ読みだし

uint16_t ReadTemperture_LM75A(uint8_t Addr){ //

 

uint8_t Readdata_MSB;

uint8_t Readdata_LSB;

uint16_t Readdata;

//I2C_Addr_RSend(Addr); //read

I2C_Addr_WSend(Addr); //write

 

LPC_I2C->MSTDAT = LM75TempRegi_pointer;

//LPC_I2C->MSTCTL = I2C_MSTCTL_MSTSTART; //RE-START

LPC_I2C->MSTCTL = I2C_MSTCTL_MSTCONTINUE; //

while(!(LPC_I2C->STAT & I2C_STAT_MSTPENDING));

if((LPC_I2C->STAT & I2C_STAT_MSTSTATE) != I2C_STAT_MSTST_TX);

LPC_I2C->MSTDAT = (Addr<<1)|1; //読みだし

LPC_I2C->MSTCTL = I2C_MSTCTL_MSTSTART; //RE=START

while(!(LPC_I2C->STAT & I2C_STAT_MSTPENDING));

Readdata_MSB=LPC_I2C->MSTDAT;

LPC_I2C->MSTCTL = I2C_MSTCTL_MSTCONTINUE;

while(!(LPC_I2C->STAT & I2C_STAT_MSTPENDING));

Readdata_LSB=LPC_I2C->MSTDAT;

 

while(!(LPC_I2C->STAT & I2C_STAT_MSTPENDING));

if((LPC_I2C->STAT & I2C_STAT_MSTSTATE) != I2C_STAT_MSTST_RX);

 

while(!(LPC_I2C->STAT & I2C_STAT_MSTPENDING));

LPC_I2C->MSTCTL = I2C_MSTCTL_MSTSTOP; // send stop NACKのスレーブへの送信

while(!(LPC_I2C->STAT & I2C_STAT_MSTPENDING));

if((LPC_I2C->STAT & I2C_STAT_MSTSTATE) != I2C_STAT_MSTST_IDLE) ;

 

 

Readdata=Readdata_MSB<<8|Readdata_LSB;

return Readdata;

}

 

void SwitchMatrix_Init()

{

/* Enable SWM clock */

LPC_SYSCON->SYSAHBCLKCTRL |= (1<<7|1<<5); //Enable SWM Clock,I2C Clock

 

LPC_SWM->PINASSIGN7 = 0x00ffffffUL; //SDA

/* I2C0_SCL */

LPC_SWM->PINASSIGN8 = 0xffffff04UL; //SCL

 

 

LPC_SWM->PINENABLE0 = 0xffffffb3UL;

 

LPC_SYSCON->SYSAHBCLKCTRL |= (1<<18); //Enables clock for IOCON block.

 

}

 

void IOCON_Init() {

 

/* Enable UART clock */

LPC_SYSCON->SYSAHBCLKCTRL |= (1<<18);

 

}

 

void Systick_Init(){

 

SysTick->CTRL=0; //Systick_Countter stop

SysTick->LOAD=12000; //1ms

SysTick->VAL=0; //

SysTick->CTRL=0x07; //Systick 

}

 

void mon_CFG(){

 

uint32_t mondata;

mondata=LPC_I2C->MONRXDAT;

}

 

 

 

0 项奖励
回复
3 回复数

52 次查看
LPC81x1114
Contributor I

Habib_MS,

Thank you for your message.
I wrote a program using Chapter 29.2 “Code Example I2C” as a reference, but it isn't working properly.
Currently, I cannot visualize how the LPC810 operates when controlling as a master using hardware I2C.
I believe the code example lists three constants to set in LPC_I2C->MSTCTL: I2C_MSTCTL_MSTSTART, I2C_MSTCTL_MSTCONTINUE, and I2C_MSTCTL_MSTSTOP.
I2C_MSTCTL_MSTSTART handles the start condition and restart condition, and also...
I2C_MSTCTL_MSTSTOP is for the stop condition,
but could you please explain how I2C_MSTCTL_MSTCONTINUE behaves in both master transmit mode and master receive mode?

Translated with DeepL.com (free version)

0 项奖励
回复

32 次查看
Habib_MS
NXP Employee
NXP Employee

Hello @LPC81x1114,
Of course.
The macro I2C_MSTCTL_MSTCONTINUE is defined with a value of 1, as shown in Chapter 29.2.1 "Definitions". It is used in the MSTCTL register, which writes a 1 to the MSTCONTINUE bit. This bit performs the following function:

Habib_MS_0-1759962768950.png

In simplified terms, this bit tells the LPC controller that it can proceed with the next operation in the I2C protocol. For example, if a transmission has already started and an ACK has been received, the next step might be to send a data byte to the slave. This is when the MSTCONTINUE bit is activated.
That is why, in the example "Master writes one byte to slave", the bit is set after receiving an ACK and before sending the data byte.

Habib_MS_1-1759962808651.png

BR
Habib

0 项奖励
回复

73 次查看
Habib_MS
NXP Employee
NXP Employee

Hello @LPC81x1114,

I highly recommend reviewing Section 7.10: "Protocols for Writing and Reading the Registers" in the LM75A datasheet. This section explains how the I2C communication frames should be structured to perform various actions with the sensor. For example, it includes the frame format required to write to the configuration register:

Habib_MS_1-1759787216901.png

Additionally, there are other useful frame formats mentioned that can help you better understand the communication process. This section also highlights key aspects of I2C communication.
I also suggest checking out Section 7.3: "Slave Address", which explains how to configure the sensor's slave address.
On another note, the RM provides several example codes that directly access I2C registers without using the ROM API. These examples can serve as a helpful reference and are located in the chapter 29.2 called "Code Examples I2C".
Hope this helps.
BR
Habib

0 项奖励
回复