I'm free

[DSP6K] I2C 통신 (TMS320C6747 to LCD) 본문

Firmware/other

[DSP6K] I2C 통신 (TMS320C6747 to LCD)

freerevival 2019. 9. 9. 13:55

급하게 DSP에 I2C통신으로 LCD(1.5inch OLED Module)를

제어해야 할 일이 생겨서 자료를 남기기 위해 작성

운영체제 : Windows 10 pro x64 

프로그램 :

 - uVision5(MDK-ARM 5.27)C6000 Code Generation Tools 7.4.23

 - AISgen for D800K005

제어장치 :

 - TMS320C6747

 - 1.5inch OLED Module

직접 해보면서 글을 쓰는 것이기 때문에 틀린 부분이 있을 수 있습니다.

잘못된 점은 언제든 삭제되거나 수정될 수 있습니다.

 


제품 정보

 

1) TMS320C6747

http://www.ti.com/product/TMS320C6747

불러오는 중입니다...

 

2) 1.5inch OLED Module

https://www.waveshare.com/wiki/1.5inch_OLED_Module

 

1.5inch OLED Module - Waveshare Wiki

Introduction 1.54inch OLED, SPI/I2C interfaces, 16-bit grey level Resources 3D Drawing FAQ Support Contact your seller (fast response and most recommended) or send emails to [email protected] (not fast enough but please be patient) for help. Our working ti

www.waveshare.com


하드웨어 연결 상태.

DSP의 핀 연결

 - SPI1_SIMO[0]/I2C1_SDA/GP5[6]/BOOT[6]

 - SPI1_SOMI[0]/I2C1_SCL/GP5[5]/BOOT[5]

 

LCD의 핀 연결

 - DIN(SDA)

 - CLK(SCL)

 - BS 1pin 

 (구매 당시 BS-0번 0옴으로 연결됨 -> 제거 후 BS-1번 0옴으로 연결)

 


세팅

(다른 하드웨어 세팅도 들어가 있음. 데이터 시트 확인 필수)

//i2C1 Output (bit21, bit22)

*( volatile unsigned int* ) 0x01E26064 = 0x0000ffff;

 

//PINMUX8 (0-3,4-7)

*(unsigned int*) 0x01C14140  = 0x28888022;  // UART2, McASP1, I2C0, I2C1

 

#define LCD_ON 0xAF
#define LCD_OFF 0xAE
#define LCD_REMAP 0xA0

//0 1 1 1 1 0 D(1)/C(0) R(1)/W(0)
#define LCD_ADDR_data (0x3E)
#define LCD_ADDR_comm (0x3C)


volatile long lcdWaitCnt = 0;
void f_lcdDelay(int n){
	long i;

	for (i = 0; i<n*2200; i++) lcdWaitCnt++;// 1cnt 0.022us.. 5500cnt 120us..

	//100kHz 10us 1bit
	//data 8bit + startbit +ackbit = 10bit : 100us
	// data sand delay
	//5300 x
	//5400 o
}

/*
#define I2C1_BASE                0x01E28000
#define I2C1_ICOAR               *( volatile Uint32* )( I2C1_BASE + 0x00 )
#define I2C1_ICIMR               *( volatile Uint32* )( I2C1_BASE + 0x04 )
#define I2C1_ICSTR               *( volatile Uint32* )( I2C1_BASE + 0x08 )
#define I2C1_ICCLKL              *( volatile Uint32* )( I2C1_BASE + 0x0C )
#define I2C1_ICCLKH              *( volatile Uint32* )( I2C1_BASE + 0x10 )
#define I2C1_ICCNT               *( volatile Uint32* )( I2C1_BASE + 0x14 )
#define I2C1_ICDRR               *( volatile Uint32* )( I2C1_BASE + 0x18 )
#define I2C1_ICSAR               *( volatile Uint32* )( I2C1_BASE + 0x1C )
#define I2C1_ICDXR               *( volatile Uint32* )( I2C1_BASE + 0x20 )
#define I2C1_ICMDR               *( volatile Uint32* )( I2C1_BASE + 0x24 )
#define I2C1_ICIVR               *( volatile Uint32* )( I2C1_BASE + 0x28 )
#define I2C1_ICEMDR              *( volatile Uint32* )( I2C1_BASE + 0x2C )
#define I2C1_ICPSC               *( volatile Uint32* )( I2C1_BASE + 0x30 )
#define I2C1_ICPID1              *( volatile Uint32* )( I2C1_BASE + 0x34 )
#define I2C1_ICPID2              *( volatile Uint32* )( I2C1_BASE + 0x38 )
#define I2C1_ICPFUNC             *( volatile Uint32* )( I2C1_BASE + 0x48 )
#define I2C1_ICPDIR              *( volatile Uint32* )( I2C1_BASE + 0x4C )
#define I2C1_ICPDIN              *( volatile Uint32* )( I2C1_BASE + 0x50 )
#define I2C1_ICPDOUT             *( volatile Uint32* )( I2C1_BASE + 0x54 )
#define I2C1_ICPDSET             *( volatile Uint32* )( I2C1_BASE + 0x58 )
#define I2C1_ICPDCLR             *( volatile Uint32* )( I2C1_BASE + 0x5C )
*/
 
void f_lcdI2C_init() {
	//1// I2C 클럭 활성 //-//

	//2// I2C 재설정 //-//
	I2C1_ICMDR &= 0xFFDF; //IRS(5)=0

	//3//ICMDR 구성 설정 //-//
	//마스터 구성
	I2C1_ICMDR |= 0x0400; //MST(10)=1
	//I2C 송신모드
	I2C1_ICMDR |= 0x0200; //TRX(9)=1
	//7비트 주소설정
	I2C1_ICMDR &= 0xFEFF; //XA(8)=0
	//반복모드 
	I2C1_ICMDR &= 0xFF7F; //RM(7)=0
	//루프백모드 비활성화
	I2C1_ICMDR &= 0xFFBF; //DLM(6)=0
	//데이터형식 비활성화 ????//free data mode //lcd보드쪽이지원안하는듯?
	I2C1_ICMDR &= 0xFFF7; //FDF(3)=0
	//옵션:시작바이트비활성
	//I2C1_ICMDR &= 0xFFEF; //STB(4)=0
	//전송비트수설정//0:8bit 1:1bit~7:7bit
	I2C1_ICMDR &= 0xFFF8; //BC(0-2)=0
	//-//-//-//

	//4// 슬레이브 주소구성 //-//
	//슬레이브주소 7bit
	I2C1_ICSAR = LCD_ADDR_comm & 0xFF;

	//5// 클럭주파수 설정 //-//
	//Prescaler frequency 6.7MHz~13.3MHz
	//I2C clock frequency = I2C input clock frequency/(IPSC + 1)
	//30MHz/(0x02+1) = 10MHz /0x03:7.5MHz/0x04:6MHz
	//계산상 0x03인데 오실로로 찍어보면 0x0A(최종 출력 클럭 100kHz 기준)
	I2C1_ICPSC = 0x0A;

	//6// 마스터 클럭주파수 설정 //-//
	//I2C serial clock frequency = prescaled module clock frequency/((ICCL + d) + (ICCH + d))
	//10MHz/((45+5)+(45+5) = 100kHz
	I2C1_ICCLKL = 0x19;// 0x2D;
	I2C1_ICCLKH = 0x41;//0x2D;

	//7// 인터럽트레지스터 확인//-//
	//ICSTR 읽고 다시 쓰기
	I2C1_ICSTR = I2C1_ICSTR;
	//ICSTR 초기화는 1
	//I2C1_ICSTR=1;	//clear
	//I2C1_ICIVR이 0이될때까지 읽기
	while (I2C1_ICIVR != 0);

	//8// 컨트롤러 리셋 취소/활성화 //-//
	I2C1_ICMDR |= 0x0020; //IRS(5)=1

	//설정 끝.



}

int f_lcdI2C_Command(Uint16* data) {

	I2C1_ICMDR &= 0xF7FF; //STP(11)=0
	I2C1_ICMDR |= 0x2020; //STT(13)=1 IRS(5)=1

	//STOP 상태 확인 STP(11)==1?
//	if (I2C1_ICMDR & 0x0800) return 1;
	//9// 버스사용중비트 확인 BB(12)==1?
//	if ((I2C1_ICSTR & 0x1000)) return I2C1_ICSTR;


	/* 전송할 데이터의 Slave Address 설정 */
	/* D/C 설정 */
	*(short*)(0x62000000) = 0x00;//(D[3]:0x08) 0:high normal //(D[2]:0x04)  0:Command
	I2C1_ICSAR = LCD_ADDR_comm & 0xFF;

	I2C1_ICMDR = 0x2E20;
	f_lcdDelay(2);

	//C0 onlyData(0) nextControl(1)
	//DC C(0) D(1)-GDRAM(++)
	//C0 DC 000000
	I2C1_ICDXR = data[0];
	I2C1_ICMDR = 0x0E20;
	f_lcdDelay(2);
	I2C1_ICDXR = data[1];
	I2C1_ICMDR = 0x0E20; 
	f_lcdDelay(2);

	f_lcdDelay(1);
	I2C1_ICMDR &= 0xFFDF; //IRS(5)=0

	return 0;
}
int f_lcdI2C_Command_select(int select) {

	I2C1_ICMDR &= 0xF7FF; //STP(11)=0
	I2C1_ICMDR |= 0x2020; //STT(13)=1 IRS(5)=1

	//STOP 상태 확인 STP(11)==1?
//	if (I2C1_ICMDR & 0x0800) return 1;
	//9// 버스사용중비트 확인 BB(12)==1?
//	if ((I2C1_ICSTR & 0x1000)) return I2C1_ICSTR;


	/* 전송할 데이터의 Slave Address 설정 */
	/* D/C 설정 */
	*(short*)(0x62000000) = 0x00;//(D[3]:0x08) 0:high normal //(D[2]:0x04)  0:Command
	I2C1_ICSAR = LCD_ADDR_comm & 0xFF;

	I2C1_ICMDR = 0x2E20;
	f_lcdDelay(2);

	//C0 onlyData(0) nextControl(1)
	//DC C(0) D(1)-GDRAM(++)
	//C0 DC 000000
	I2C1_ICDXR = 0x00;
	I2C1_ICMDR = 0x0E20;
	f_lcdDelay(2);

	switch (select)
	{
	case LCD_ON:
		I2C1_ICDXR = LCD_ON;
		I2C1_ICMDR = 0x0E20;
		f_lcdDelay(2);
		break;
	case LCD_OFF:
		I2C1_ICDXR = LCD_OFF;
		I2C1_ICMDR = 0x0E20;
		f_lcdDelay(2);
		break;

	case LCD_REMAP:
		/*
		A[0] = 0b, Disable Column Address Re-map(RESET) (우좌)
		A[0] = 1b, Enable Column Address Re-map (좌우) EN
		A[1] = 0b, Disable Nibble Re-map (RESET) EN
		A[1] = 1b, Enable Nibble Re-map
		A[2] = 0b, Enable Horizontal Address Increment(RESET)(가로) EN
		A[2] = 1b, Enable Vertical Address Increment(세로)
		A[3] = 0b, Reserved (RESET)
		A[4] = 0b, Disable COM Re-map (RESET)(아래서위로)
		A[4] = 1b, Enable COM Re-map(반전)(위에서아래로) EN
		A[5] = 0b, Reserved (RESET)
		A[6] = 0b, Disable COM Split Odd Even (RESET)(홀수/짝수)
		A[6] = 1b, Enable COM Split Odd Even(순서대로) EN
		A[7] = 0b, Reserved (RESET)
		*/
		I2C1_ICDXR = LCD_REMAP;
		I2C1_ICMDR = 0x0E20;
		f_lcdDelay(2);
		I2C1_ICDXR = 0x51;// = 0x01 | 0x10 | 0x40;
		I2C1_ICMDR = 0x0E20;
		f_lcdDelay(2);
		break;
	default:
		break;
	}

	f_lcdDelay(1);
	I2C1_ICMDR &= 0xFFDF; //IRS(5)=0

	return 0;
}
int f_lcdI2C_Data(Uint16 numOfByte, Uint16* data) {
	int i;

	I2C1_ICMDR &= 0xF7FF; //STP(11)=0
	I2C1_ICMDR |= 0x2020; //STT(13)=1 IRS(5)=1

	//STOP 상태 확인 STP(11)==1?
//	if (I2C1_ICMDR & 0x0800) return 1;
	//9// 버스사용중비트 확인 BB(12)==1?
//	if ((I2C1_ICSTR & 0x1000)) return I2C1_ICSTR;


	/* 전송할 데이터의 Slave Address 설정 */
	/* D/C 설정 */
//	*(short*)(0x62000000) = 0x02;//(D[3]:0x08) 0:high normal //(D[2]:0x04)  1:Data
//	I2C1_ICSAR = LCD_ADDR_data & 0xFF;
	*(short*)(0x62000000) = 0x00;//(D[3]:0x08) 0:high normal //(D[2]:0x04)  0:Command
	I2C1_ICSAR = LCD_ADDR_comm & 0xFF;

	I2C1_ICMDR = 0x2E20;
	f_lcdDelay(2);

	//C0 onlyData(0) nextControl(1)
	//DC C(0) D(1)-GDRAM(++)
	//C0 DC 00 0000
	I2C1_ICDXR = 0x40;
	I2C1_ICMDR = 0x2E20;
	f_lcdDelay(2);

	//I2C1_ICCNT = numOfByte & 0xFF;
	//lcdDelay(2);
	for (i = 0; i < numOfByte; i+=2) {
		I2C1_ICDXR = (Uint8)((((data[i] << 4) & 0xF0) | (data[i+1] & 0x0F))&0xFF);
		I2C1_ICMDR = 0x2E20;
		f_lcdDelay(2);
	}

	f_lcdDelay(1);
	I2C1_ICMDR &= 0xFFDF; //IRS(5)=0

	return 0;
}

 

문제점

아래 사진은 LCD ON 명령을  I2C로 보내는 것을 Oscilloscope로 측정한 것이다.

DataSheet에 나와있는 대로 신호가 잘 가다가 마지막 Stop bit 처리하는 부분에서 DataSheet와 상이하게 동작한다. 이는 DSP쪽 코드 문제로 보이며 그냥 진행하면 한 번만 보내고 Stop 이벤트를 인식하지 못해 이후 출력을 새로 보내지 않고 Data정보만 보내는 문제가 있다,

이를 해결하지 못했다.(누군가 알려주었으면 좋겠지만)

그래서 위 코드상에 보면 인터럽트를 강제 리셋시키고 다시 시작하는 방식으로 구현되어있다.

(내가 생각해도 정상적인 방법은 아니지만 동작은 잘되니...)

 


코드 적용

 

- 이전에 만들어둔 이미지를 HAX 변환하여 만든 이미지 배열을 적용

[Labview] Image to RGB(hax) ver.10

 

[Labview] Image to RGB(hax) ver.10

+. 용도. 펌웨어 개발시 Display 화면에 사용할 이미지를 코드화 변환용. 1. 이미지 파일 추가 -> BMP(24bit), JPG(JPEG), PNG 지원 2. 출력데이터. -> 폴더생성 : out_txt_bmp -> Color data : image(Color).txt..

freerevival.tistory.com

 

LCD가 4bit 방식이라 변환작업을 코드상에서 구현.

(변환 프로그램에서 4bit도 추가하면 좋겠지만, 귀찮으니 나중에 하는 걸로...)

 

#define Uint16  unsigned short
//LCD
#define XByte 128 //1 BYTE = 2dot,X max Dot = 128
#define YByte 128 //1 Byte = 1Dot,y max Dot = 128 
#define OLED_BUFSIZ XByte * YByte
extern Uint16 f_lcdBuffer[OLED_BUFSIZ];


int imageToColor[16384] = {
0x434343,0x696969,0x797979, //변환 HAX코드 적용(생략)
};


void main(void) {
	int k;
	j = 0;
	//임시 테스트용 
	//다른방식 사용 필요.
	for (k = 0; k < OLED_BUFSIZ; k++) {
		j = (imageToColor[k] & 0xFF)
			+ ((imageToColor[k] >> 8) & 0xFF)
			+ ((imageToColor[k] >> 16) & 0xFF);
		j /= 3;

		f_lcdBuffer[k] = (j >>4)&0x0F;

	}
    
	f_lcdI2C_init();
    
	//LCD 초기 설정-- LCD속도 설정 필요
	fftestff = f_lcdI2C_Command_select(LCD_REMAP);
	fftestff = f_lcdI2C_Command_select(LCD_ON);
	fftestff = f_lcdI2C_Data(OLED_BUFSIZ, f_lcdBuffer);
    
	while (1) {
    //
    }
}
    
    

 

동작 화면

Gray 스케일 OLED라 조금 아쉽다. 

RGB(color) OLED도 조만간 구매한다니.(소스 수정해야 돼 귀찮...)

칼라로도 해보면 나름 괜찮겠다 싶다.

 

 

 

Comments