Click here to Skip to main content
15,885,366 members
Please Sign up or sign in to vote.
0.00/5 (No votes)
See more:
I'm having trouble reading from an SPI bus, specifically an ILI9341 display adapter (i've had the same trouble with other devices as well though). When I attempt to read, all I ever get back are zeroes. I can write just fine.

I am using an ESP-WROVER-KIT v4.1 with an integrated ILI9341 display, so I know the wiring is correct. According to the documentation my configured MISO line is correct. Again, I write data just fine, so MOSI is good as well.

Basically, I set the address window, initiate a memory read (0x2E) and read a dummy parameter (which is always zero for me) and then read data. This is being done as separate transactions. When I write this way I have no trouble (except there is no dummy parameter on writes). Unfortunately, again I get zeroes when I read.

The complete code for reproducing this is as short as I can make it and yet too long for this forum, so I'm posting a link to the relevant .c file here that will reproduce the problem.

ili9341_read_rep/main.c at master · codewitch-honey-crisis/ili9341_read_rep · GitHub[^]

That repo also contains a full platformio project if you need to run it. Just back up to the main repo link.

An excerpt of the code is below

Here is a link to the datasheet for reference https://cdn-shop.adafruit.com/datasheets/ILI9341.pdf The relevant pages are 116 and 117. I do not think the datasheet will uncover the core issue but I'm providing it anyway. I think the issue is the way I'm calling the API, but I can't be sure. There are no good examples of reads in the ESP-IDF SDK except from an NVS thing which uses an entirely different SPI configuration (10 command bits, address bits, HALF_DUPLEX flag, etc) so it's not very useful to me.

I've also tried looking at Arduino code to do this but the SPI API is too different for me to make heads or tails of it enough to translate it to the ESP-IDF

Perhaps my code above needs some minor corrections? I'm hoping that's the case. Any help would be greatly appreciated.

I'm trying to ask this on stack-overflow as well, but it looks like my questions all get downvoted and I'll be blocked soon. I don't get that site.

What I have tried:

From main.c (see the full code at the link)

C++
spi_device_handle_t handle;
ESP_ERROR_CHECK(spi_bus_add_device(HOST,&devcfg,&handle));
init_display(handle);
uint16_t fill[320];
memset(fill,0xFF,320*2);
set_window(handle,0,0,319,239);
uint8_t cmd = 0x2C; // memory write
send(handle,&cmd,1,true);
for(int y=0;y<240;++y) {
    send(handle,(uint8_t*)fill,320*2,false);
}
set_window(handle,0,0,319,239);
cmd = 0x2E; // memory read
send(handle,&cmd,1,true);
// dummy read (see datasheet)
retr(handle,&cmd,1,false);
printf("dummy value: 0x");
print_hex(&cmd,1);
printf("\r\n");
// getting zeroes here, but expect FFFFFF...
for(int y=0;y<240;++y) {
    size_t sz = retr(handle,(uint8_t*)fill,320*2,false);
    print_hex((uint8_t*)fill,sz);
    printf("\r\n");
    vTaskDelay(1);
}

Here's how I set up the read (the retr() function)

C++
// retrieves data from the SPI bus MISO line
// this doesn't seem to return meaningful data currently
size_t retr(spi_device_handle_t handle, uint8_t* data,size_t size,bool cmd) {
    if(0<size) {
        spi_transaction_t t;
        memset(&t,0,sizeof(t));
        // always use rx_buffer
        t.rx_buffer = data;
        t.length = t.rxlength = 8*size;
        t.user = (void*)!cmd;
        ESP_ERROR_CHECK(spi_device_polling_transmit(handle,&t));
        return (t.rxlength+7)/8;
    }
    return 0;
}
Posted
Comments
[no name] 25-May-21 10:48am    
No idea ... don't know c++ either; but you "defined" (?) fill as uint16_t, then "cast" (?) it as uint8_t ... so you only get "half-words" (?). Or, why not uint8_t fill[640] and no 320*2, etc.
honey the codewitch 25-May-21 10:57am    
The reason it's defined that way is it's 16-bit color values, but send and retr take a byte array. It's fine - casting does nothing to the data. It only changes how the data is perceived. It is a "pure" operation with no side effects (unless it is overloaded, and in this case it isn't). say you had a 16 bit word of 0xC1A2. If you cast that to bytes you'd have a byte C1 followed by A2 (actually reversed on little endian systems but you get the idea). send and retr deal in BLOBs which are byte arrays, effectively. But it's easier to deal with pixels in their native format, hence the discrepancy there. a 16 bit pixel is R:5, G:6, B:5 so you can't split it cleanly.

As to your second question, each color is 2 bytes. The pixels are 320 across. The compiler will "fold" the value to 640 with no runtime overhead, but defining it this way makes it clearer that it's 320 pixels of 2 bytes each. It's just a way to express intent with code.
[no name] 25-May-21 11:38am    
Sounds good ... Now, in your "for loop", you vary "y" but never reference it. I don't see your for loop "moving".
honey the codewitch 25-May-21 11:50am    
Whoops, I forgot to increment my fill pointer. Not sure what i was thinking. Still, it doesn't solve my issue but thanks for spotting that.

Edit: Never mind. retr() will fill "fill" each time with new data. The y is just there to make sure it gets called the right number of times.

This content, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)



CodeProject, 20 Bay Street, 11th Floor Toronto, Ontario, Canada M5J 2N8 +1 (416) 849-8900