-
Notifications
You must be signed in to change notification settings - Fork 41
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
ESP32 How to access UART1? #57
Comments
As I learn more I see there is a C-to-Forth gateway mechanism, however as I am completely new to this, I wonder if it would be possible to give a quick example? |
1 similar comment
As I learn more I see there is a C-to-Forth gateway mechanism, however as I am completely new to this, I wonder if it would be possible to give a quick example? |
As I learn more I discovered there is a C-to-Forth gateway mechanism as mentioned in the ForthHub/discussion, however as I am completely new to this, I wonder if it would be possible to give a quick example? |
I thought that I replied to this yesterday via email but apparently my reply didn't get added to the thread. In each subdirectory of cforth/src/app/, for example cforth/src/app/esp32, there is a file named extend.c which contains C code that you can call from Forth. You can look in any such extend.c file for examples. You can put your own C functions there, and you can also call functions from whatever framework happens to be used - for example from esp-idf / freertos for the ESP32 build. At the end of extend.c there is a ccalls table that maps from C to Forth. Here's an example of a table entry:
That entry creates a Forth word named "i2c-write-read" that calls a C function named "i2c_write_read". The C function's prototype is
The stack diagram for the Forth word is:
Note that the order is backwards - reflecting the way that arguments are actually pushed on the stack in C. Inside the { ... } list that defines the call gateway, the first character of every item must be either "i" - meaning a number, "a" - meaning an address, or "$" - meaning a string. An item beginning with "-" separates inputs from outputs. Since C functions can have only 0 or 1 return value, there can be at most one output. If an input item starts with "$", a Forth "adr len" string will be converted to a C null-terminated string before passing it to the C function. For C functions that you define yourself in extend.c, you do not necessarily need a prototype because the definition exists before the ccalls table. For functions that you want to call from an external library, you need to provide a prototype inside extend.c (or in a .h file that it includes). You can do that by including .h files from the framework, or you can provide a simplified prototype of your own creation. Including the framework's .h file is more correct, but it can lead to a nightmare of include dependencies, so sometimes it is prudent to fake it with an abbreviated prototype like:
That prototype is not "correct" - that routine's actual return value is "int" and it has an argument of type "adc1_channel_t channel" - but it works anyway. The reason it works is because no actual C code to directly call the function is generated. Instead, the address of the function is added to an array. At run time, Forth uses information in the { ... } list to pull items from the Forth stack, marshal them as C function arguments, and call the function from the table. For your specific problem, there is some code in esp-idf that may be helpful. Look in esp-idf/components/driver/test/test_uart.c to see how to use the UART functions that esp-idf provides. You can add entries for those functions in src/app/esp32/extend.c |
Off-topic; there have been reports of GitHub being down or misbehaving, especially in the past couple of hours. I didn't get a notification for any reply yesterday, and got only one notification for @TJ-C 's second, third, and fourth comments today. I suspect those comments are artefacts of outage. Nice write-up, thanks! |
Thanks for the detailed write up, I have now added all the UART calls and compiled successfully. Now I just have to find all those hard to find API constants to populate the values. :D Apologies for all the repeated notifications, GitHub was very slow at the time and repeatedly told me my comment had failed. I was surprised to find they had got through. |
Quick question: How do I send a null pointer from cforth to C? Answer: According to a number of articles NULL in C is just 0, so in forth 0 constant NULL should work. From Kolban ESP32 book
One of the options we can specify when initializing a driver is to supply a FreeRTOS queue handle. If we supply this, then events that are detected by the UART are then posted onto the queue. We can have tasks that are blocked watching the queue ready to process incoming events when they arrive. This allows us to perform UART data processing asynchronously. If we don't want to use a queue, we specify NULL for the queue parameter. |
A null pointer is just the number 0. It is useful to distinguish (int)0 from (void *)0 (== NULL) in C source for type checking purposes, but at the core, a zero is a zero is a zero. CForth explicitly uses a cell size that is the same size as a pointer so stuff like this - and also access to memory-mapped IO devices - works correctly. |
I'm struggling with passing 8-bit address pointers, which has probably got a lot to do with my lack of C and Forth skills. All my working files are here. Originally I was just going to take the esp-idf api and code the interface, which worked Ok until I got to:
And in forth:
I also tried calling the functions in my t-board-interfaces.c
As soon as I try to read from the uart it just crashes the system.
Also, you are using # in front of numbers, what does '#' do? Thank you. |
|
Thanks. It turns out putting comments in the calls[] table caused some weird behaviour resulting in the wrong function to be called. |
Sorry I didn't reply earlier. You message from 4 days ago go buried in an email thread display and I missed seeing it. |
Hi Mitch,
Thanks to the explanations I found here I was able to add For esp_clk_cpu_freq worked after using: esp_set_cpu_freq was a bit more complicated, after: Since there are a few more calls to the OS on my list I would like to know what NOTE: Please ignore I just found interface.h (Sorry) |
Just FYI, there are these lines in src/app/esp32/targets.mk
You can extend that list if you need other include directories to pick up other include dependencies. |
How do I access UART1 do I need to code new words to talk directly with the hardware, or are their words already available ( I have looked, but couldn't see anything obvious)?
Does forth run inside freertos, or is it bare metal?
Many thanks.
The text was updated successfully, but these errors were encountered: