robert-hh / micropython

MicroPython - a lean and efficient Python implementation for microcontrollers and constrained systems
https://micropython.org
Other
14 stars 4 forks source link

docs: W600 Timer API differs from micropython standards #22

Closed jkorte-dev closed 6 months ago

jkorte-dev commented 7 months ago

Checks

Documentation URL

No response

Description

Hi Robert,

I have tested various functionalities of the w600 port and everything works perfectly. But I struggled a bit with the timer because setting up the timer differs from the micropython documentation.

I could successfully set up timers with: from machine import Timer tim1 = Timer(1) tim2 = Timer(2) tim1.init(Timer.ONE_SHOT, period=5000, callback=lambda t:print(1)) tim2.init(Timer.PERIODIC, period=1000, callback=lambda t:print(2))

by obmitting the 'mode' variable name. Also variable name freq seems not to be supported. Is this deviation of the micropython standard (documented here https://docs.micropython.org/en/latest/library/machine.Timer.html#machine-timer) intended?

Anyway it it a great port. Are there any plans to merge to mainline micropython?

Thank you very much Joerg

rkompass commented 7 months ago

I assume @robert-hh didn't notice your issue. Usually he is very responsive. If he agrees I could try to code the necessary small changes and post here.

Are there any plans to merge to mainline micropython?

As much as I would support this, having a port in mainline is a permanent increase of responsibility and maintenance work. Damien responded once earlier on this request negatively (I don't have the link to this at hand). The port was not in the good shape it is now in then. One of the prerequisites demanded iirc was the availability and active support of the SDK, which is not there. Winner stopped the work on it, some of the descriptions we had to translate to english even. It seems Winner switched their work to the w800 series, which are mostly the same but have a different (chinese) processor architecture inside (perhaps there was a license issue with ARM?). A second prerequisite is a permanent availability of the chips and boards, which is also questionable now. It might be there is only remaining stock still available.

jkorte-dev commented 7 months ago

Hi @rkompass , thank you very much for your remarks. I fully understand Damien's points, but the port has evolved and seems to be in good condition now, and has found a maintainer. That's why I asked. But yes, availability of hardware and support for the SDK are questionable. It is said but understandable. I really like micropython but I was wondering that there are so many forks of micropython making it for beginners really hard. Thank you

robert-hh commented 7 months ago

Sorry, that must have skipped my attention. About your questions: The arguments can be given with keyword and without keyword, but the in the order mode, period, callback. That is common to all machine.Timer implementations. The freq argument is not supported at the W600 port, and generally not by all MicroPython ports. There is a note at the start of the documentation that not all ports implement all features. It is not difficult to support the freq=nn argument, but the resolution of the timer would stay ms, with theoretically 1 ms as the shortest period. So skipping the freq arguments gives a more consistent result. b.t.w. Since the W600 is not a performance monster, any period below 10ms is questionable.

Note about MicroPython: There are two major ports: a) the genuine MicroPython at micropython.org, and b) The port by Adafruit. There was a commercially maintained port by Pycom, but Pycom closed it's operation. There are quite a few ports by board vendors, like XBEE, Seeed, ..., but these are usually not well maintained.

jkorte-dev commented 7 months ago

Thank you for your reply. I managed to use the Timer (so no need to waste your time on this for me), but from the explanations you gave I still think there is something odd, or I do not have the latest version, or I just made a stupid mistake. Anyway here is my observations:

import time
from machine import Timer

tim1 = Timer(1)
tim1.init(Timer.ONE_SHOT, 1000, lambda t:print('msg from timer', 1))
print("Timer 1 startet")

tim2 = Timer(2)
tim2.init(mode=Timer.ONE_SHOT, period=1000, callback=lambda t:print('msg from timer', 2))
print("Timer 2 startet")

tim3 = Timer(3)
tim3.init(Timer.ONE_SHOT, period=1000, callback=lambda t:print('msg from timer', 3))
print("Timer 3 startet")

try:
    while True:
        time.sleep_ms(1)
except KeyboardInterrupt:
    print("Interrupted deinit timer")
    tim1.deinit()
    tim2.deinit()
    tim3.deinit()

Output:

MPY: soft reboot
Timer 1 startet
Timer 2 startet
Timer 3 startet
msg from timer 1
msg from timer 3

=> the message from Timer 2 is missing.  It looks to me that "mode=" is causing the timer not to start.

robert-hh commented 7 months ago

Thanks. You are right. There was an omission in the code. It required at least one positional argument. Will be fixed. The fix is changing line 89 of machine_timer.c into: if (n_args > 0 || kw_args->used > 0) {

robert-hh commented 7 months ago

The source code and the binaries are updated.

jkorte-dev commented 7 months ago

It works :-) Thank you

rkompass commented 7 months ago

Since the W600 is not a performance monster, any period below 10ms is questionable.

For checking this I wanted to measure the accuracy of machine.Timer and apparently found a bug:

from machine import Timer
from time import ticks_us, ticks_diff

tim = Timer(-1)                 # Software timer
# tim = Timer(1)                 # Hardware timer
N_Runs = 203
Period_ms = 10

Period_us = 1000 * Period_ms
t_now = 0
i_now = 0
tdif = []

# @micropython.viper
def tim_measure(t):
    global t_now, i_now
    t_now = ticks_us()
    i_now += 1
    # print('now:', i_now)

tim.init(mode=Timer.PERIODIC, period=Period_ms, callback=tim_measure)
t_then = ticks_us()
i_upd = 0

while i_upd < N_Runs:
    # print(i_now, i_upd)  #  !!!!! <--   the changes in i_now and i_upd seem not to be registered here
    if i_now > i_upd:
        tdif.append(ticks_diff(t_now, t_then)-Period_us)
        t_then = t_now
        i_upd += 1

tim.deinit()
print(tdif[0:3])
tdif[0:2] = []
tdif.sort()
print('Deviations (us) lowest:', tdif[0:10])
print('Deviations (us) highest:', tdif[-11:-1])

# Result with RP2040: MP v1.19.1-919-g14b49a651
# Deviations (us) lowest: [-8, -6, -5, -5, -5, -5, -5, -5, -5, -5]
# Deviations (us) highest: [5, 5, 5, 5, 5, 5, 6, 7, 7, 7]

A periodic time measurement and update of a counter variable is made. Simultaneously the value of this variable is compared in a while loop in the main program. But the change of it is not noticed.

Robert: This reminds me of some problem we had with soft timer. Somehow a sleep was necessary to function??? I tried it and: Yes:

. . .
while i_upd < N_Runs:
    # print(i_now, i_upd)  #     the changes in i_now and i_upd seem not to be registered here
    sleep_ms(1)            # it needs this sleep to register the changes
    if i_now > i_upd:
. . .

inserting it allows the program to work.

Result: with N_Runs = 2003 Period_ms = 5

[-109, -1008, -1000]
Deviations (us) lowest: [-1291, -1225, -1225, -1218, -1218, -1218, -1218, -1218, -1140, -1133]
Deviations (us) highest: [-867, -867, -860, -782, -782, -782, -782, -782, -775, -775]

with N_Runs = 2003, Period_ms = 10

[1041, -9, 0]
Deviations (us) lowest: [-3, -3, -3, -3, -3, -3, -3, -3, -3, -3]
Deviations (us) highest: [3, 3, 3, 3, 3, 3, 3, 3, 3, 3]

probably the last is illusory precision as the tick_us is updated in a similar imprecise manner as the timer callback.

So your statement regarding the timer periods seems right.

But I think the not-noticing of the changed variable is not acceptable.

robert-hh commented 7 months ago

As far as I recall, the internal tick resolution of the W600 RTOS is 2 ms. Task switches happen at that rate. That definitely applies to software timers. The hardware timer should run at a 1ms resolution, but in the test the results are way worse, like in the range of -227 to 211 ms. But at least not affected by a missing sleep_ms(). So maybe the IRQ priority of the hardware timer must be raised when set active. About the need to enter sleep_ms() or idle() into the loop: a tight loop will block the runtime from scheduling other MP tasks, like in this case the software IRQ handler. Tha#s done by calling mp_handle_pending(true), as being part of the MICROPY_EVENT_POLL_HOOK macro, which in turn is part of time.sleep_ms() and idle().

rkompass commented 7 months ago

I observed that in the while loop the if i_now > i_upd: is not executed as true, because increments of i_now in the callback are not registered.

_When I stopped the running program (with Ctrl-C) then I observed that i_now had a value of > 400._

So the IRQ priority of the timer was high enough obviously. i_now could not have got this value after the program stop. One may conclude that the tight loop had not blocked the runtime from scheduling the callback.

So the variable change of i_now simply was not noticed within the loop.

Is there something else that sleep_ms(1) achieves in this respect, that print() doesn't ?

If it's about the MICROPY_EVENT_POLL_HOOK macro: Is there something else in this macro that leads to a re-actualization of variables that belongs into the while statement?

rkompass commented 7 months ago

Btw.: I noticed that the freq argument in the timer now is usable.

robert-hh commented 7 months ago

When I stopped the running program (with Ctrl-C) then I observed that i_now had a value of > 400.

When you stop the program with Ctr-C, the timer continues to run. But at the REPL prompt when waiting for a character, MICROPY_EVENT_POLL_HOOK is called.

rkompass commented 7 months ago

You are right. The interrupts did not happen. I checked that by letting the LED flicker. They flickered after a Ctrl-C only and so the variable i_upd in the above script was incremented afterwards.

Still the w600 exhibits strange behaviour: Only this platform requires a sleep_ms() in the tight while loop for the timer interrupts to happen. Other platforms: 'rp2', 'mimxrt', 'esp8266', and 'esp32' all let the interrupts happen.

I improved the test script a bit:

from machine import Pin, Timer
from time import ticks_us, ticks_diff, sleep_ms
from sys import platform

if platform in ['rp2', 'w600', 'mimxrt']:
    led = Pin("LED", Pin.OUT, value=1)
elif platform in ['esp8266', 'esp32']:
    led = Pin(2, Pin.OUT, value=1)

if platform == 'mimxrt':
    N_Runs = 83                 # on Teensy there is no print to USB after longer inactivity --> 2s only
else:
    N_Runs = 403                # 10 seconds total
Period_ms = 25                  # flicker of 20 Hz (recognizable)

Period_us = 1000 * Period_ms
t_now = 0
i_now = 0
tdif = []

# @micropython.viper
def tim_measure(t):
    global t_now, i_now
    t_now = ticks_us()
    i_now += 1
    led(not led())              # esp8266, esp32 don't have led.toggle()

tim = Timer(-1)                 # Software timer
tim.init(mode=Timer.PERIODIC, period = Period_ms, callback=tim_measure)

t_then = ticks_us()
i_upd = 0

try:
    while i_upd < N_Runs:
        # sleep_ms(1)            # it needs this sleep to register the changes only on w600
        if i_now > i_upd:
            tdif.append(ticks_diff(t_now, t_then)-Period_us)
            t_then = t_now
            i_upd += 1
finally:
    # tim.init(callback=None)
    tim.deinit()
    led(1)
    print('i_now:', i_now)
    print('tdif[0:3]:', tdif[0:3])
    tdif[0:2] = []
    tdif.sort()
    print('Deviations (us) lowest:', tdif[0:10])
    print('Deviations (us) highest:', tdif[-11:-1])

Now one observes the LED flicker, if the timer interrupts are happening. Also at Ctrl-C immediately a print of the i_now variable is done.

Could it be that in an ordinary tight while loop internally still a mp_hal_delay_us() is inserted? With the other platforms a mp_hal_delay_us() with sufficient delay includes mp_handle_pending(true) . With the w600 this is not the case.

robert-hh commented 7 months ago

rp2 and mimxrt are not based on a RTOS. There the timer callbacks a scheduled through a PENDSV interrupt handler. Besides that there is only the MicroPython "task". ESP32 and ESP8266 are based on an RTOS, and they seem to handle it better. But they have too a problem with tight loops, albeit not that critical. As far as I know, Python code is executed the same on all ports. There should be no mp_hal_delay_us(), and I see none. But I have something in mind that it checks for pending tasks between statements. The interesting thing is: If I disable threading, the results for using the hard timer are quite good:

>>> import timertest
Deviations (us) lowest: [-9, -8, -8, -8, -7, -7, -7, -6, -6, -4]
Deviations (us) highest: [4, 4, 5, 5, 5, 5, 6, 6, 6, 7]

Compared to values in the range of -60 to +60 with threading. Maybe we should disable it by default.

rkompass commented 7 months ago

I find mp_handle_pending(true) in py/vm.c at line 1313 ff. where it is called under certain conditions at the end of every instruction. At least that is my current understanding.

pending_exception_check:
                // We've just done a branch, use this as a convenient point to
                // run periodic code/checks and/or bounce the GIL.. i.e.
                // not _every_ instruction but on average a branch should
                // occur every few instructions.
                MICROPY_VM_HOOK_LOOP

                // Check for pending exceptions or scheduled tasks to run.
                // Note: it's safe to just call mp_handle_pending(true), but
                // we can inline the check for the common case where there is
                // neither.
                if (
                #if MICROPY_ENABLE_SCHEDULER
                #if MICROPY_PY_THREAD
                    // Scheduler + threading: Scheduler and pending exceptions are independent, check both.
                    MP_STATE_VM(sched_state) == MP_SCHED_PENDING || MP_STATE_THREAD(mp_pending_exception) != MP_OBJ_NULL
                #else
                    // Scheduler + non-threading: Optimisation: pending exception sets sched_state, only check sched_state.
                    MP_STATE_VM(sched_state) == MP_SCHED_PENDING
                #endif
                #else
                    // No scheduler: Just check pending exception.
                    MP_STATE_THREAD(mp_pending_exception) != MP_OBJ_NULL
                #endif
                #if MICROPY_ENABLE_VM_ABORT
                    // Check if the VM should abort execution.
                    || MP_STATE_VM(vm_abort)
                #endif
                ) {
                    MARK_EXC_IP_SELECTIVE();
                    mp_handle_pending(true);
                }

and either it is not called there for some reason or it is not effective. Even if compiled with MICROPY_PY_THREAD ?= 0 the above test script fails (no interrupts in the while loop). If I comment all conditions out and change the if to a if(1) before MARK_EXC_IP_SELECTIVE(); mp_handle_pending(true); then I still get the same behaviour.

So there must be a different reason the w600 port behaves different from esp8266/esp32.

rkompass commented 7 months ago

The interesting thing is: If I disable threading, the results for using the hard timer are quite good:

I just confirmed this (same measurements) and only now realize: The mp_handle_pending(true); in vm.c is fine. The problem is not in the tight while loop not allowing interrupts but in the software type of interrupt.

How are software timer interrupts handled at all?

robert-hh commented 7 months ago

AFAIK, software timers are handled in the RTOS by adding a timer event into a list of timers. Whenever that event happens, a callback for this timer is called (machine_soft_timer_callback()), which schedules a MP task. Same mechanism as for hardware timers. The second part should work. So maybe the timer task of the OS does not get scheduled or the tasks initiated by the timer task never get scheduled. Scheduling of OS task is a little bit critical. It seems not to happen per se. To support it, there is the tls_os_time_delay(1) call in MICROPY_EVENT_POLL_HOOK, which forces a task switch. Some other problem is, that in case of non-working soft timer in the test code Ctrl-C does not stop the timer. There seem still many tasks pending.

robert-hh commented 7 months ago

I could get the soft time to fire without idle() .. by increasing the priority of the timer task. It was 1. Changing it to 32 made the difference. Low numbers mean low priority. The MPY task runs at level 33, the FTPS runs at level 32. Edit: At level 33 the numbers are:

Deviations (us) lowest: [-4, -4, -4, -4, -4, -4, -4, -4, -4, -4]
Deviations (us) highest: [4, 4, 4, 4, 5, 5, 5, 6, 7, 8]

But only if WiFi is not active. With Wifi the numbers are with and without idle():

Deviations (us) lowest: [-2696, -2588, -2549, -645, -594, -574, -208, -112, -107, -104]
Deviations (us) highest: [103, 103, 104, 110, 218, 486, 591, 661, 2516, 2596]

Hard timer + Wifi:

Deviations (us) lowest: [-1553, -1541, -1541, -1540, -1532, -705, -19, -18, -18, -17]
Deviations (us) highest: [15, 15, 17, 17, 20, 724, 1540, 1543, 1550, 1550]
robert-hh commented 7 months ago

Unfortunately, the file FreeRTOS-h to change the priority are not part of the MP tree, but are in the RTOS tree. That makes maintenance of the port a little bit more complicated.

rkompass commented 7 months ago

It (the priority of the timer task) was 1. Changing it to 32 made the difference. .. . The MPY task runs at level 33, the FTPS runs at level 32.

My findings are:

With software timer and TIMER_TASK_PRIORITY = 32, no wifi
Deviations (us) lowest: [-1179, -1137, -1137, -1136, -1102, -1102, -1102, -1102, -1102, -1102]
Deviations (us) highest: [-898, -898, -897, -897, -897, -897, -896, -862, -861, -860]

With software timer and TIMER_TASK_PRIORITY = 33, no wifi
Deviations (us) lowest: [-1009, -1007, -1007, -1007, -1007, -1007, -1007, -1007, -1007, -1007]
Deviations (us) highest: [-996, -996, -996, -996, -995, -995, -994, -994, -994, -994]

With hardware timer and TIMER_TASK_PRIORITY = 33, no wifi
Deviations (us) lowest: [-6, -6, -6, -6, -6, -5, -5, -5, -5, -5]
Deviations (us) highest: [4, 4, 4, 4, 5, 5, 5, 5, 5, 5]

With software timer and TIMER_TASK_PRIORITY = 32, wifi active
Deviations (us) lowest: [-3576, -3562, -3557, -3554, -3442, -1614, -1560, -1558, -1558, -1556]
Deviations (us) highest: [-427, -426, -425, -424, -424, -382, 1574, 1575, 1577, 1577]

With software timer and TIMER_TASK_PRIORITY = 33, wifi active
Deviations (us) lowest: [-3566, -3563, -3562, -3562, -3557, -3552, -3544, -3543, -1654, -1561]
Deviations (us) highest: [-423, -423, -327, 1463, 1570, 1574, 1577, 1577, 1578, 1581]

With hardware timer and TIMER_TASK_PRIORITY = 33, wifi active
Deviations (us) lowest: [-2142, -2136, -2031, -1026, -1019, -1000, -489, -431, -152, -151]
Deviations (us) highest: [53, 172, 173, 435, 493, 1038, 1042, 1045, 2052, 2153]

That is very good news! Another little hickup of the w600 port is removed! How did you get there? Is that the way esp8266 and esp32 do it?

The wifi seems to have a higher priority even than the hardware timer.

TIMER_TASK_PRIORITY 32 or 33 seems to make no difference.

Now that this problem is solved it seems the 1ms delay in the MICROPY_EVENT_POLL_HOOK can be removed again? What do you think?

Ideally we would have a MP version tightly integrated with FreeRTOS, where task priorities could be set in MP, e.g. in defining the timer. Where the FreeRTOS tasks somehow would be MP tasks and not the MP a task in FreeRTOS.

rkompass commented 7 months ago

To be more precise:

robert-hh commented on Jun 18, 2023 That does not sound right. At the moment I changed MICROPY_EVENT_POLL_HOOK to include a call to tls_os_time_delay(1) instead of __WFI(). That will slow down each call to MICROPY_EVENT_POLL_HOOK by 500µs in average, but will force a context switch. I do not know why the other versions did not work. I have to see, if I can find a reason, but not now.

could be reverted, I think, as the problem is solved now.

robert-hh commented 7 months ago

How did I find it: After it was evident, that the soft timer callbacks were not called and that the soft timer runs as separate task, I scanned though the SDK code for the placement where the soft timer task was started and the priority was set. The only thing I do not like is the fact, that the priority cannot be configured in a header file of a project, which is included into the RTOS build. That is something to be solved. Ideally, MicroPython should not require changes to the SDK. And where that happened in the past, I move the respective files to the MP directory.

I have to test, whether the delay in MICROPY_EVENT_POLL_HOOK can be removed. There are more tasks than MicroPython and Timer, and removing it did not help with the timer task. So the whole subject is not yet finished. I do not know how ESP32 or ESP8266 handle this.

robert-hh commented 7 months ago

I've remove the delay in MICROPY_EVENT_POLL_HOOK and everything seems to work. While testing I noticed a problem in threading. When a thread terminates, the system freezes. That did not happen when threading was initially added. It is related to memory management. So I'll have to find a fix. About the timer task priority. This is a catch 22 situation. I want to avoid setting the priority in FreeRTOS.h. So I considered increasing the priority later in the MicroPython startup sequence. There is a RTOS call allowing this, bit it needs the handle of the timer task. There is a RTOS API to get this handle, but it is disabled by default. Enabling it needs to change ........ FreeRTOS.h. I recall that you one had made a little program to get a list of tasks. Maybe I can use that method to find the timer task handle. Do you still have that code?

rkompass commented 7 months ago

Its here:

I compiled a new command in:

w600.rtos_disp_task_stat_info()

task        task status stack total stack remain    stack least remain
33      R       8192        7112        6132    
63      R       360     272     272 
62      B       800     680     592 
1       B       4800        4680        3724    
15      B       2048        1816        1816    
5       S       800     624     624 
7       S       1600        1172        1172    
13      S       8192        8036        8036    
14      S       512     336     336 
17      S       1024        776     660 
19      S       512     344     312 
10      S       512     380     376 
4       S       1200        848     848

with:

STATIC mp_obj_t rtos_avail_heapsize(void) {
    u32 mp_task_heap_size = tls_mem_get_avail_heapsize();
    return mp_obj_new_int_from_uint(mp_task_heap_size);
}
STATIC MP_DEFINE_CONST_FUN_OBJ_0(rtos_avail_heapsize_obj, rtos_avail_heapsize);

STATIC mp_obj_t rtos_disp_task_stat_info(void) {
    tls_os_disp_task_stat_info();
    return mp_const_none;
}
STATIC MP_DEFINE_CONST_FUN_OBJ_0(rtos_disp_task_stat_info_obj, rtos_disp_task_stat_info);

STATIC const mp_rom_map_elem_t w600_module_globals_table[] = {
    { MP_ROM_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR_w600) },

    { MP_ROM_QSTR(MP_QSTR_flash_read), MP_ROM_PTR(&w600_flash_read_obj) },
    { MP_ROM_QSTR(MP_QSTR_flash_write), MP_ROM_PTR(&w600_flash_write_obj) },
    { MP_ROM_QSTR(MP_QSTR_flash_erase), MP_ROM_PTR(&w600_flash_erase_obj) },
    { MP_ROM_QSTR(MP_QSTR_flash_id), MP_ROM_PTR(&w600_flash_id_obj) },
    { MP_ROM_QSTR(MP_QSTR_flash_size), MP_ROM_PTR(&w600_flash_size_obj) },
    { MP_ROM_QSTR(MP_QSTR_flash_user_start), MP_ROM_PTR(&w600_flash_user_start_obj) },

    { MP_ROM_QSTR(MP_QSTR_run_ftpserver), MP_ROM_PTR(&w600_run_ftpserver_obj) },

    { MP_ROM_QSTR(MP_QSTR_version), MP_ROM_PTR(&w600_get_version_obj) },
    { MP_ROM_QSTR(MP_QSTR_rtos_avail_heapsize), MP_ROM_PTR(&rtos_avail_heapsize_obj) },
    { MP_ROM_QSTR(MP_QSTR_rtos_disp_task_stat_info), MP_ROM_PTR(&rtos_disp_task_stat_info_obj) },
    { MP_ROM_QSTR(MP_QSTR_dht_readinto), MP_ROM_PTR(&dht_readinto_obj) },
 };

R, B and S is for running, blocked and suspended. We still have to find out, which tasks correspond to the numbers..

and then ..

With task names (which are not complete):

                task        task status stack total stack remain    stack least remain
w60xmpy     33      R       8192        7328        6096    
IDLE        63      R       360     272     272 
Tmr Svc     62      B       800     680     680 
�       1       B       4800        4680        3724    
�       15      B       2048        1816        1816    
�       5       S       800     624     624 
        7       S       1600        1172        1172    
        10      S       512     380     380 
        13      S       8192        8036        8036    
�       14      S       512     336     336 
Sys Tas     17      S       1024        776     660 
hostspi     19      S       512     344     312 
        4       S       1200        848     848

this is complemented by your previous post:

And 4/5-th of the 80K area are unused, if there is no threading?

Forget threading. A MPY stack of 16k is common for devices with large RAM. It could be reduced to 8kand all of the 80k area is used. Look into wm_w600.map to tell for which purpose. Look for the line starting with .bss. In my build, it's line 17650. I have to revert my assumption about just a single task besides Start_task. There seem to be many, each with their own stack of 1k, 2k, 4k and 8k. Quite a few of them in binary blobs. I collected some of that from the map file, adding up to 42k. The only ones in reach seem to be the mpy_task_stk and the mpy_ftps_stk. So let's keep that in mind for now.

scan_task_stk       0x320             WM_SDK_W60X_G3.04.00/Lib/GNU/wlan.a(tls_wl_core.o)
rx_task_stk         0x640             WM_SDK_W60X_G3.04.00/Lib/GNU/wlan.a(tls_wl_core.o)
ibss_task_stk       0x400             WM_SDK_W60X_G3.04.00/Lib/GNU/wlan.a(tls_wl_core.o)
bss_mgmt_task_stk   0x200             WM_SDK_W60X_G3.04.00/Lib/GNU/wlan.a(tls_wl_core.o)
supplicant_task_stk 0x2000            WM_SDK_W60X_G3.04.00/Lib/GNU/wlan.a(wpa_supplicant.o)
mlme_task_stk       0x4b0             WM_SDK_W60X_G3.04.00/Lib/GNU/wlan.a(tls_wl_core.o)
supplicant_timer_task_stk 0x200       WM_SDK_W60X_G3.04.00/Lib/GNU/wlan.a(wpa_supplicant.o)
.bss.fwup_task_stk  0x400             WM_SDK_W60X_G3.04.00/Lib/GNU/wmcommon.a(wm_fwup.o)
.bss.mpy_task_stk   0x4000            build/main.o
.bss.spi_scheduler_stk 0x200          build/hal/wm_hostspi.o
.bss.mpy_ftps_stk   0x2000            build/tools/ftpserver.o
.bss.lwip_task_stk  0x800             WM_SDK_W60X_G3.04.00/Lib/GNU/wmlwip.a(sys_arch.o)
.bss.sys_task_stk   0x400             WM_SDK_W60X_G3.04.00/Lib/GNU/wmmain.a(tls_sys.o)

but that numbers are not up to date anymore. You optimized the stack usage.

While we are at it:

I suggest treating the w600 like an ordinary port from now. The MP ftp command runs well and we get +8k RAM if we abolish the internal ftp task. Which is the better option, I suppose.

One person at elektroda maintains an updated SDK (only little changes iirc). Why not offer the changed SDK on the Github site as well?

robert-hh commented 7 months ago

OK.

rkompass commented 7 months ago

Unless you start ftp, the ftp task is not created. Only the 4k stack (!) space is reserved on the heap. But we could change that to allocation from the MP heap.

That would even be better.

robert-hh commented 7 months ago

I made a few updates:

rkompass commented 7 months ago

!!!! Congratulations !!!!

I tested the timer now: It works as expected. Did you also work on Timer.deinit()? The issue that it did not work before is gone now.

gc.mem_free() reports >105k free on start.

Not here, with this mornings build. :-( Can I somehow check whether the ftp server memory is allocated?

rkompass commented 7 months ago

My script had a custom Makefile, so the CFLAGS += -D__HEAP_SIZE=0x25000 update was not taken over. Sorry for raising trouble.

robert-hh commented 7 months ago

Did you also work on Timer.deinit()?

No. Maybe there is still a problem, or it was fixed bye the priority change as well.

rkompass commented 6 months ago

Orginally I had to do an additional tim.init(callback=None) to stop the running interrupts (aka flickering LED). After your change tim.deinit() suffices, like in the other ports. Seems to be fixed.

I had an almost finished change for the SPI stuff (removing the very fast SPI, as you agreed it is not needed), to free the buffer for it and have yet more RAM. This is lost now, it seems. I deleted the file apparently, together with the older w600 build:-( It's good to see you keep everything on this port up to date. I will see to get the time/energy to recreate the SPI thing.

Shall we close this issue and proceed on Compilation III?

robert-hh commented 6 months ago

There is a similar problem of stopping with the Pin IRQ. These will create problems if the interrupt source is still active and one runs a soft reset. Then the device locks up. I'm not sure if I should fix that in the soft reset path. For testing this is not an issue, as one can always push hard reset. User code must the stop Pin-IRQ by appropriate coding.

Sometimes it happens to me as well that I loose changes. If I'm lucky, it's still in the backup files.

Yes, we can go on with a Compilation III issue.