Compare commits
8 Commits
695e5dc9f4
...
888a5af823
Author | SHA1 | Date |
---|---|---|
King Kévin | 888a5af823 | |
King Kévin | 8bc856095e | |
King Kévin | 7ba053d34f | |
King Kévin | 9e35864548 | |
King Kévin | 41435806b8 | |
King Kévin | df611e4436 | |
King Kévin | d02facf754 | |
King Kévin | df482ca7c4 |
|
@ -17,6 +17,11 @@ if the ERROR LED is on, the possible cause is one of the following:
|
||||||
- tried reading the EDID from the monitor, but it is not connected
|
- tried reading the EDID from the monitor, but it is not connected
|
||||||
- communication with monitor failed, due to damaged cable
|
- communication with monitor failed, due to damaged cable
|
||||||
- monitor EDID is invalid
|
- monitor EDID is invalid
|
||||||
|
- storing EDID in EEPROM failed
|
||||||
|
|
||||||
|
the firewall only acts as an I²C EEPROM at address 0x50 toward the HDMI device to provide the EDID information.
|
||||||
|
if the EDID switch is on the BLOCK position, the EEPROM is read only.
|
||||||
|
if the EDID switch is on the ALLOW position, writing the EEPROM is possible over the HDMI connection using standard I²C write operations.
|
||||||
|
|
||||||
limitations
|
limitations
|
||||||
===========
|
===========
|
||||||
|
|
95
main.c
95
main.c
|
@ -12,7 +12,7 @@
|
||||||
#include "softi2c_master.h"
|
#include "softi2c_master.h"
|
||||||
|
|
||||||
// enable UART debug
|
// enable UART debug
|
||||||
#define DEBUG 0
|
#define DEBUG 1
|
||||||
|
|
||||||
#define EEPROM_ADDR 0x4000 // EEPROM start address
|
#define EEPROM_ADDR 0x4000 // EEPROM start address
|
||||||
static bool eeprom_valid = true; // if the EDID can be read from EEPROM
|
static bool eeprom_valid = true; // if the EDID can be read from EEPROM
|
||||||
|
@ -48,8 +48,14 @@ static bool hpd_fwd = false; // if the I²C source line is connected to sink
|
||||||
|
|
||||||
// if an I²C transaction started
|
// if an I²C transaction started
|
||||||
static volatile bool i2c_transaction_new = false;
|
static volatile bool i2c_transaction_new = false;
|
||||||
// if an I²C transaction with new data started
|
// if an I²C transaction with incoming data started
|
||||||
static volatile bool i2c_input_new = false;
|
static volatile bool i2c_input_new = false;
|
||||||
|
// if the byte should be programmed
|
||||||
|
static volatile bool i2c_prog = false;
|
||||||
|
// the address of the byte to be read or programmed
|
||||||
|
static volatile uint8_t i2c_addr = 0;
|
||||||
|
// the data to be programmed
|
||||||
|
static volatile uint8_t i2c_data = 0;
|
||||||
|
|
||||||
// blocking wait (in 10 us steps, up to UINT32_MAX / 10)
|
// blocking wait (in 10 us steps, up to UINT32_MAX / 10)
|
||||||
static void wait_10us(uint32_t us10)
|
static void wait_10us(uint32_t us10)
|
||||||
|
@ -130,19 +136,21 @@ static uint16_t edid_length(const uint8_t* edid)
|
||||||
|
|
||||||
if (1 == edid[18]) { // EDID 1.3/1.4 128-byte structure
|
if (1 == edid[18]) { // EDID 1.3/1.4 128-byte structure
|
||||||
if (checksum_ok(&edid[0], 128)) { // ensure checksum of base EDID is ok
|
if (checksum_ok(&edid[0], 128)) { // ensure checksum of base EDID is ok
|
||||||
const uint16_t length = 128 + (1 + edid[126]) * 128; // get length with all extensions
|
const uint16_t length = 128 + edid[126] * 128; // get length with all extensions
|
||||||
puts("(v1.4 ");
|
puts("(v1.3/1.4, ");
|
||||||
putn(edid[126] / 100);
|
putn(edid[126] / 100);
|
||||||
putn((edid[126] / 10) % 10);
|
putn((edid[126] / 10) % 10);
|
||||||
putn(edid[126] % 10);
|
putn(edid[126] % 10);
|
||||||
puts(" extension) ");
|
puts(" extension) ");
|
||||||
for (uint16_t i = 128; i < length && i < 256; i += 128) { // verify checksum of each extension (we actually only support one extension)
|
if (edid[126]) { // extensions are present
|
||||||
if (!checksum_ok(&edid[i], 128)) {
|
for (uint16_t i = 128; i < length && i < 256; i += 128) { // verify checksum of each extension (we actually only support one extension)
|
||||||
puts("extension CRC error\r\n");
|
if (!checksum_ok(&edid[i], 128)) {
|
||||||
return 0; // EDID is broken
|
puts("extension CRC error\r\n");
|
||||||
|
return 0; // EDID is broken
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
puts("CRC ok\r\n");
|
puts("CRC OK\r\n");
|
||||||
return length;
|
return length;
|
||||||
} else {
|
} else {
|
||||||
puts("base CRC error\r\n");
|
puts("base CRC error\r\n");
|
||||||
|
@ -476,7 +484,7 @@ level pulse on the Hot Plug Detect pin. This pulse shall be at least 100 msec.
|
||||||
|
|
||||||
// verify stored EDID validity
|
// verify stored EDID validity
|
||||||
if (!edid_length((uint8_t*)EEPROM_ADDR)) {
|
if (!edid_length((uint8_t*)EEPROM_ADDR)) {
|
||||||
LED_PORT->ODR.reg &= ~LED_PIN; // switch LED on to indicate I²C read fail
|
LED_PORT->ODR.reg &= ~LED_PIN; // switch LED on to indicate EDID is invalid
|
||||||
puts("EEPROM EDID invalid\r\n");
|
puts("EEPROM EDID invalid\r\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -494,6 +502,40 @@ level pulse on the Hot Plug Detect pin. This pulse shall be at least 100 msec.
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
*/
|
*/
|
||||||
|
if (i2c_prog) { // received data over i2c to be programmed
|
||||||
|
if (EDID_PORT->IDR.reg & EDID_PIN) { // EDID switched off
|
||||||
|
puts("I²C prog disabled\r\n");
|
||||||
|
I2C_CR2 &= I2C_CR2_ACK; // NACK next received byte to indicate programming it disabled
|
||||||
|
} else { // EDID programming allowed
|
||||||
|
/*
|
||||||
|
puts("I²C prog ");
|
||||||
|
puth(i2c_data);
|
||||||
|
puts("@");
|
||||||
|
puth(i2c_addr);
|
||||||
|
puts("\r\n");
|
||||||
|
*/
|
||||||
|
IWDG_KR = IWDG_KR_KEY_REFRESH; // reset watchdog
|
||||||
|
// disable DATA (e.g. EEPROM) write protection
|
||||||
|
if (0 == (FLASH_IAPSR & FLASH_IAPSR_DUL)) {
|
||||||
|
FLASH_DUKR = FLASH_DUKR_KEY1;
|
||||||
|
FLASH_DUKR = FLASH_DUKR_KEY2;
|
||||||
|
}
|
||||||
|
// save need EDID
|
||||||
|
*(uint8_t*)(EEPROM_ADDR + i2c_addr) = i2c_data; // write byte
|
||||||
|
while (FLASH_CR2 & FLASH_CR2_WPRG); // wait for write to complete
|
||||||
|
// check if programming failed
|
||||||
|
// we don't check for WR_PG_DIS (while checking EOP) because EEPROM isn't (and can't be) write protected
|
||||||
|
if (!(FLASH_IAPSR & FLASH_IAPSR_EOP)) {
|
||||||
|
FLASH_IAPSR &= ~FLASH_IAPSR_DUL; // re-enable write protection
|
||||||
|
LED_PORT->ODR.reg &= ~LED_PIN; // switch LED on to indicate programming failed
|
||||||
|
I2C_CR2 &= I2C_CR2_ACK; // NACK next received byte to indicate programming error
|
||||||
|
puts("EEPROM byte prog failed\r\n");
|
||||||
|
}
|
||||||
|
FLASH_IAPSR &= ~FLASH_IAPSR_DUL; // re-enable write protection
|
||||||
|
}
|
||||||
|
action = true; // re-run loop
|
||||||
|
i2c_prog = false; // clear flag
|
||||||
|
}
|
||||||
if (action) { // something has been performed, check if other flags have been set meanwhile
|
if (action) { // something has been performed, check if other flags have been set meanwhile
|
||||||
action = false; // clear flag
|
action = false; // clear flag
|
||||||
} else { // nothing down
|
} else { // nothing down
|
||||||
|
@ -510,25 +552,24 @@ void awu(void) __interrupt(IRQ_AWU) // auto wakeup
|
||||||
|
|
||||||
void i2c(void) __interrupt(IRQ_I2C) // auto wakeup
|
void i2c(void) __interrupt(IRQ_I2C) // auto wakeup
|
||||||
{
|
{
|
||||||
static uint8_t addr = 0; // EEPROM address to read
|
|
||||||
// make copies of status registers, since some bits might be cleared meanwhile
|
// make copies of status registers, since some bits might be cleared meanwhile
|
||||||
const uint8_t sr1 = I2C_SR1;
|
const uint8_t sr1 = I2C_SR1;
|
||||||
const uint8_t sr2 = I2C_SR2;
|
const uint8_t sr2 = I2C_SR2;
|
||||||
const uint8_t sr3 = I2C_SR3; // clears ADDR after reading SR1
|
const uint8_t sr3 = I2C_SR3; // clears ADDR after reading SR1
|
||||||
if (sr1 & I2C_SR1_TXE) { // transmission buffer is empty
|
if (sr1 & I2C_SR1_TXE) { // transmission buffer is empty
|
||||||
// transmit next byte
|
I2C_DR = *(uint8_t*)(EEPROM_ADDR + i2c_addr++); // transmit next byte (even if invalid)
|
||||||
if (eeprom_valid) {
|
|
||||||
I2C_DR = *(uint8_t*)(EEPROM_ADDR + addr++);
|
|
||||||
} else {
|
|
||||||
I2C_DR = 0xff;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
if (sr1 & I2C_SR1_RXNE) { // receive buffer is full
|
if (sr1 & I2C_SR1_RXNE) { // receive buffer is full
|
||||||
const uint8_t data = I2C_DR; // read data (also clears flag)
|
i2c_data = I2C_DR; // read data (also clears flag)
|
||||||
if (I2C_CR2 & I2C_CR2_ACK) {
|
if (i2c_input_new) { // we just received the first byte
|
||||||
addr = data; // we only take the first address byte
|
i2c_addr = i2c_data; // we only take the first address byte
|
||||||
|
i2c_input_new = false; // next byte is not the first
|
||||||
|
} else { // received data byte
|
||||||
|
i2c_prog = true; // notify main loop data needs to be programmed
|
||||||
|
}
|
||||||
|
if (EDID_PORT->IDR.reg & EDID_PIN) { // EDID programming is not enabled
|
||||||
|
I2C_CR2 &= I2C_CR2_ACK; // NACK next received byte to indicate programming it disabled
|
||||||
}
|
}
|
||||||
I2C_CR2 &= I2C_CR2_ACK; // NACK next received byte
|
|
||||||
}
|
}
|
||||||
if (sr1 & I2C_SR1_STOPF) { // stop received
|
if (sr1 & I2C_SR1_STOPF) { // stop received
|
||||||
I2C_CR2 |= I2C_CR2_ACK; // this is just to clear the flag
|
I2C_CR2 |= I2C_CR2_ACK; // this is just to clear the flag
|
||||||
|
@ -536,14 +577,14 @@ void i2c(void) __interrupt(IRQ_I2C) // auto wakeup
|
||||||
if (sr1 & I2C_SR1_ADDR) { // our slave address has been selected
|
if (sr1 & I2C_SR1_ADDR) { // our slave address has been selected
|
||||||
i2c_transaction_new = true; // notify main loop transaction started
|
i2c_transaction_new = true; // notify main loop transaction started
|
||||||
if (sr3 & I2C_SR3_TRA) { // start data transmission
|
if (sr3 & I2C_SR3_TRA) { // start data transmission
|
||||||
if (eeprom_valid) {
|
I2C_DR = *(uint8_t*)(EEPROM_ADDR + i2c_addr++); // transmit selected byte
|
||||||
I2C_DR = *(uint8_t*)(EEPROM_ADDR + addr++); // transmit selected byte
|
|
||||||
} else {
|
|
||||||
I2C_DR = 0xff;
|
|
||||||
}
|
|
||||||
i2c_input_new = false; // notify we send data
|
i2c_input_new = false; // notify we send data
|
||||||
} else { // we will receive data
|
} else { // we will receive data
|
||||||
I2C_CR2 |= I2C_CR2_ACK; // ACK next received byte
|
if (EDID_PORT->IDR.reg & EDID_PIN) { // EDID switched off
|
||||||
|
I2C_CR2 &= I2C_CR2_ACK; // NACK next received byte to indicate programming it disabled
|
||||||
|
} else {
|
||||||
|
I2C_CR2 |= I2C_CR2_ACK; // ACK next received byte
|
||||||
|
}
|
||||||
i2c_input_new = true; // notify we get data
|
i2c_input_new = true; // notify we get data
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue