Explorar o código

I2C, LCD optimizations

kbere %!s(int64=2) %!d(string=hai) anos
pai
achega
ddd2628a78
Modificáronse 4 ficheiros con 32 adicións e 6 borrados
  1. 4 0
      soft/HD44780-I2C.c
  2. 3 0
      soft/HD44780-I2C.h
  3. 19 5
      soft/I2C.c
  4. 6 1
      soft/expander.c

+ 4 - 0
soft/HD44780-I2C.c

@@ -57,7 +57,9 @@ void LCD_WriteCommand(unsigned char commandToWrite)
 {
 	expander_set_bit(LCD_RS_PORT, LCD_RS, 0);
 	_LCD_Write(commandToWrite);
+#ifdef LCD_WAIT_FOR_READY
 	while(LCD_ReadStatus()&0x80);
+#endif
 }
 
 //-------------------------------------------------------------------------------------------------
@@ -79,7 +81,9 @@ void LCD_WriteData(unsigned char dataToWrite)
 {
 	expander_set_bit(LCD_RS_PORT, LCD_RS, 1);
 	_LCD_Write(dataToWrite);
+#ifdef LCD_WAIT_FOR_READY
 	while(LCD_ReadStatus()&0x80);
+#endif
 }
 //-------------------------------------------------------------------------------------------------
 //

+ 3 - 0
soft/HD44780-I2C.h

@@ -34,6 +34,9 @@
 #define LCD_DATA_OUTPUT() 	expander_set_dir(0, 0x00, 0x00)
 #define LCD_DATA_INPUT() 	expander_set_dir(0, 0xFF, 0x00)
 
+
+#undef LCD_WAIT_FOR_READY /* typically not needed, I2C bus is slow enough */
+
 //-------------------------------------------------------------------------------------------------
 //
 // Instrukcje kontrolera Hitachi HD44780

+ 19 - 5
soft/I2C.c

@@ -9,9 +9,23 @@
 #include "I2C.h"
 #include "main.h"
 
+#define I2C_FREQ	400000
+
+#define	PRESCALER	1 /* possible values: 1, 4, 16, 64 */
+
 void I2C_init(void){
-	TWBR = 18;
+	TWBR = (F_CPU/I2C_FREQ - 16.0)/2.0/PRESCALER;
+#if PRESCALER == 1
 	TWSR |= 0;
+#elif	PRESCALER == 4
+	TWSR |= _BV(TWPS0);
+#elif PRESCALER == 16
+	TWSR |= _BV(TWPS1);
+#elif PRESCALER == 64
+	TWSR |= _BV(TWPS1) | _BV(TWPS0);
+#else
+#error Invalid prescaler
+#endif
 }
 
 /* two byte command (or command + value) */
@@ -141,7 +155,7 @@ unsigned int I2C_Receive_n_bytes(unsigned char address, unsigned char command, u
 unsigned int I2C_ReceiveCommand3byte(unsigned char address, unsigned char command, unsigned char *data0, unsigned char *data1)
 {
 	unsigned int error = ERROR_I2C;
-	unsigned char addressTrash;
+	unsigned char _unused;
 	for(int index = 0 ; (index < MAX_REPEAT_I2C) && (error != ERROR_NO); index++)
 	{
 		error = 0;
@@ -155,7 +169,7 @@ unsigned int I2C_ReceiveCommand3byte(unsigned char address, unsigned char comman
 		TWCR = (1<<TWINT) | (1<<TWSTA) | (1<<TWEN);
 		error |= I2C_WaitForTWInt();
 
-		error |= I2C_ReceiveOneCommandByte(&addressTrash, 0);
+		error |= I2C_ReceiveOneCommandByte(&_unused, 0);
 		error |= I2C_ReceiveOneCommandByte(data0, 0);
 		error |= I2C_ReceiveOneCommandByte(data1, 0);
 		
@@ -181,10 +195,10 @@ unsigned int I2C_ReceiveOneCommandByte(unsigned char *command, unsigned char ack
 }
 
 unsigned int I2C_WaitForTWInt(void){
-	unsigned char count = 20;
+	unsigned char count = 10;
 	while (count && !(TWCR & (1<<TWINT))){
 		count--;
-		_delay_us(6);
+		_delay_us(1000000.0/I2C_FREQ*10); /* wait for 10 bit periods; the transaction never succeeds quicker */
 	}
 	if(count == 0) return ERROR_I2C_TIMEOUT;
 

+ 6 - 1
soft/expander.c

@@ -12,15 +12,20 @@
 #include <avr/io.h>
 
 unsigned char exp_output[EXPANDER_COUNT*2];
+unsigned char directions[EXPANDER_COUNT*2];
 
 void expander_init(unsigned char addr, unsigned char p1in, unsigned char p2in){
 	addr += EXPANDER_ADDR;
 	expander_write_all();
-	expander_set_dir(addr, p1in, p2in);
+	System.global_error |= I2C_SendCommand3byte(addr, CMD_PORT0_CONFIG, p1in, p2in);
 }
 
 void expander_set_dir(unsigned char addr, unsigned char p1in, unsigned char p2in){
+	if(p1in == directions[addr*2] && p2in == directions[addr*2 + 1])
+			return; /* no change needed, save one transaction */
 	System.global_error |= I2C_SendCommand3byte(addr, CMD_PORT0_CONFIG, p1in, p2in);
+	directions[addr*2] = p1in;
+	directions[addr*2 + 1] = p2in;
 }
 
 unsigned int expander_read(unsigned char addr){