It's not the pixels that are swapped, it's the actual bytes getting loaded into the I2S path. So instead of just swapping the pixels around, you should swap around the way you write into the I2S buffer. If you don't, the sync signals will still be written 'straight' and me emitted in the wrong place.
doh, you're right of course. I did try to fix it, and got an improvement. Right edge is clean, but am still not getting the whole line. Have tried latching previous line on first pixel, or current line on last pixel. First option looks better - shows more of the right side, left border is smaller.
With the original PIC24 graphic controller, the HS latch pulse is on the last pixel of the row, but it's a short pulse (< 1/2 clock period, and positive edge is when clock is low). As per the info I have, the line data is latched on the falling edge of the HS pulse.
With this setup, the HS pulse is one full clock period with positive edge synced to clock positive edge. I tried inverting the HS pulse with 'gpio_matrix_out()', but the lcd doesn't like that, no image at all.
But maybe there is something else I haven't taken care of.
I would be interested to see the source to create data including sync signals.
In the code below that generates this image, I am basically hacking the FR toggle by placing two copies of the same image in a buffer with FR = 0 for the first and FR= 1 for the second, the i2s just loops around both. I suppose this could be done via an interrupt setting a gpio rather than through the i2s parallel bus.
Code: Select all
#define NUM_COLS 60
#define NUM_ROWS 160
#define FRAME_SIZE (NUM_COLS * NUM_ROWS)
#define BIT_HS (uint8_t)(1<<4)
#define BIT_VS (uint8_t)(1<<5)
#define BIT_FR (uint8_t)(1<<6)
//
// Image data for lena
//
const uint8_t lenaBitmap[] =
{
0x55, 0xEB, 0x65, 0x7B,... etc
};
uint8_t frameBuffer[2*FRAME_SIZE];
static void createTestImage(uint8_t* pFB, uint8_t* pImg) {
uint8_t* pPkt = pFB;
uint8_t* pSrc = pImg;
for (int row = 0; row < NUM_ROWS; row++) {
int col = 0;
while (col < NUM_COLS) {
uint8_t d4;
uint8_t d8a = *pSrc++;
uint8_t d8b = *pSrc++;
d4 = d8b>>4;
if (row == 0) d4 |= BIT_VS;
*pPkt++ = d4;
col++;
d4 = d8b&0xf;
//if (col == 57) d4 |= BIT_HS; // latch current line on the last clock
if (row == 0) d4 |= BIT_VS;
*pPkt++ = d4;
col++;
d4 = d8a>>4;
if (col == 2) d4 |= BIT_HS; // latch previous line on the first clock
if (row == 0) d4 |= BIT_VS;
*pPkt++ = d4;
col++;
d4 = d8a&0xf;
if (row == 0) d4 |= BIT_VS;
*pPkt++ = d4;
col++;
}
}
memcpy(pPkt, pFB, FRAME_SIZE);
for (int inx = 0; inx < FRAME_SIZE; inx++) {
*pPkt |= BIT_FR;
pPkt++;
}
}
void app_main(){
gpio_set_direction(PIN_LED, GPIO_MODE_DEF_OUTPUT);
gpio_set_direction(PIN_DOFF, GPIO_MODE_DEF_OUTPUT);
gpio_set_level(PIN_DOFF, 0);
gpio_set_direction(PIN_BIASEN, GPIO_MODE_DEF_OUTPUT);
gpio_set_level(PIN_BIASEN, 0);
gpio_set_direction(PIN_BTN, GPIO_MODE_DEF_INPUT);
gpio_pullup_en(PIN_BTN);
createTestImage(frameBuffer, (uint8_t*)lenaBitmap);
i2s_parallel_buffer_desc_t bufdesc[2];
i2s_parallel_config_t cfg = {
.gpio_bus = {15, // 0 : d0
2, // 1 : d1
4, // 2 : d2
16, // 3 : d3
17, // 4 : HS
5, // 5 : VS
18, // 6 : FR
-1}, // 7 : no connection
.gpio_clk = 19, // XCK
.bits = I2S_PARALLEL_BITS_8,
.clkspeed_hz = 2000*1000,
.bufa = &bufdesc[0],
.bufb = &bufdesc[1]
};
bufdesc[0].memory = frameBuffer;
bufdesc[0].size = 2*FRAME_SIZE;
bufdesc[1].memory = frameBuffer; // not used for now, so point to the same buffer
bufdesc[1].size = 2*FRAME_SIZE;
gpio_set_level(PIN_BIASEN, 1); // enable lcd bias voltage V0
vTaskDelay(50 / portTICK_PERIOD_MS);
gpio_set_level(PIN_DOFF, 1); // enable lcd
vTaskDelay(50 / portTICK_PERIOD_MS);
i2s_parallel_setup(&I2S1, &cfg);
printf("I2S setup done.\n");
//int backbuf_id = 0; //which buffer is the backbuffer, as in, which one is not active so we can write to it
int level = 0;
while(1) {
//Show our work!
//i2s_parallel_flip_to_buffer(&I2S1, backbuf_id);
//backbuf_id ^= 1;
vTaskDelay(1000 / portTICK_PERIOD_MS);
gpio_set_level(PIN_LED, level);
level = !level;
if (gpio_get_level(PIN_BTN)) {
}
else {
}
}
}