Open Neothai opened 2 months 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:
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.
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.
Thank you for your reply.
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)
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:
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:
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.
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 :)
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!
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);
}
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);
}
I'm open to hearing from all of you.😀 Thank you very much.
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:
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 ;-)
Thank you for the detailed advice. I will keep trying :)
LVGL9 example has been added.
https://github.com/user-attachments/assets/db216dea-c39e-4bb4-ad38-d4f8491db229
@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!)
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.
@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.)
@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 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!)
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.
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
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 ;-)
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.
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.)
@WebDust21 Sorry for my late reply. I will try to do it Look, thanks for the great guidance :)
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.
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.:
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
Are you running the ESP32 and F1C200s test code on the exact same GT911 sensor?
Are you running the ESP32 and F1C200s test code on the exact same GT911 sensor?
That's right, I'm using the same GT911.
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
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 likeuint8_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.)
@WebDust21 Thank you for the detailed explanation. I will follow your advice.
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.
It's the little things that make the biggest difference sometimes.
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.
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.
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!
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?
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:
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.
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
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
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.