reading EDID information from display and submission to host works
This commit is contained in:
		| @@ -87,6 +87,7 @@ | ||||
|  *        multiple of 1000000UL (1 MHz). | ||||
|  */ | ||||
| #define delay_us( us )   ( __delay_cycles( ( F_CPU / 1000000UL ) * ( us ) ) ) | ||||
| #define delay_ms( ms )   ( __delay_cycles( ( F_CPU / 100000000000L ) * ( ms ) ) ) | ||||
|  | ||||
| /*! \brief Preprocessor magic. | ||||
|  * | ||||
| @@ -133,6 +134,7 @@ | ||||
|  | ||||
| /*! \brief Define the delay_us macro for GCC. */ | ||||
| #define delay_us( us )   (_delay_us( us )) | ||||
| #define delay_ms( ms )   (_delay_ms( ms )) | ||||
|  | ||||
| #define INLINE static inline | ||||
|  | ||||
|   | ||||
							
								
								
									
										138
									
								
								edid_injector.c
									
									
									
									
									
								
							
							
						
						
									
										138
									
								
								edid_injector.c
									
									
									
									
									
								
							| @@ -44,7 +44,7 @@ | ||||
| #define BAUDRATE	100000 | ||||
| #define TWI_BAUDSETTING TWI_BAUD(F_CPU, BAUDRATE) | ||||
|  | ||||
| #define EDID_SLAVE_ADDRESS 0xA0 | ||||
| #define EDID_SLAVE_ADDRESS 0x50 | ||||
|  | ||||
| /* TWIC is on the display side */ | ||||
| TWI_t * const twiDisplay = &TWIC; | ||||
| @@ -65,23 +65,39 @@ ISR(TWIE_TWIS_vect) | ||||
| 	TWI_SlaveInterruptHandler(&twisHost); | ||||
| } | ||||
|  | ||||
| #define EDID_BLOCK_LENGTH 128 | ||||
|  | ||||
| void TWIC_SlaveProcessData(void) | ||||
| static uint8_t edid_data[EDID_BLOCK_LENGTH]; | ||||
| static uint8_t edid_offset; | ||||
| static uint8_t recvbuf[1]; | ||||
|  | ||||
| void TWIC_SlaveProcessData(TWI_Slave_t * const twi) | ||||
| { | ||||
| 	if( twi->bytesReceived ) { | ||||
| 		edid_offset = twi->recvData[0]; | ||||
| 	} | ||||
| 	twi->sendData = edid_data + edid_offset; | ||||
| 	twi->bytesToSend = sizeof(edid_data) - edid_offset; | ||||
| } | ||||
|  | ||||
| void edid_initHostTWI(void) | ||||
| { | ||||
| 	/* Initialize TWI slave. */ | ||||
| 	TWI_SlaveInitializeDriver(&twisHost, twiHost, TWIC_SlaveProcessData); | ||||
| 	TWI_SlaveInitializeDriver(&twisHost, | ||||
| 		twiHost, | ||||
| 		TWIC_SlaveProcessData); | ||||
|  | ||||
| 	TWI_SlaveInitializeModule(&twisHost, | ||||
| 		EDID_SLAVE_ADDRESS, | ||||
| 		TWI_SLAVE_INTLVL_MED_gc ); | ||||
| 		TWI_SLAVE_INTLVL_HI_gc, | ||||
| 		recvbuf, | ||||
| 		sizeof(recvbuf) ); | ||||
| } | ||||
|  | ||||
| void edid_initDisplayTWI(void) | ||||
| { | ||||
| 	/* Initialize TWI master. */ | ||||
| 	twimDisplay.status = TWIM_STATUS_READY; | ||||
| 	TWI_MasterInit(&twimDisplay, | ||||
| 	               twiDisplay, | ||||
| 	               TWI_MASTER_INTLVL_LO_gc, | ||||
| @@ -99,52 +115,128 @@ void edid_initDisplayTWI(void) | ||||
|  | ||||
| } | ||||
|  | ||||
| uint8_t edid_checkData(uint8_t const *ediddata) | ||||
| { | ||||
| 	uint8_t checksum = 0; | ||||
| 	for(uint8_t i = 0; i < EDID_BLOCK_LENGTH; i++) { | ||||
| 		checksum += ediddata[i]; | ||||
| 	} | ||||
| 	if( 0 != checksum ) { | ||||
| 		return 1; /* checksum failed */ | ||||
| 	} | ||||
|  | ||||
| 	if( 0 != ediddata[0] ) { | ||||
| 		return 2; /* headerbyte[0] != 0 */ | ||||
| 	} | ||||
|  | ||||
| 	for(uint8_t i = 1; i < 7; i++) { | ||||
| 		if( 0xff != ediddata[i] ) { | ||||
| 			return 3; /* headerbyte[1..6] != 0xff */ | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	if( 0 != ediddata[7] ) { | ||||
| 		return 4; /* headerbyte[7] != 0 */ | ||||
| 	} | ||||
|  | ||||
| 	return 0; /* EDID data passed checks */ | ||||
| } | ||||
|  | ||||
| uint8_t edid_genChecksum(uint8_t *ediddata) | ||||
| { | ||||
| 	uint8_t bytessum = 0; | ||||
| 	for(size_t i = 0; i < 127; i++) { | ||||
| 	for(uint8_t i = 0; i < EDID_BLOCK_LENGTH-1; i++) { | ||||
| 		bytessum += ediddata[i]; | ||||
| 	} | ||||
|  | ||||
| 	return 0xff - bytessum; | ||||
| 	return 0xff - bytessum + 1; | ||||
| } | ||||
|  | ||||
| void edid_readFromDisplayToEEPROM(void) | ||||
| uint8_t edid_readFromDisplayToEEPROM(void) | ||||
| { | ||||
| 	uint8_t displayedid[128]; | ||||
| 	memset(displayedid, 0, sizeof(displayedid)); | ||||
| 	uint8_t const offset[1] = {0x00}; | ||||
| 	uint8_t displayedid[EDID_BLOCK_LENGTH]; | ||||
|  | ||||
| 	/* read 128 EDID bytes from display */ | ||||
| 	uint8_t error = 0; | ||||
| 	uint8_t retry = 20; | ||||
| 	while( retry-- ) { | ||||
| 		TWI_MasterForceIdle(&twimDisplay); | ||||
| 		delay_ms(1); | ||||
|  | ||||
| 		/* set EDID offset to 0 */ | ||||
| 		if( !TWI_MasterWriteRead(&twimDisplay, | ||||
| 			EDID_SLAVE_ADDRESS, | ||||
| 			offset, | ||||
| 			sizeof(offset), | ||||
| 			displayedid, | ||||
| 			sizeof(displayedid) ) ) { | ||||
| 			PORTB.OUTCLR = (1<<3); | ||||
| 			PORTB.OUTSET = (1<<3); | ||||
| 		}; | ||||
|  | ||||
| 		while( !TWI_MasterReady(&twimDisplay) ) { | ||||
| 			delay_ms(1); | ||||
| 		} | ||||
| 		delay_ms(1); | ||||
|  | ||||
| 		if( twimDisplay.result != TWIM_RESULT_OK ) { | ||||
| 			error = 1; | ||||
| 			continue; | ||||
| 		} | ||||
|  | ||||
| 		if( edid_checkData(displayedid) ) { | ||||
| 			error = 2; | ||||
| 			continue; | ||||
| 		} | ||||
|  | ||||
| 		break; | ||||
| 	} | ||||
| 	if( !retry ) { | ||||
| 		return error; | ||||
| 	} | ||||
|  | ||||
| 	/* set EDID Extension Block count / flags to zero */ | ||||
| 	displayedid[126] = 0; | ||||
|  | ||||
| 	/* recalculate checksum */ | ||||
| 	displayedid[127] = edid_genChecksum(displayedid); | ||||
|  | ||||
| 	/* write EDID information to EEPROM */ | ||||
| 	memcpy(edid_data, displayedid, EDID_BLOCK_LENGTH); | ||||
|  | ||||
| 	return 0; | ||||
| } | ||||
|  | ||||
| int main(void) | ||||
| { | ||||
| 	edid_initHostTWI(); | ||||
| 	memset(edid_data, 0, sizeof(edid_data)); | ||||
|  | ||||
| 	PORTB.DIR = (1<<3); | ||||
| 	PORTE.DIR = (1<<2) | (1<<3); | ||||
|  | ||||
| 	edid_initHostTWI(); | ||||
| 	edid_initDisplayTWI(); | ||||
|  | ||||
|  | ||||
| 	/* Enable LO interrupt level. */ | ||||
| 	PMIC.CTRL |= | ||||
| 		  PMIC_LOLVLEN_bm | ||||
| 		| PMIC_MEDLVLEN_bm | ||||
| 		| PMIC_HILVLEN_bm; | ||||
| 	sei(); | ||||
|  | ||||
| 	delay_ms(20);  | ||||
|  | ||||
| 	#if 0 | ||||
| 		TWI_MasterWriteRead(&twiMaster, | ||||
| 		                    SLAVE_ADDRESS, | ||||
| 		                    &sendBuffer[BufPos], | ||||
| 		                    1, | ||||
| 		                    1); | ||||
|  | ||||
|  | ||||
| 		while (twiMaster.status != TWIM_STATUS_READY) { | ||||
| 			/* Wait until transaction is complete. */ | ||||
| 		} | ||||
| 	#if 1 | ||||
| 	/* EDID standard requires a host to wait for 20ms after switching +5V | ||||
| 	 * supply to display before performing the first readout attempt. | ||||
| 	 * Since uC supply == display +5V supply we're waiting 20ms here. | ||||
| 	 */ | ||||
| 	for(;;) { | ||||
| 		edid_readFromDisplayToEEPROM(); | ||||
| 		delay_ms(1000);  | ||||
| 	} | ||||
| 	#endif | ||||
|  | ||||
| 	return 0; | ||||
| } | ||||
|  | ||||
|   | ||||
| @@ -68,6 +68,10 @@ | ||||
|  | ||||
| #include "twi_master_driver.h" | ||||
|  | ||||
| static void TWI_MasterWriteHandler(TWI_Master_t *twi); | ||||
| static void TWI_MasterReadHandler(TWI_Master_t *twi); | ||||
| static void TWI_MasterTransactionFinished(TWI_Master_t *twi, uint8_t result); | ||||
| static void TWI_MasterArbitrationLostBusErrorHandler(TWI_Master_t *twi); | ||||
|  | ||||
| /*! \brief Initialize the TWI module. | ||||
|  * | ||||
| @@ -86,14 +90,28 @@ void TWI_MasterInit(TWI_Master_t *twi, | ||||
|                     uint8_t baudRateRegisterSetting) | ||||
| { | ||||
| 	twi->interface = module; | ||||
| 	twi->interface->CTRL = TWI_SDAHOLD_bm; | ||||
| 	twi->interface->MASTER.CTRLA = intLevel | | ||||
| 	                               TWI_MASTER_RIEN_bm | | ||||
| 	                               TWI_MASTER_WIEN_bm | | ||||
| 	                               TWI_MASTER_ENABLE_bm; | ||||
|  | ||||
| 	#if 1 | ||||
| 	twi->interface->MASTER.CTRLB = | ||||
| 		TWI_MASTER_TIMEOUT_200US_gc; | ||||
| 	#endif | ||||
|  | ||||
| 	twi->interface->MASTER.BAUD = baudRateRegisterSetting; | ||||
| 	twi->interface->MASTER.STATUS = TWI_MASTER_BUSSTATE_IDLE_gc; | ||||
|  | ||||
| 	twi->status = TWIM_STATUS_READY; | ||||
| } | ||||
|  | ||||
| void TWI_MasterForceIdle(TWI_Master_t *twi) | ||||
| { | ||||
| 	twi->interface->MASTER.STATUS = TWI_MASTER_BUSSTATE_IDLE_gc; | ||||
| 	twi->status = TWIM_STATUS_READY; | ||||
| } | ||||
|  | ||||
| /*! \brief Returns the TWI bus state. | ||||
|  * | ||||
| @@ -128,7 +146,7 @@ TWI_MASTER_BUSSTATE_t TWI_MasterState(TWI_Master_t *twi) | ||||
|  */ | ||||
| bool TWI_MasterReady(TWI_Master_t *twi) | ||||
| { | ||||
| 	bool twi_status = (twi->status & TWIM_STATUS_READY); | ||||
| 	bool twi_status = (twi->status == TWIM_STATUS_READY); | ||||
| 	return twi_status; | ||||
| } | ||||
|  | ||||
| @@ -147,10 +165,14 @@ bool TWI_MasterReady(TWI_Master_t *twi) | ||||
|  */ | ||||
| bool TWI_MasterWrite(TWI_Master_t *twi, | ||||
|                      uint8_t address, | ||||
|                      uint8_t *writeData, | ||||
|                      uint8_t const *writeData, | ||||
|                      uint8_t bytesToWrite) | ||||
| { | ||||
| 	bool twi_status = TWI_MasterWriteRead(twi, address, writeData, bytesToWrite, 0); | ||||
| 	bool twi_status = TWI_MasterWriteRead(twi, | ||||
| 		address, | ||||
| 		writeData, bytesToWrite, | ||||
| 		NULL, 0); | ||||
|  | ||||
| 	return twi_status; | ||||
| } | ||||
|  | ||||
| @@ -168,9 +190,14 @@ bool TWI_MasterWrite(TWI_Master_t *twi, | ||||
|  */ | ||||
| bool TWI_MasterRead(TWI_Master_t *twi, | ||||
|                     uint8_t address, | ||||
| 		    uint8_t *readData, | ||||
|                     uint8_t bytesToRead) | ||||
| { | ||||
| 	bool twi_status = TWI_MasterWriteRead(twi, address, 0, 0, bytesToRead); | ||||
| 	bool twi_status = TWI_MasterWriteRead(twi, | ||||
| 		address, | ||||
| 		NULL, 0, | ||||
| 		readData, bytesToRead); | ||||
|  | ||||
| 	return twi_status; | ||||
| } | ||||
|  | ||||
| @@ -192,55 +219,57 @@ bool TWI_MasterRead(TWI_Master_t *twi, | ||||
|  */ | ||||
| bool TWI_MasterWriteRead(TWI_Master_t *twi, | ||||
|                          uint8_t address, | ||||
|                          uint8_t *writeData, | ||||
|                          uint8_t const *writeData, | ||||
|                          uint8_t bytesToWrite, | ||||
| 			 uint8_t *readData, | ||||
|                          uint8_t bytesToRead) | ||||
| { | ||||
| 	/*Parameter sanity check. */ | ||||
| 	if (bytesToWrite > TWIM_WRITE_BUFFER_SIZE) { | ||||
| 		return false; | ||||
| 	if( !bytesToWrite || !writeData ) { | ||||
| 		writeData = NULL; | ||||
| 		bytesToWrite = 0; | ||||
| 	} | ||||
| 	if (bytesToRead > TWIM_READ_BUFFER_SIZE) { | ||||
| 		return false; | ||||
| 	if( !bytesToRead || !readData ) { | ||||
| 		readData = NULL; | ||||
| 		bytesToRead = 0; | ||||
| 	} | ||||
|  | ||||
| 	/*Initiate transaction if bus is ready. */ | ||||
| 	if (twi->status == TWIM_STATUS_READY) { | ||||
|  | ||||
| 		twi->status = TWIM_STATUS_BUSY; | ||||
| 		twi->result = TWIM_RESULT_UNKNOWN; | ||||
|  | ||||
| 		twi->address = address<<1; | ||||
|  | ||||
| 		/* Fill write data buffer. */ | ||||
| 		for (uint8_t bufferIndex=0; bufferIndex < bytesToWrite; bufferIndex++) { | ||||
| 			twi->writeData[bufferIndex] = writeData[bufferIndex]; | ||||
| 		} | ||||
|  | ||||
| 		twi->bytesToWrite = bytesToWrite; | ||||
| 		twi->bytesToRead = bytesToRead; | ||||
| 		twi->bytesWritten = 0; | ||||
| 		twi->bytesRead = 0; | ||||
|  | ||||
| 		/* If write command, send the START condition + Address + | ||||
| 		 * 'R/_W = 0' | ||||
| 		 */ | ||||
| 		if (twi->bytesToWrite > 0) { | ||||
| 			uint8_t writeAddress = twi->address & ~0x01; | ||||
| 			twi->interface->MASTER.ADDR = writeAddress; | ||||
| 		} | ||||
|  | ||||
| 		/* If read command, send the START condition + Address + | ||||
| 		 * 'R/_W = 1' | ||||
| 		 */ | ||||
| 		else if (twi->bytesToRead > 0) { | ||||
| 			uint8_t readAddress = twi->address | 0x01; | ||||
| 			twi->interface->MASTER.ADDR = readAddress; | ||||
| 		} | ||||
| 		return true; | ||||
| 	} else { | ||||
| 	if( twi->status != TWIM_STATUS_READY ) { | ||||
| 		return false; | ||||
| 	} | ||||
|  | ||||
| 	twi->status = TWIM_STATUS_BUSY; | ||||
| 	twi->result = TWIM_RESULT_UNKNOWN; | ||||
|  | ||||
| 	twi->address = (address << 1); | ||||
|  | ||||
| 	twi->writeData = writeData; | ||||
| 	twi->readData = readData; | ||||
| 	twi->bytesToWrite = bytesToWrite; | ||||
| 	twi->bytesToRead = bytesToRead; | ||||
| 	twi->bytesWritten = 0; | ||||
| 	twi->bytesRead = 0; | ||||
|  | ||||
| 	/* If write command, send the START condition + Address + | ||||
| 	 * 'R/_W = 0' | ||||
| 	 */ | ||||
| 	if( twi->bytesToWrite > 0 ) { | ||||
| 		uint8_t const writeAddress = twi->address & ~0x01; | ||||
| 		twi->interface->MASTER.ADDR = writeAddress; | ||||
|  | ||||
| 		uint8_t const data = twi->writeData[0]; | ||||
| 		twi->interface->MASTER.DATA = data; | ||||
| 		twi->bytesWritten++; | ||||
| 	} else | ||||
| 	/* If read command, send the START condition + Address + | ||||
| 	 * 'R/_W = 1' | ||||
| 	 */ | ||||
| 	if( twi->bytesToRead > 0 ) { | ||||
| 		uint8_t const readAddress = twi->address | 0x01; | ||||
| 		twi->interface->MASTER.ADDR = readAddress; | ||||
| 	} | ||||
| 	 | ||||
| 	return true; | ||||
| } | ||||
|  | ||||
|  | ||||
| @@ -252,28 +281,64 @@ bool TWI_MasterWriteRead(TWI_Master_t *twi, | ||||
|  */ | ||||
| void TWI_MasterInterruptHandler(TWI_Master_t *twi) | ||||
| { | ||||
| 	uint8_t currentStatus = twi->interface->MASTER.STATUS; | ||||
| #if 0 | ||||
| 	PORTB.OUTSET = (1<<3); | ||||
| 	PORTB.OUTCLR = (1<<3); | ||||
| #endif | ||||
| 	uint8_t const currentStatus = twi->interface->MASTER.STATUS; | ||||
|  | ||||
| 	/* If arbitration lost or bus error. */ | ||||
| 	if ((currentStatus & TWI_MASTER_ARBLOST_bm) || | ||||
| 	    (currentStatus & TWI_MASTER_BUSERR_bm)) { | ||||
| #if 0 | ||||
| 	PORTB.OUTSET = (1<<3); | ||||
| 	PORTB.OUTCLR = (1<<3); | ||||
| #endif | ||||
|  | ||||
| 		TWI_MasterArbitrationLostBusErrorHandler(twi); | ||||
| 	} | ||||
|  | ||||
| 		twi->interface->MASTER.STATUS = | ||||
| 			  currentStatus | ||||
| 			| TWI_MASTER_ARBLOST_bm | ||||
| 			| TWI_MASTER_BUSERR_bm; | ||||
| 	} else | ||||
| 	/* If master write interrupt. */ | ||||
| 	else if (currentStatus & TWI_MASTER_WIF_bm) { | ||||
| 	if (currentStatus & TWI_MASTER_WIF_bm) { | ||||
| #if 0 | ||||
| 	PORTB.OUTSET = (1<<3); | ||||
| 	PORTB.OUTCLR = (1<<3); | ||||
| #endif | ||||
| 		TWI_MasterWriteHandler(twi); | ||||
| 	} | ||||
|  | ||||
| 		twi->interface->MASTER.STATUS = | ||||
| 			  currentStatus | ||||
| 			| TWI_MASTER_WIF_bm; | ||||
| 	} else | ||||
| 	/* If master read interrupt. */ | ||||
| 	else if (currentStatus & TWI_MASTER_RIF_bm) { | ||||
| 	if (currentStatus & TWI_MASTER_RIF_bm) { | ||||
| #if 0 | ||||
| 	PORTB.OUTSET = (1<<3); | ||||
| 	PORTB.OUTCLR = (1<<3); | ||||
| #endif | ||||
| 		TWI_MasterReadHandler(twi); | ||||
| 	} | ||||
|  | ||||
| 		twi->interface->MASTER.STATUS = | ||||
| 			  currentStatus | ||||
| 			| TWI_MASTER_RIF_bm; | ||||
| 	} else  | ||||
| 	/* Bus went idle (timeout) */ | ||||
| 	if( (currentStatus & TWI_MASTER_BUSSTATE_IDLE_gc) | ||||
| 	    == TWI_MASTER_BUSSTATE_IDLE_gc ) { | ||||
| 		TWI_MasterTransactionFinished(twi, TWIM_RESULT_UNKNOWN); | ||||
| 	} | ||||
| 	/* If unexpected state. */ | ||||
| 	else { | ||||
| #if 0 | ||||
| 	PORTB.OUTSET = (1<<3); | ||||
| 	PORTB.OUTCLR = (1<<3); | ||||
| #endif | ||||
| 		TWI_MasterTransactionFinished(twi, TWIM_RESULT_FAIL); | ||||
|  | ||||
| 		twi->interface->MASTER.STATUS = currentStatus; | ||||
| 	} | ||||
| } | ||||
|  | ||||
| @@ -284,9 +349,9 @@ void TWI_MasterInterruptHandler(TWI_Master_t *twi) | ||||
|  * | ||||
|  *  \param twi  The TWI_Master_t struct instance. | ||||
|  */ | ||||
| void TWI_MasterArbitrationLostBusErrorHandler(TWI_Master_t *twi) | ||||
| static void TWI_MasterArbitrationLostBusErrorHandler(TWI_Master_t *twi) | ||||
| { | ||||
| 	uint8_t currentStatus = twi->interface->MASTER.STATUS; | ||||
| 	uint8_t const currentStatus = twi->interface->MASTER.STATUS; | ||||
|  | ||||
| 	/* If bus error. */ | ||||
| 	if (currentStatus & TWI_MASTER_BUSERR_bm) { | ||||
| @@ -297,9 +362,6 @@ void TWI_MasterArbitrationLostBusErrorHandler(TWI_Master_t *twi) | ||||
| 		twi->result = TWIM_RESULT_ARBITRATION_LOST; | ||||
| 	} | ||||
|  | ||||
| 	/* Clear interrupt flag. */ | ||||
| 	twi->interface->MASTER.STATUS = currentStatus | TWI_MASTER_ARBLOST_bm; | ||||
|  | ||||
| 	twi->status = TWIM_STATUS_READY; | ||||
| } | ||||
|  | ||||
| @@ -310,36 +372,49 @@ void TWI_MasterArbitrationLostBusErrorHandler(TWI_Master_t *twi) | ||||
|  * | ||||
|  *  \param twi The TWI_Master_t struct instance. | ||||
|  */ | ||||
| void TWI_MasterWriteHandler(TWI_Master_t *twi) | ||||
| static void TWI_MasterWriteHandler(TWI_Master_t *twi) | ||||
| { | ||||
| 	/* Local variables used in if tests to avoid compiler warning. */ | ||||
| 	uint8_t bytesToWrite  = twi->bytesToWrite; | ||||
| 	uint8_t bytesToRead   = twi->bytesToRead; | ||||
| 	uint8_t const bytesToWrite  = twi->bytesToWrite; | ||||
| 	uint8_t const bytesToRead   = twi->bytesToRead; | ||||
|  | ||||
| 	/* If NOT acknowledged (NACK) by slave cancel the transaction. */ | ||||
| 	if (twi->interface->MASTER.STATUS & TWI_MASTER_RXACK_bm) { | ||||
| 	if( twi->interface->MASTER.STATUS & TWI_MASTER_RXACK_bm ) { | ||||
| #if 0 | ||||
| 	PORTB.OUTSET = (1<<3); | ||||
| 	PORTB.OUTCLR = (1<<3); | ||||
| #endif | ||||
| 		twi->interface->MASTER.CTRLC = TWI_MASTER_CMD_STOP_gc; | ||||
| 		twi->result = TWIM_RESULT_NACK_RECEIVED; | ||||
| 		twi->status = TWIM_STATUS_READY; | ||||
| 	} | ||||
|  | ||||
| 	} else | ||||
| 	/* If more bytes to write, send data. */ | ||||
| 	else if (twi->bytesWritten < bytesToWrite) { | ||||
| 		uint8_t data = twi->writeData[twi->bytesWritten]; | ||||
| 	if( twi->bytesWritten < bytesToWrite ) { | ||||
| #if 0 | ||||
| 	PORTB.OUTSET = (1<<3); | ||||
| 	PORTB.OUTCLR = (1<<3); | ||||
| #endif | ||||
| 		uint8_t const data = twi->writeData[twi->bytesWritten]; | ||||
| 		twi->interface->MASTER.DATA = data; | ||||
| 		++twi->bytesWritten; | ||||
| 	} | ||||
|  | ||||
| 		twi->bytesWritten++; | ||||
| 	} else | ||||
| 	/* If bytes to read, send repeated START condition + Address + | ||||
| 	 * 'R/_W = 1' | ||||
| 	 */ | ||||
| 	else if (twi->bytesRead < bytesToRead) { | ||||
| 		uint8_t readAddress = twi->address | 0x01; | ||||
| 	if( twi->bytesRead < bytesToRead ) { | ||||
| #if 0 | ||||
| 	PORTB.OUTSET = (1<<3); | ||||
| 	PORTB.OUTCLR = (1<<3); | ||||
| #endif | ||||
| 		uint8_t const readAddress = twi->address | 0x01; | ||||
| 		twi->interface->MASTER.ADDR = readAddress; | ||||
| 	} | ||||
|  | ||||
| 	/* If transaction finished, send STOP condition and set RESULT OK. */ | ||||
| 	else { | ||||
| #if 0 | ||||
| 	PORTB.OUTSET = (1<<3); | ||||
| 	PORTB.OUTCLR = (1<<3); | ||||
| #endif | ||||
| 		twi->interface->MASTER.CTRLC = TWI_MASTER_CMD_STOP_gc; | ||||
| 		TWI_MasterTransactionFinished(twi, TWIM_RESULT_OK); | ||||
| 	} | ||||
| @@ -353,32 +428,36 @@ void TWI_MasterWriteHandler(TWI_Master_t *twi) | ||||
|  * | ||||
|  *  \param twi The TWI_Master_t struct instance. | ||||
|  */ | ||||
| void TWI_MasterReadHandler(TWI_Master_t *twi) | ||||
| static void TWI_MasterReadHandler(TWI_Master_t *twi) | ||||
| { | ||||
| #if 1 | ||||
| 	PORTB.OUTTGL = (1<<3); | ||||
| 	PORTB.OUTTGL = (1<<3); | ||||
| #endif | ||||
|  | ||||
| 	/* Local variable used in if test to avoid compiler warning. */ | ||||
| 	uint8_t const bytesToRead = twi->bytesToRead; | ||||
|  | ||||
| 	/* Fetch data if bytes to be read. */ | ||||
| 	if (twi->bytesRead < TWIM_READ_BUFFER_SIZE) { | ||||
| 		uint8_t data = twi->interface->MASTER.DATA; | ||||
| 	if( twi->bytesRead < bytesToRead ) { | ||||
| 		uint8_t const data = twi->interface->MASTER.DATA; | ||||
| 		twi->readData[twi->bytesRead] = data; | ||||
| 		twi->bytesRead++; | ||||
| 	} | ||||
|  | ||||
| 	/* If buffer overflow, issue STOP and BUFFER_OVERFLOW condition. */ | ||||
| 	else { | ||||
| 		twi->interface->MASTER.CTRLC = TWI_MASTER_CMD_STOP_gc; | ||||
| 		TWI_MasterTransactionFinished(twi, TWIM_RESULT_BUFFER_OVERFLOW); | ||||
| 	} | ||||
|  | ||||
| 	/* Local variable used in if test to avoid compiler warning. */ | ||||
| 	uint8_t bytesToRead = twi->bytesToRead; | ||||
|  | ||||
| 	/* If more bytes to read, issue ACK and start a byte read. */ | ||||
| 	if (twi->bytesRead < bytesToRead) { | ||||
| 	if( twi->bytesRead < bytesToRead ) { | ||||
| 		twi->interface->MASTER.CTRLC = TWI_MASTER_CMD_RECVTRANS_gc; | ||||
| 	} | ||||
|  | ||||
| 	/* If transaction finished, issue NACK and STOP condition. */ | ||||
| 	else { | ||||
| 		twi->interface->MASTER.CTRLC = TWI_MASTER_ACKACT_bm | | ||||
| 		twi->interface->MASTER.CTRLC = //TWI_MASTER_ACKACT_bm | | ||||
| 		                               TWI_MASTER_CMD_STOP_gc; | ||||
| 		TWI_MasterTransactionFinished(twi, TWIM_RESULT_OK); | ||||
| 	} | ||||
| @@ -392,8 +471,9 @@ void TWI_MasterReadHandler(TWI_Master_t *twi) | ||||
|  *  \param twi     The TWI_Master_t struct instance. | ||||
|  *  \param result  The result of the operation. | ||||
|  */ | ||||
| void TWI_MasterTransactionFinished(TWI_Master_t *twi, uint8_t result) | ||||
| static void TWI_MasterTransactionFinished(TWI_Master_t *twi, uint8_t result) | ||||
| { | ||||
| 	twi->result = result; | ||||
| 	twi->status = TWIM_STATUS_READY; | ||||
| } | ||||
|  | ||||
|   | ||||
| @@ -72,63 +72,62 @@ | ||||
|  | ||||
| /*! Transaction result enumeration. */ | ||||
| typedef enum TWIM_RESULT_enum { | ||||
| 	TWIM_RESULT_UNKNOWN          = (0x00<<0), | ||||
| 	TWIM_RESULT_OK               = (0x01<<0), | ||||
| 	TWIM_RESULT_BUFFER_OVERFLOW  = (0x02<<0), | ||||
| 	TWIM_RESULT_ARBITRATION_LOST = (0x03<<0), | ||||
| 	TWIM_RESULT_BUS_ERROR        = (0x04<<0), | ||||
| 	TWIM_RESULT_NACK_RECEIVED    = (0x05<<0), | ||||
| 	TWIM_RESULT_FAIL             = (0x06<<0), | ||||
| 	TWIM_RESULT_UNKNOWN          , | ||||
| 	TWIM_RESULT_OK               , | ||||
| 	TWIM_RESULT_BUFFER_OVERFLOW  , | ||||
| 	TWIM_RESULT_ARBITRATION_LOST , | ||||
| 	TWIM_RESULT_BUS_ERROR        , | ||||
| 	TWIM_RESULT_NACK_RECEIVED    , | ||||
| 	TWIM_RESULT_FAIL             , | ||||
| } TWIM_RESULT_t; | ||||
|  | ||||
| /*! Buffer size defines */ | ||||
| #define TWIM_WRITE_BUFFER_SIZE         8 | ||||
| #define TWIM_READ_BUFFER_SIZE          8 | ||||
|  | ||||
|  | ||||
| /*! \brief TWI master driver struct | ||||
|  * | ||||
|  *  TWI master struct. Holds pointer to TWI module, | ||||
|  *  buffers and necessary varibles. | ||||
|  */ | ||||
| typedef struct TWI_Master { | ||||
| 	TWI_t *interface;                  /*!< Pointer to what interface to use */ | ||||
| 	register8_t address;                            /*!< Slave address */ | ||||
| 	register8_t writeData[TWIM_WRITE_BUFFER_SIZE];  /*!< Data to write */ | ||||
| 	register8_t readData[TWIM_READ_BUFFER_SIZE];    /*!< Read data */ | ||||
| 	register8_t bytesToWrite;                       /*!< Number of bytes to write */ | ||||
| 	register8_t bytesToRead;                        /*!< Number of bytes to read */ | ||||
| 	register8_t bytesWritten;                       /*!< Number of bytes written */ | ||||
| 	register8_t bytesRead;                          /*!< Number of bytes read */ | ||||
| 	register8_t status;                             /*!< Status of transaction */ | ||||
| 	register8_t result;                             /*!< Result of transaction */ | ||||
| 	TWI_t *interface;         /*!< Pointer to what interface to use */ | ||||
| 	uint8_t const *writeData; /*!< Data to write */ | ||||
| 	uint8_t *readData;        /*!< Read data */ | ||||
| 	uint8_t address;      /*!< Slave address */ | ||||
| 	uint8_t bytesToWrite; /*!< Number of bytes to write */ | ||||
| 	uint8_t bytesToRead;  /*!< Number of bytes to read */ | ||||
| 	uint8_t bytesWritten; /*!< Number of bytes written */ | ||||
| 	uint8_t bytesRead;    /*!< Number of bytes read */ | ||||
| 	uint8_t status;       /*!< Status of transaction */ | ||||
| 	uint8_t result;       /*!< Result of transaction */ | ||||
| }TWI_Master_t; | ||||
|  | ||||
|  | ||||
|  | ||||
| void TWI_MasterInit(TWI_Master_t *twi, | ||||
|                     TWI_t *module, | ||||
|                     TWI_MASTER_INTLVL_t intLevel, | ||||
|                     uint8_t baudRateRegisterSetting); | ||||
|  | ||||
| TWI_MASTER_BUSSTATE_t TWI_MasterState(TWI_Master_t *twi); | ||||
|  | ||||
| bool TWI_MasterReady(TWI_Master_t *twi); | ||||
|  | ||||
| void TWI_MasterForceIdle(TWI_Master_t *twi); | ||||
|  | ||||
| bool TWI_MasterWrite(TWI_Master_t *twi, | ||||
|                      uint8_t address, | ||||
|                      uint8_t * writeData, | ||||
|                      uint8_t const * writeData, | ||||
|                      uint8_t bytesToWrite); | ||||
|  | ||||
| bool TWI_MasterRead(TWI_Master_t *twi, | ||||
|                     uint8_t address, | ||||
| 		    uint8_t * readData, | ||||
|                     uint8_t bytesToRead); | ||||
|  | ||||
| bool TWI_MasterWriteRead(TWI_Master_t *twi, | ||||
|                          uint8_t address, | ||||
|                          uint8_t *writeData, | ||||
|                          uint8_t const *writeData, | ||||
|                          uint8_t bytesToWrite, | ||||
| 			 uint8_t *readData, | ||||
|                          uint8_t bytesToRead); | ||||
|  | ||||
| void TWI_MasterInterruptHandler(TWI_Master_t *twi); | ||||
| void TWI_MasterArbitrationLostBusErrorHandler(TWI_Master_t *twi); | ||||
| void TWI_MasterWriteHandler(TWI_Master_t *twi); | ||||
| void TWI_MasterReadHandler(TWI_Master_t *twi); | ||||
| void TWI_MasterTransactionFinished(TWI_Master_t *twi, uint8_t result); | ||||
|  | ||||
|  | ||||
| /*! TWI master interrupt service routine. | ||||
|   | ||||
| @@ -79,7 +79,7 @@ | ||||
|  */ | ||||
| void TWI_SlaveInitializeDriver(TWI_Slave_t *twi, | ||||
|                                TWI_t *module, | ||||
|                                void (*processDataFunction) (void)) | ||||
|                                TWI_SlaveProc processDataFunction) | ||||
| { | ||||
| 	twi->interface = module; | ||||
| 	twi->Process_Data = processDataFunction; | ||||
| @@ -102,13 +102,18 @@ void TWI_SlaveInitializeDriver(TWI_Slave_t *twi, | ||||
|  */ | ||||
| void TWI_SlaveInitializeModule(TWI_Slave_t *twi, | ||||
|                                uint8_t address, | ||||
|                                TWI_SLAVE_INTLVL_t intLevel) | ||||
|                                TWI_SLAVE_INTLVL_t intLevel, | ||||
| 			       uint8_t *recvData, | ||||
| 			       uint8_t bytesMaxRecv ) | ||||
| { | ||||
| 	twi->bytesMaxRecv = bytesMaxRecv; | ||||
| 	twi->recvData = recvData; | ||||
|  | ||||
| 	twi->interface->SLAVE.CTRLA = intLevel | | ||||
| 	                              TWI_SLAVE_DIEN_bm | | ||||
| 	                              TWI_SLAVE_APIEN_bm | | ||||
| 	                              TWI_SLAVE_ENABLE_bm; | ||||
| 	twi->interface->SLAVE.ADDR = (address<<1); | ||||
| 	twi->interface->SLAVE.ADDR = (address << 1); | ||||
| } | ||||
|  | ||||
|  | ||||
| @@ -121,7 +126,12 @@ void TWI_SlaveInitializeModule(TWI_Slave_t *twi, | ||||
|  */ | ||||
| void TWI_SlaveInterruptHandler(TWI_Slave_t *twi) | ||||
| { | ||||
| 	uint8_t currentStatus = twi->interface->SLAVE.STATUS; | ||||
| #if 1 | ||||
| 	PORTE.OUTSET = (1<<2); | ||||
| 	PORTE.OUTCLR = (1<<2); | ||||
| #endif | ||||
|  | ||||
| 	uint8_t const currentStatus = twi->interface->SLAVE.STATUS; | ||||
|  | ||||
| 	/* If bus error. */ | ||||
| 	if (currentStatus & TWI_SLAVE_BUSERR_bm) { | ||||
| @@ -129,30 +139,30 @@ void TWI_SlaveInterruptHandler(TWI_Slave_t *twi) | ||||
| 		twi->bytesSent = 0; | ||||
| 		twi->result = TWIS_RESULT_BUS_ERROR; | ||||
| 		twi->status = TWIS_STATUS_READY; | ||||
| 	} | ||||
| 	} else | ||||
|  | ||||
| 	/* If transmit collision. */ | ||||
| 	else if (currentStatus & TWI_SLAVE_COLL_bm) { | ||||
| 	if (currentStatus & TWI_SLAVE_COLL_bm) { | ||||
| 		twi->bytesReceived = 0; | ||||
| 		twi->bytesSent = 0; | ||||
| 		twi->result = TWIS_RESULT_TRANSMIT_COLLISION; | ||||
| 		twi->status = TWIS_STATUS_READY; | ||||
| 	} | ||||
| 	} else | ||||
|  | ||||
| 	/* If address match. */ | ||||
| 	else if ((currentStatus & TWI_SLAVE_APIF_bm) && | ||||
| 	if ((currentStatus & TWI_SLAVE_APIF_bm) && | ||||
| 	        (currentStatus & TWI_SLAVE_AP_bm)) { | ||||
|  | ||||
| 		TWI_SlaveAddressMatchHandler(twi); | ||||
| 	} | ||||
| 	} else | ||||
|  | ||||
| 	/* If stop (only enabled through slave read transaction). */ | ||||
| 	else if (currentStatus & TWI_SLAVE_APIF_bm) { | ||||
| 	if (currentStatus & TWI_SLAVE_APIF_bm) { | ||||
| 		TWI_SlaveStopHandler(twi); | ||||
| 	} | ||||
| 	} else | ||||
|  | ||||
| 	/* If data interrupt. */ | ||||
| 	else if (currentStatus & TWI_SLAVE_DIF_bm) { | ||||
| 	if (currentStatus & TWI_SLAVE_DIF_bm) { | ||||
| 		TWI_SlaveDataHandler(twi); | ||||
| 	} | ||||
|  | ||||
| @@ -219,7 +229,7 @@ void TWI_SlaveStopHandler(TWI_Slave_t *twi) | ||||
|  */ | ||||
| void TWI_SlaveDataHandler(TWI_Slave_t *twi) | ||||
| { | ||||
| 	if (twi->interface->SLAVE.STATUS & TWI_SLAVE_DIR_bm) { | ||||
| 	if( twi->interface->SLAVE.STATUS & TWI_SLAVE_DIR_bm ) { | ||||
| 		TWI_SlaveWriteHandler(twi); | ||||
| 	} else { | ||||
| 		TWI_SlaveReadHandler(twi); | ||||
| @@ -235,18 +245,20 @@ void TWI_SlaveDataHandler(TWI_Slave_t *twi) | ||||
|  */ | ||||
| void TWI_SlaveReadHandler(TWI_Slave_t *twi) | ||||
| { | ||||
| 	uint8_t const bytesMaxRecv = twi->bytesMaxRecv; | ||||
|  | ||||
| 	/* Enable stop interrupt. */ | ||||
| 	uint8_t currentCtrlA = twi->interface->SLAVE.CTRLA; | ||||
| 	twi->interface->SLAVE.CTRLA = currentCtrlA | TWI_SLAVE_PIEN_bm; | ||||
|  | ||||
| 	/* If free space in buffer. */ | ||||
| 	if (twi->bytesReceived < TWIS_RECEIVE_BUFFER_SIZE) { | ||||
| 	if( twi->bytesReceived < bytesMaxRecv ) { | ||||
| 		/* Fetch data */ | ||||
| 		uint8_t data = twi->interface->SLAVE.DATA; | ||||
| 		twi->receivedData[twi->bytesReceived] = data; | ||||
| 		twi->recvData[twi->bytesReceived] = data; | ||||
|  | ||||
| 		/* Process data. */ | ||||
| 		twi->Process_Data(); | ||||
| 		twi->Process_Data(twi); | ||||
|  | ||||
| 		twi->bytesReceived++; | ||||
|  | ||||
| @@ -254,11 +266,12 @@ void TWI_SlaveReadHandler(TWI_Slave_t *twi) | ||||
| 		 * complete transaction and wait for next START. Otherwise | ||||
| 		 * send ACK and wait for data interrupt. | ||||
| 		 */ | ||||
| 		if (twi->abort) { | ||||
| 		if( twi->abort ) { | ||||
| 			twi->interface->SLAVE.CTRLB = TWI_SLAVE_CMD_COMPTRANS_gc; | ||||
| 			TWI_SlaveTransactionFinished(twi, TWIS_RESULT_ABORTED); | ||||
| 			twi->abort = false; | ||||
| 		} else { | ||||
| 		} | ||||
| 		else { | ||||
| 			twi->interface->SLAVE.CTRLB = TWI_SLAVE_CMD_RESPONSE_gc; | ||||
| 		} | ||||
| 	} | ||||
| @@ -281,6 +294,7 @@ void TWI_SlaveReadHandler(TWI_Slave_t *twi) | ||||
|  */ | ||||
| void TWI_SlaveWriteHandler(TWI_Slave_t *twi) | ||||
| { | ||||
| 	uint8_t const bytesToSend = twi->bytesToSend; | ||||
| 	/* If NACK, slave write transaction finished. */ | ||||
| 	if ((twi->bytesSent > 0) && (twi->interface->SLAVE.STATUS & | ||||
| 	                             TWI_SLAVE_RXACK_bm)) { | ||||
| @@ -290,7 +304,7 @@ void TWI_SlaveWriteHandler(TWI_Slave_t *twi) | ||||
| 	} | ||||
| 	/* If ACK, master expects more data. */ | ||||
| 	else { | ||||
| 		if (twi->bytesSent < TWIS_SEND_BUFFER_SIZE) { | ||||
| 		if( twi->bytesSent < bytesToSend ) { | ||||
| 			uint8_t data = twi->sendData[twi->bytesSent]; | ||||
| 			twi->interface->SLAVE.DATA = data; | ||||
| 			twi->bytesSent++; | ||||
|   | ||||
| @@ -77,11 +77,9 @@ typedef enum TWIS_RESULT_enum { | ||||
| 	TWIS_RESULT_ABORTED            = (0x06<<0), | ||||
| } TWIS_RESULT_t; | ||||
|  | ||||
| /* Buffer size defines. */ | ||||
| #define TWIS_RECEIVE_BUFFER_SIZE         8 | ||||
| #define TWIS_SEND_BUFFER_SIZE            8 | ||||
|  | ||||
| struct TWI_Slave; | ||||
|  | ||||
| typedef void (*TWI_SlaveProc)(struct TWI_Slave*); | ||||
|  | ||||
| /*! \brief TWI slave driver struct. | ||||
|  * | ||||
| @@ -89,26 +87,28 @@ typedef enum TWIS_RESULT_enum { | ||||
|  *  buffers and necessary varibles. | ||||
|  */ | ||||
| typedef struct TWI_Slave { | ||||
| 	TWI_t *interface;                               /*!< Pointer to what interface to use*/ | ||||
| 	void (*Process_Data) (void);                    /*!< Pointer to process data function*/ | ||||
| 	register8_t receivedData[TWIS_RECEIVE_BUFFER_SIZE]; /*!< Read data*/ | ||||
| 	register8_t sendData[TWIS_SEND_BUFFER_SIZE];        /*!< Data to write*/ | ||||
| 	register8_t bytesReceived;                          /*!< Number of bytes received*/ | ||||
| 	register8_t bytesSent;                              /*!< Number of bytes sent*/ | ||||
| 	register8_t status;                                 /*!< Status of transaction*/ | ||||
| 	register8_t result;                                 /*!< Result of transaction*/ | ||||
| 	bool abort;                                     /*!< Strobe to abort*/ | ||||
| 	TWI_t *interface;           /*!< Pointer to what interface to use*/ | ||||
| 	TWI_SlaveProc Process_Data; /*!< Pointer to process data function*/ | ||||
| 	uint8_t *recvData; | ||||
| 	uint8_t const *sendData;    /*!< Data to write*/ | ||||
| 	uint8_t bytesMaxRecv; | ||||
| 	uint8_t bytesToSend;        /*!< Number of bytes to send */ | ||||
| 	uint8_t bytesReceived;      /*!< Number of bytes received*/ | ||||
| 	uint8_t bytesSent;          /*!< Number of bytes sent*/ | ||||
| 	uint8_t status;             /*!< Status of transaction*/ | ||||
| 	uint8_t result;             /*!< Result of transaction*/ | ||||
| 	bool abort;                 /*!< Strobe to abort*/ | ||||
| } TWI_Slave_t; | ||||
|  | ||||
|  | ||||
|  | ||||
| void TWI_SlaveInitializeDriver(TWI_Slave_t *twi, | ||||
|                                TWI_t *module, | ||||
|                                void (*processDataFunction) (void)); | ||||
|                                TWI_SlaveProc processDataFunction); | ||||
|  | ||||
| void TWI_SlaveInitializeModule(TWI_Slave_t *twi, | ||||
|                                uint8_t address, | ||||
|                                TWI_SLAVE_INTLVL_t intLevel); | ||||
|                                TWI_SLAVE_INTLVL_t intLevel, | ||||
| 			       uint8_t *recvData, | ||||
| 			       uint8_t bytesMaxRecv ); | ||||
|  | ||||
| void TWI_SlaveInterruptHandler(TWI_Slave_t *twi); | ||||
| void TWI_SlaveAddressMatchHandler(TWI_Slave_t *twi); | ||||
|   | ||||
										
											Binary file not shown.
										
									
								
							
										
											Binary file not shown.
										
									
								
							
		Reference in New Issue
	
	Block a user