minilogic / f1c_nonos

Bare metal code examples for Allwinner's F1C100S (F1C200S) SOC
64 stars 20 forks source link

Getting started with F1C100S Bare Metal (no operating system) #5

Open Neothai opened 2 months ago

Neothai commented 2 months ago

Hello everyone, I just bought a LicheePi nano board (F1C100S chip). And I want to use it without an operating system to run a program with basic C language, such as typing "Hello World!" through Uart0, where I want to boot the program through 16MB SPI-Flash. Can you advise me? Like how do I compile the code? Or must the program be written into SPI-Flash at which address?

Thank you very much.

Nano_2

WebDust21 commented 1 month ago

a) You will need a LOT of in-depth knowledge of programming processors from the ground up. "Bare metal" means literally that: there is no structure present that you don't bring. In this case, @minilogic has provided a great resource for getting started--but you aren't going to find any "Arduino" functionality here in any shape or form! b) There will not be any Google Search help results for anything found in this repository. You're largely on your own...just you, the F1C100s board, and the F1Cx00s Technical Reference Manual (surprisingly short at 352 pages, because a lot of functionality is just summarized, and not fully documented).

Basic "getting started" as I found it:

  1. You'll need to download and install sunxi-tools; without it, you're dead in the water. In my case, the distro package available for Ubuntu 22.04 ("sudo apt get install sunxi-tools") was too old to support the F1Cx00s (as that was a recent patch--it worked for the V3S, but could not recognize the F1Cx00s). It was fairly simple to download the repository, install all necessary dependencies (via the Readme) and then run "make install" in the root directory. Once that succeeded, I was able to recognize the chip via connecting it to my computer, putting it in FEL mode (might be tricky on your board, as it doesn't appear to have a BOOT button), and then running "sunxi-fel ver".
  2. With sunxi-tools working, you should then be able to move on to the next step: getting some code compiled and working. In my case, I had to install the "arm-none-eabi" toolchain. https://github.com/minilogic/f1c_nonos/blob/4a001b73570018b8911c9e0aeb1b52446ccdc3d7/common.mk#L12
  3. Next, if you download this entire repository, it's a veritable treasure trove of "getting started" functionality for the F1Cx00s in bare metal form. Took me a bit to figure out that you just go to an example folder (i.e. https://github.com/minilogic/f1c_nonos/tree/main/src/coremark ), ensure your F1Cx00s is in FEL mode and connected to your computer, then run "make run" to test. To program, use "make flash". See here: https://github.com/minilogic/f1c_nonos/blob/4a001b73570018b8911c9e0aeb1b52446ccdc3d7/common.mk#L23-L33
  4. You may have to adjust the paths to the various tools referenced by the "common.mk" file. In my case (on Ubuntu), I also had to recompile the "mksunxi" tool--as what's provided here is all for Windoze. (find it here: https://github.com/hipboi/mksunxiboot . Downloaded, ran "make" and promptly had the necessary binary.)
  5. Have a lot of fun.
Neothai commented 1 month ago

Thank you for the advice It is very useful. And now I can start using some sample code.

But the sample code USBMSC HOST (F1C100S read usb drive) now it still doesn't work, there is no reaction when plugging the usb drive into F1C100S. And now I'm looking for a way to fix it.

Note: The USB MSC Device function (F1C100S simulates a USB drive with an SD card) can still be used normally.

WebDust21 commented 1 month ago

Do you have the USB OTG adapter pictured in @minilogic's example video? That may be critical. Also note that the UART output is over separate pins, which @minilogic broke out via wires to an external USB-UART board for debug output.

Neothai commented 1 month ago

Thank you for your reply.

Screenshot 2024-07-05 094316

From the picture above, if it's the piece circled in red. I don't have it. But if it's the one with the green circle, I have it because the store gave it to me when I bought the main board.

And now I have bought a new board (the main chip is the same as the original board) because I think this board should be more convenient to use than the old board.

Here is a picture of the new board I ordered. (Sample picture from the store) 6a4fadfd23754055800685ee0dcab441

WebDust21 commented 1 month ago

From the picture above, if it's the piece circled in red. I don't have it. But if it's the one with the green circle, I have it because the store gave it to me when I bought the main board.

The red part is something that @minilogic evidently personally created for development. The green part is what you would need.

If it's not working, then there's something else amiss. Time to dig deep into the source code and add diagnostic outputs. I wouldn't be surprised if the issue is one of the following:

minilogic commented 1 month ago

Thank you everyone for your interest in this project. Special thanks to @WebDust21 for his response regarding getting started. Indeed, learning any new project should begin by looking at the project's build system. The main setting is done in the sys.h file, which depends on common.mk As for the board, which is circled in red, this is an external power and debug adapter: adapter

WebDust21 commented 1 month ago

As for the board, which is circled in red, this is an external power and debug adapter:

kinda what I figured it was ;-)

My main goal for delving into bare metal programming of these processors is because of their LCD driver peripheral, as well as internal data bus structure.
For example, there's a very nice 7" touchscreen LCD module available from Waveshare, but it's powered by an ESP32-S3. Yes, the ESP32-S3 has an LCD driver peripheral--but it's simply unable to keep up with an 800x480 panel, barely managing a 14MHz pixel clock, equating to just under 30FPS actual panel refresh rate. (Let's not get started on the actual processing ability with LVGL...it's barely passable.)

On the page, the ESP32 appears to be a formidable processor, having a dual-core 240MHz 32-bit Tensilica Xtensa core. What's not widely published is how severely bottlenecked that processor is. Let's just say for theoretical purposes that it's running 32-bit words (technically it isn't...they're variable length instructions), and running 1 MIPs/MHz. That means that 240MIPs * 4 bytes/instruction = 960MB/s minimum theoretical data rate to keep a SINGLE core waitstate-free. (1,920MB/s for dual core.) BUT...all the firmware gets run off external FLASH. Which is connected to the ESP32 with a 4-bit bus ("QSPI") running at 80MHz. In other words, the data rate to the CPU is a truly pitiful 40MB/s, severely limiting processing power. And if you're running an 800x480 LCD panel, that's a buffer size of 768KB--which won't fit in the internal 520KB SRAM (which runs at CPU speed AFAIK...if code is run from here, it's runs blisteringly fast!) In other words, that LCD peripheral has to get all the LCD bitmap via...external PSRAM, which is running over a 8-bit bus ("OPI") also running at 80MHz.

I had someone argue with me that the ESP32 has to be much more powerful than a Pentium III CPU. And on the surface, it might seem possible...UNTIL you look at the severe bottlenecking applied to the ESP32: 40MB/s on the FLASH to the CPU. Meanwhile, that Pentium III with a 32-bit FSB running at 133MHz = 532MB/s (might double that to 1,064MB/s if DDR applies to the FSB?? I'm not sure.) This of course easily explains why "cheap Chinese tablets" run so terribly slow despite boasting quad-core 1.2GHz processors: they're severely bottlenecked on the FLASH!

All that to say that while the F1Cx00S runs at ~576MHz with this repo, the huge improvement with the F1Cx00S series over an ESP32 is that the internal DRAM likely has a 32-bit internal connection. True, the F1Cx00S has DDR1 DRAM, which is a good bit slower than the much faster DDR2 DRAM present in the V3S...but it's still a marked improvement.

Worth noting that in example videos online (and in my brief tests out of this repo here), the F1Cx00S isn't "buttery smooth" with LVGL on an 800x480 panel--but I wonder if tweaking the DRAM settings might be able to solve some of that? A lot of people say the F1Cx00S can be run up closer to 900MHz--but if the DRAM speed doesn't increase with it, that's quite pointless! (Especially when all of the firmware is being run directly out of DRAM as with this repo. Way faster than SPI FLASH, that's for sure!)

The V3S is a lot smoother due to having DDR2 DRAM.

Neothai commented 1 month ago

Today I tried to connect LVGL version 9.1.0 to this project, but it didn't work (but the older version of LVGL that came with the project worked). Can you suggest a way to achieve this? Thank you very much.

This is LVGL version 9.1.0. https://drive.google.com/file/d/1xc7xoKN24vAosIze3RxIYjHn-b1zQmcR/view?usp=sharing

This is a picture of using LVGL version 7 :) IMG20240710222730

WebDust21 commented 1 month ago

Today I tried to connect LVGL version 9.1.0 to this project, but it didn't work (but the older version of LVGL that came with the project worked). Can you suggest a way to achieve this? Thank you very much.

This is something I was planning to do at some point (plus porting TinyUSB to the V3s)--but like I said earlier up, in the bare-metal world, you're largely on your own. Bon voyage!

Neothai commented 1 month ago

It seems that my efforts are close to success. Now I can compile LVGL version 9 to F1C200S. But I ran into another problem: the display was distorted (Picture 1), and I didn't know exactly how to adjust the dispFlush() function so that the display could display normally.

Picture 1: 800*480 5-inch display using F1C200S+LVGL Version 9 powered

static void display_flush(lv_display_t *disp, const lv_area_t *area, uint16_t * px_map){
  layer[0].addr = (uint16_t*)px_map;
  disp_sync();
  lay_update(0);
  lv_display_flush_ready(disp);
}

IMG_20240711_215843_s1

Picture 2: 800*480 5-inch display using F1C200S+LVGL Version 7 (the original code that came with your example) powered

static void display_flush(lv_disp_drv_t *disp_drv, const lv_area_t *area, lv_color_t *color_p){
  layer[0].addr = color_p;
  disp_sync();
  lay_update(0);
  lv_disp_flush_ready(disp_drv);
}

IMG20240710222730_2

I'm open to hearing from all of you.😀 Thank you very much.

WebDust21 commented 1 month ago

So I have not (yet) worked in-depth with LVGL and a direct video framebuffer going to hardware.

However, there is a basic issue with the LVGL setup (even in the v7 example) that may have worked simply due to how memory was handled in LVGL v7 vs v9.

layer[0].addr = (uint16_t*)px_map;

This does NOT copy any memory: all that is being transferred is the pointer to "px_map"--which apparently LVGL is then invalidating/destroying due to LVGL setup. For this to work, you would have to configure LVGL (via "lv_conf.h") to do a FULL framebuffer, not a partial framebuffer.

The above line is assuming that LVGL is going to give us a pointer to an internally allocated LVGL framebuffer that is static (i.e. constantly/always there). Apparently this is not the case with the current v9 setup, resulting in the LCD driver getting gibberish from memory that doesn't contain the expected display framebuffer bitmap.

Two ways around that:

  1. use memcpy (or a physical FOR loop if you have to do any byteswapping) to actually copy the data from the LVGL "px_map" to the bare-metal LCD driver framebuffer (I haven't delved into the code here to see if one was actually allocated. If not, you'll need to malloc some memory for a framebuffer.)
  2. configure LVGL to utilize a FULL framebuffer, and not a partial (typical is 1/10th size) framebuffer. Double-buffered would be even better, as that way LVGL can write to one buffer while the LCD is being refreshed out of the other by the LCD peripheral. For bare-metal development, this likely will be the best solution, as it would leverage more LVGL functionality (less work for you!)

To that end, I would suggest starting here: https://docs.lvgl.io/master/porting/display.html particularly with LV_DISPLAY_RENDER_MODE_DIRECT. Note where it says "Due to this in flush_cb typically only a frame buffer address needs to be changed" -> this is what you want. That's what the above referenced line of code is doing (just changing the LCD driver's memory pointer address)...it just needs to point to a full-LCD framebuffer.

Best of luck. You're really close ;-)

Neothai commented 1 month ago

Thank you for the detailed advice. I will keep trying :)

minilogic commented 1 month ago

LVGL9 example has been added.

https://github.com/user-attachments/assets/db216dea-c39e-4bb4-ad38-d4f8491db229

WebDust21 commented 1 month ago

@minilogic Woohoo, you're the best! That's surprisingly smooth rendering behavior...I may not need to reinvent the TinyUSB wheel with the V3s after all... If I created a F1C200s replacement board for the Waveshare 7" capacitive touchscreen panel, would you be interested in some?? (The ESP32-S3 that they use is pathetically weak for anything in-depth with a panel of this size!)

minilogic commented 1 month ago

In the USBMSC HOST example, added waiting for any key press in the terminal. At this time, you need to connect the drive through the adapter. ch_usbh

WebDust21 commented 1 month ago

@minilogic Curious if there's a reason you used the LVGL partial buffer -> blit to "outside" framebuffer, instead of utilizing the LVGL full-buffer/double-buffering methodology? It's not like we're lacking for memory on the F1C200s! https://github.com/minilogic/f1c_nonos/blob/bbde37f38aaccbc5d3f34ebb7e0bae37ae4052bc/src/gui/lvgl9/main.c#L64 as you're just doing a direct memcopy from the LVGL flush callback to the framebuffer: https://github.com/minilogic/f1c_nonos/blob/bbde37f38aaccbc5d3f34ebb7e0bae37ae4052bc/src/gui/lvgl9/main.c#L29

I did a bare-metal LVGL 8 attempt with an AT91SAM9263 through RT-Thread in 2022, and ended up having to swap the Red and Blue bits between LVGL and the framebuffer due to the PCB wiring (it was an old point-of-service terminal for a laundromat)...obviously, in that case there's has to be an intermediary "correction" routine between LVGL and the destination framebuffer.

heck, what am I waiting for, maybe I should just try a double framebuffer and PR the results if they're noticeably better. (I would think we'd get even better performance if LVGL's rendering function writes directly to the destination memory, without an intermediate copy operation taking place.)

minilogic commented 1 month ago

@WebDust21 You're probably right and it's worth trying double buffering. It's a pity that I have so little free time. This damn war took away not only my home and work, but even my free time.

WebDust21 commented 1 month ago

@WebDust21 You're probably right and it's worth trying double buffering. It's a pity that I have so little free time. This damn war took away not only my home and work, but even my free time.

Understood. If only politicians could get along....the world would be a better place. I'll probably get to it before too long--your example with LVGL9 is showing considerable promise with providing a good user interface with the F1C200s.

(My goal is an updated off-grid solar system "home central" where I can view all of the device parameters on a nice touchscreen. The ESP32-S3 just ain't gonna cut it while attempting to directly drive a very tolerant 800x480 LCD panel at half refresh rate!)

Neothai commented 1 month ago

Oh, awesome! Now I'm successful. @minilogic because of the LVGL9 example you released. Thank you for everyone's dedication. Especially @minilogic who has added LVGL. Version 9 for this project

This is a beautiful result... https://github.com/user-attachments/assets/198b27fe-ee1a-400a-b201-355015a1dbd9

But now I am facing problem to add touch driver (GT911 I2C Address = 0x14) to F1C200S. (Because I am using a display with capacitive touch)

The picture shows my GT911 touch driver.

IMG_20240712_081155_2

It will be very good news if in the near future F1C200S also supports GT911 touch chip driver😀.

If anyone has any suggestions I am open to all suggestions and will be involved. Thank you again

WebDust21 commented 1 month ago

If anyone has any suggestions I am open to all suggestions and will be involved. Thank you again

https://github.com/lvgl/lvgl_esp32_drivers/blob/master/lvgl_touch/gt911.c

might be able to leverage some hints from here (although they didn't get it working): https://forum.lvgl.io/t/driving-gt911-touch-panel-with-lvgl/12057

Plus @minilogic has already implemented the F1C200s I2C driver ("TWI"), and even given an example for an NS2009 resistive touch controller (it's what's on the F1C200s board right near the LCD connector): https://github.com/minilogic/f1c_nonos/blob/main/src/twi/ns2009/main.c

All the puzzle pieces are done, they just need put together with a bit of glue ;-)

WebDust21 commented 1 month ago

It is worth noting that @minilogic already implemented I2C touch functionality in the LVGL 9 example--for the NS2009 resistive touch controller. You just need to adapt this to the GT911 requirements (from datasheet or the LVGL "ESP32 GT911 driver" code example).

pretty simple.

https://github.com/minilogic/f1c_nonos/blob/bbde37f38aaccbc5d3f34ebb7e0bae37ae4052bc/src/gui/lvgl9/main.c#L6-L21

WebDust21 commented 1 month ago

actually digging further, I realized that the "ns2009_read" call is a specialized function inside the general "twi.c"... https://github.com/minilogic/f1c_nonos/blob/bbde37f38aaccbc5d3f34ebb7e0bae37ae4052bc/drv/twi.c#L233-L298

so not as simple as it might seem from the LVGL 9 "main.c" source.

Fortunately, the basic I2C control/functionality is also present in "twi.c"; this is what you'd need to leverage for reading the GT911. (Use "ns2009_rd" as a template: that's where the low-level I2C functions are used to get data from the NS2009 into the CPU registers.)

Neothai commented 1 month ago

@WebDust21 Sorry for my late reply. I will try to do it Look, thanks for the great guidance :)

Neothai commented 1 month ago

Now I am creating a function to write-read data to register of GT911. Can you help check if this code is correct or if there are any errors?

#define GT911_I2C_SLAVE_ADDR 0x14

static void write_register(TWI_T *TWI, uint16_t reg, uint8_t *data, uint16_t len) {
    uint16_t buffer[len + 2];
    buffer[0] = (reg >> 8) & 0xFF;
    buffer[1] = reg & 0xFF;
    for (int i = 0; i < len; i++) {
        buffer[i + 2] = data[i];
    }
    twi_write_start(TWI, GT911_I2C_SLAVE_ADDR << 1, buffer[0]);
    twi_send(TWI, &buffer[1], len + 1);
    twi_stop(TWI);
}

static void read_register(TWI_T *TWI, uint16_t reg, uint8_t *data, uint16_t len) {
    uint16_t buffer[2];
    buffer[0] = (reg >> 8) & 0xFF;
    buffer[1] = reg & 0xFF;
    twi_write_start(TWI, GT911_I2C_SLAVE_ADDR << 1, buffer[0]);
    twi_send(TWI, &buffer[1], 1);
    twi_restart(TWI, (GT911_I2C_SLAVE_ADDR << 1) | 1);
    twi_recv(TWI, data, len);
    twi_stop(TWI);
}

Thank you very much.

WebDust21 commented 1 month ago

Looks like it should work.

I'd highly recommend test debugging with printf statements to indicate values at particular locations (i.e. read chip device ID, print the result -> compare to datasheet), etc. You can do a lot of useful debugging without "proper" debug tooling...just as long as you can printf from the device to indicate what's going on internally, i.e.:

https://github.com/minilogic/f1c_nonos/blob/bbde37f38aaccbc5d3f34ebb7e0bae37ae4052bc/src/twi/ns2009/main.c#L57

Neothai commented 1 month ago

Hi, now I have improved those functions again (but still not working well).

static void write_register(TWI_T *TWI, uint16_t reg, uint8_t *data, uint16_t len) {
    uint16_t buffer[len + 2];
    buffer[0] = (reg >> 8) & 0xFF;
    buffer[1] = reg & 0xFF;
    twi_write_start(TWI, GT911_I2C_SLAVE_ADDR << 1, buffer[0]);
    twi_send(TWI, buffer[1], 1);
    twi_send(TWI, data, len);
    twi_stop(TWI);
}

static void read_register(TWI_T *TWI, uint16_t reg, uint8_t *data, uint16_t len) {
    uint16_t buffer[2];
    buffer[0] = (reg >> 8) & 0xFF;
    buffer[1] = reg & 0xFF;
    twi_write_start(TWI, GT911_I2C_SLAVE_ADDR << 1, buffer[0]);
    twi_send(TWI, &buffer[1], 1);
    twi_restart(TWI, (GT911_I2C_SLAVE_ADDR << 1) | 1);
    twi_recv(TWI, data, len);
    twi_stop(TWI);
}

To make sure the code I wrote to register to GT911 is correct. Because I'm most familiar with the I2C commands of ArduinoESP32. So I have adapted some code to ESP32. Arduino and then test it with I2C of ESP32. The code seems to work fine.

Result of message printed via Serial terminal of ESP32

GT911 initialized, ID: 911
regState: 000000
0
bufferStatus: 0, proximityValid: 0, haveKey: 0

regState: 000000 <- When not touching on the display
0
bufferStatus: 0, proximityValid: 0, haveKey: 0

regState: 0x0083 <- When touching 3 point on the display
3
bufferStatus: 1, proximityValid: 0, haveKey: 0

regState: 0x0083
3
bufferStatus: 1, proximityValid: 0, haveKey: 0

regState: 0x0081 <- When touching 1 point on the display
1
bufferStatus: 1, proximityValid: 0, haveKey: 0

Full code -> GT911_ESP32Code

But for F1C200S it seems to work. But it doesn't work.

Result of message printed via Serial terminal of F1C200S.

GT911 OK
GT911 initialized, ID: 911
regState: 0x0080 <- To touch or not to touch on the display It shows a message like this.
Tnum: 0
bufferStatus: 1, proximityValid: 0, haveKey: 0
regState: 0x0080
Tnum: 0
bufferStatus: 1, proximityValid: 0, haveKey: 0
....

Full code -> GT911_F1C200SCode

WebDust21 commented 1 month ago

Are you running the ESP32 and F1C200s test code on the exact same GT911 sensor?

Neothai commented 1 month ago

Are you running the ESP32 and F1C200s test code on the exact same GT911 sensor?

That's right, I'm using the same GT911.

Neothai commented 1 month ago

Now I'm not sure if the GT911's write-to-register function works well. But the main problem I noticed was the readout function of my GT911. If I read the ID of the GT911 chip it returns "911" which is the same correct result as the ESP32 reads.

Use this code

uint8_t productId[4]; // <-----
read_register(TWI0, GT911_PRODUCT_ID1, productId, 4);

if(!twi_error){
 printf("GT911 OK\n");
 printf("GT911 initialized, ID: %c%c%c%c\n", productId[0], productId[1], productId[2], productId[3]);
}

But what if I read out the touch data using these codes? Even if I touch only one point, many points, or none at all, The returned values ​​are no different.

// These codes are in loops.

uint8_t pointInfo;
read_register(TWI0, GT911_POINT_INFO, &pointInfo, 1);
printf("regState: %#06x\n", pointInfo);

uint8_t touch_num = pointInfo & 0x0f;
printf("Tnum: %d\n", touch_num);

uint8_t bufferStatus = pointInfo >> 7 & 1;
uint8_t proximityValid = pointInfo >> 5 & 1;
uint8_t haveKey = pointInfo >> 4 & 1;
printf("bufferStatus: %d, proximityValid: %d, haveKey: %d\n", bufferStatus, proximityValid, haveKey);

write_register(TWI0, GT911_POINT_INFO, 0, 1);
delay(5);
static void write_register(TWI_T *TWI, uint16_t reg, uint8_t *data, uint16_t len) {
    uint16_t buffer[len + 2];
    buffer[0] = (reg >> 8) & 0xFF;
    buffer[1] = reg & 0xFF;
    twi_write_start(TWI, GT911_I2C_SLAVE_ADDR << 1, buffer[0]);
    twi_send(TWI, &buffer[1], 1);
    twi_send(TWI, data, len);
    twi_stop(TWI);
}

static void read_register(TWI_T *TWI, uint16_t reg, uint8_t *data, uint16_t len) {
    uint16_t buffer[2];
    buffer[0] = (reg >> 8) & 0xFF;
    buffer[1] = reg & 0xFF;
    twi_write_start(TWI, GT911_I2C_SLAVE_ADDR << 1, buffer[0]);
    twi_send(TWI, &buffer[1], 1);
    twi_restart(TWI, (GT911_I2C_SLAVE_ADDR << 1) | 1);
    twi_recv(TWI, data, len);
    twi_stop(TWI);
}

From what I've observed Found that if I read data from GT911 into an array like uint8_t productId[4]; The resulting data will look good. But if I read non-array data like uint8_t pointInfo; The results will look strange.

Do you think I2C of F1C200S is normal? Or is it the code itself that may have some bugs?

Thank you

WebDust21 commented 1 month ago

Do you think I2C of F1C200S is normal?

Of course. This is one of the most basic chip functions, so likelihood of fault with it is extremely low--plus @minilogic showed successful use of the Allwinner I2C with the NS2009 chip, proving functionality.

Or is it the code itself that may have some bugs?

From what I've observed Found that if I read data from GT911 into an array like uint8_t productId[4]; The resulting data will look good. But if I read non-array data like uint8_t pointInfo; The results will look strange.

yeah, you need a basic understanding of C functionality, the difference between passing pointers and variables as arguments, etc. That's the root of the issue here.

Take a look here:

static void write_register(TWI_T *TWI, uint16_t reg, uint8_t *data, uint16_t len) {

Notice that "data" is defined as a POINTER--that's what the asterisk means.

You can't just pass "0" to it, as that'll be interpreted as MEMORY ADDRESS 0, not a value of zero. Memory address 0 actually points to the F1Cx00s Boot ROM, so it definitely isn't going to contain a VALUE of 0.

Thusly the following code:

write_register(TWI0, GT911_POINT_INFO, 0, 1);

writes one byte from ADDRESS "0" (0x00000000) to the chip. It does NOT write a VALUE of 0 to the chip. And that is because the function argument is defined with an asterisk, i.e. argument is defined as a memory pointer.

So I presume the GT911 needs this register reset every time you loop through, otherwise it won't update. And that's causing the issue--because what's being written isn't valid. Because the "value" argument in the function is defined as a POINTER, therefore we must pass it a variable ADDRESS, not a value. Like this:

uint8_t val = 0;
write_register(TWI0, GT911_POINT_INFO, &val, 1);

where the function writes ONE byte from the address of "val".

Notice that this stipulation is due to the function definition. However, the function definition is not at fault: defining a function argument as a pointer ("*") allows you to tell it to "write 17 bytes from this memory address". This is what happens when you pass the function an array: the C compiler automatically sends the function the array address.
Remember: in basic C functionality, anything more than a 32-bit value (in this case, with this processor) cannot be sent as an argument, as it won't fit in a CPU register. For example, in this part of the code, the address of "pointInfo" is sent as an argument.

uint8_t pointInfo;
read_register(TWI0, GT911_POINT_INFO, &pointInfo, 1);
printf("regState: %#06x\n", pointInfo);

Notice that "pointInfo" isn't an array. But it's being passed to the "read_register" call with an "&" symbol: this forces the compiler to pass the ADDRESS of "pointInfo" instead of its value, and the function reads one byte from that address. (If you remove the "&", the processor likely will crash/fault or go haywire as the function writes to a random memory location. Little things like this can be the most frustrating to figure out.)

Neothai commented 1 month ago

@WebDust21 Thank you for the detailed explanation. I will follow your advice.

Neothai commented 1 month ago

From your latest advice @WebDust21 I'm about to reach another level of success. And now I can read the number of points touched on the touch pad.

Thank you very much.

WebDust21 commented 1 month ago

It's the little things that make the biggest difference sometimes.

Neothai commented 1 month ago

Now I've integrated it with LVGL. V9 is complete. It works well

https://github.com/user-attachments/assets/16611c3d-e4ba-43db-976a-1521b787b751

Thank you very much for everyone's advice.

WebDust21 commented 1 month ago

Now I've integrated it with LVGL. V9 is complete. It works well result1.mp4

Thank you very much for everyone's advice.

It's surprisingly responsive--which is quite nice. After switching to a double-buffering modus to simplify the code further, there may not be any need to pursue the V3S for me; I personally don't like "jittery" or clearly underpowered HMI interfaces--but this looks quite decent.

WebDust21 commented 1 month ago

just look at the horrid jitter on the "page swipe" here on the much-hyped ESP32-P4: https://youtu.be/txV9y1Eo2vM?si=CARx69g3gJwBjjea&t=19

A brand-new 2024 processor solution? Ugh!

Neothai commented 1 month ago

just look at the horrid jitter on the "page swipe" here on the much-hyped ESP32-P4: https://youtu.be/txV9y1Eo2vM?si=CARx69g3gJwBjjea&t=19

A brand-new 2024 processor solution? Ugh!

As far as I know It looks like this ESP32-P4 has a much higher price than the F1C200S, haha...


However, now I am planning to enhance the F1C200S by adding multitasking functions such as FreeRTOS would be great. ESP32 HMI users who are annoyed by its GUI and its "very slow response" ESP32 users should be interested in the F1C200S as it is both cheaper and has better performance.

How interesting do you think this enhancement to the F1C200S is? And is there a possibility?

WebDust21 commented 1 month ago

However, now I am planning to enhance the F1C200S by adding multitasking functions such as FreeRTOS would be great.

You'd better be a C/C++ coding whiz to attempt that. Porting FreeRTOS is not something to be taken lightly...at all. If getting LVGL working was a struggle...umm...you'd better have a really good support team and resources outside of this repository and issue.

Something perhaps more accessible might be to utilize RT-Thread and the allwinner-tina section (that's the F1Cx00s, just they don't want to identify it for some reason): https://github.com/RT-Thread/rt-thread/tree/master/bsp/allwinner_tina

Heck, @minilogic utilized RT-Thread as a resource for this repository anyway: image

RT-Thread is a bare-metal RTOS out of the box, so that's sorted. While it has big goals about being able to "import all these libraries" (including LVGL), what's badly missing is all the interconnect/glue logic and the like to make said libraries an "easy integration."
My attempts to create RT-Thread microPython bindings for LVGL 7 were a very frustrating exercise. While I did succeed in regenerating the QSTRdefs so you could run very simple microPython LVGL scripts, I very quickly hit some solid roadblocks with bugs in the RT-thread microPython implementation. (Any sort of C -> microPython callback resulted in the processor hanging.)

And if your end goal is to just to "get a bazillion different functionalities implemented", then just quit while you're ahead and utilize a minimal Linux system. All the work is already done.

Neothai commented 1 month ago

Porting FreeRTOS is not something to be taken lightly...at all.

I think so because when I purchased the F1C200S development board, the seller gave me this data file. It looks like FreeRTOS can be used with the F1C200S.

This is the file I got. https://drive.google.com/drive/folders/1oN78ScOT-NRfIxU-GsmNyye6aQhGp3UZ?usp=sharing

Neothai commented 4 weeks ago

Hello everyone, Now I have a little doubt with these functions. What is the difference between the sd_init(); and sd_card_init() functions? So how do I get the size of the SD?

Thank you very much