Menu

Thallium - a preemptiv µRTOS

Ralf Pagel
3 days ago
5 hours ago
  • Ralf Pagel

    Ralf Pagel - 3 days ago

    Hi,

    About 25 years ago, I started writing an RTOS for what was then the first AVR microcontroller with sufficient SRAM (for those in the know, the ATmega103). Due to lack of time and the necessary expertise, I soon abandoned the project. Although GCB might not seem very useful for assembly programming at first glance, it has greatly helped me revive my old project. I've given the project the working title Thallium. Although I wrote Thallium almost entirely in assembly, I hope it will be of interest here because it increases flexibility in developing BASIC programs.

    In document AN2751, author Ivar Holand from Microchip succinctly describes the advantages of multitasking systems, which also include Thallium. Therefore, I will refrain from going into further detail here. Those interested can read the article to gain an understanding.

    Key features:
    • Up to 8 tasks can be installed.
    • A separate stack is created for each task. When switching tasks, the stack pointer is simple set to the lowest address of a different stack.
    • Up to 8 different priorities can be assigned to tasks.
    • There is a scheduler that always selects the task with the highest priority first.
    • All tasks with the same priority are executed using a round-robin procedure.
    • Each task has a flag register that controls its execution.
    • There is a tick count for delay and timing purposes.
    • Up to 15 mutexes are possible to control access to shared resources.
    • All commands that waste computing time are forbidden except in Task0.

    The following commands are currently available:
    setUpTask - is called only once for each task during initialization - Parameters: osTaskNbr, osLabel, osPriority, osFlagsBitMask
    setFlags - sets the flags for the specified task - Parameters: osTaskNbr, osBitMask
    clrFlags - clears the flags for the specified task - Parameters: osTaskNbr, osBitMask
    slumber - disables the current task for a specified number of osTicks - Parameter: osDuration
    yield - allows all other tasks to run at least once - Parameter: osTaskNbr
    signal - marks a shared resource as occupied (think at a public restroom door) - Parameters: osTaskNbr, osSignalNbr
    passed - releases a shared resource - Parameter: osSignalNbr
    lock - disables the global interrupt (use this if the task must not be interrupted)
    resume - enables the global interrupt

    Because Thallium is written in assembly language, it only requires 992 bytes of program memory and 87 bytes of SRAM (that's what my compiler reports for the attached program). Most preemptive RTOSs are written in the C programming language and are therefore not suitable (or not well suited) for use with GCB. Thallium, on the other hand, is based on macros, which provide an API for use with GCB. Thallium already works very well, but there is still much room for improvement, and it will probably never be truly finished. At the moment, it is only a draft. If there is interest, I would be happy to continue this topic here.

    Note:
    Thallium only runs on AVR microcontrollers with sufficient SRAM (approximately 1024 bytes or more). The cores for the ATmega328pb and the AVR128DA28 are already running. The smaller PIC microcontrollers, however, are not suitable for peemptive multitasking due to their hardware stack.

    Cheers
    Ralf

     
    ❤️
    1
  • Anobium

    Anobium - 2 days ago

    Very good. There is another similar OS in the demo pack, so, this is a great addition.

    An insight/question. Would you to override the INITSYS? and the BASPROGRAMSTART jmp ( at vector 0 ) and put you own label to handle the init as you wish? I would be possible to do this with a tweak in the AVR part of the compiler ( it already does this for the PICs ). And, would it also be useful to remove the Interrupt vectors ( not implemented but this would be rather easy to do )?

    We can create initialisation for PICS with out BASPROGRAMSTART etc. This is needed for specific bootloaders. This is only used for the specific bootloader use case and is not documented.

    There are very few things that are not documented, but, #option UserCodeOnly INITMCU: is one of the undocumented hidden gems.


    Want me to move the OS to GitHub? Nice webpage.... etc etc. :-)

     
  • Ralf Pagel

    Ralf Pagel - 2 days ago

    Hi,

    For Thallium, the GCB initialization with INITSYS and BASPROGRAMSTART can remain as is. Only the enabling of global interrupts (sei) occurs slightly too early, but I can immediately undo this afterward. Therefore, this has no impact on the program.

    The situation is different with the removal of the interrupt vectors. This would indeed be a significant improvement, especially for traditional AVR chips. Unlike more modern AVR chips, traditional AVR chips do not allow you to determine within the shared INTERRUPT subroutine whether an interrupt is a timer interrupt. Consequently, you cannot use any interrupts other than the timer interrupt. More modern AVR chips (AVR128xxx), on the other hand, do not automatically clear their interrupt flags upon entering the interrupt vector. This allows me to select interrupts according to their origin within the shared INTERRUPT subroutine. But even with more modern AVR chips, the ability to influence the vectors brings speed advantages because the interrupts no longer have to be selected afterwards.

    Removing the fixed interrupt vectors will likely also remove INITSYS and BASPROGRAMSTART. The name of the option 'UserCodeOnly INITMCU' suggests this. It would be great to be able to use this option with AVR chips in the future.

    Thank you very much, this will help improve Thallium.

    Please wait to move the OS to GitHub until I have completed these changes to the interrupt vectors.

    Cheers
    Ralf

     
  • Anobium

    Anobium - 2 days ago

    Ralf,

    Recommend you try option UserCodeOnly INITMCU add a label called INITMCU: at the top of the your program. What needs to be resolved there? I mean. We need to change what to make this preprocessor instruction behave on the AVR compared to a PIC.

    As we cannot change the behaviour of option UserCodeOnly ( beyond fixing the PIC/AVR compatibilty ) we should then add a new preprocessor instruction option RemoveAVRInterruptVectors. What is the exact need ? Removal of what ? I think I need examples 'as-is' and 'to-be'. Adding new functionality like this is not hard, it is low risk as the functionality is very specific to preprocessor instructions.

     
  • Ralf Pagel

    Ralf Pagel - 2 days ago

    Hi Evan,

    To test your suggestion, I compiled the UserCodeOnly option for a PIC.
    This is exactly the feature I was missing at GCB when programming Thallium! I'm looking forward to it.

    All vectors can be entered before the INITMCU label in the BASIC program. This can also be done with a macro (which looks better).

    I think its behavior doesn't need to change with an AVR microcontroller, except that rjmp INITMCU must be generated in the ASM file instead of goto INITMCU.

    Cheers
    Ralf

     
  • Anobium

    Anobium - 1 day ago

    OK. Before I start.

    Try the UserCodeOnly option with the AVR.

    What explicitly needs changing?
    And, you must use AVRASM2 as the selected tool to ensure ASM we are generating is valid. So, you can take the ASM generated by GCBASIC, make your changes and validate these changes using AVRASM2.

    I really need a reference ASM file.

    My tests here.


    My source: ( first-demo.gcb)

    #chip mega328p
    #option Explicit
    #option UserCodeOnly INITMCU:
    
    INITMCU:
    

    Give AVRASM2 errors.

    GCBASIC (2026.02.07 (Windows 64 bit) : Build 1557)
    
    Compiling: first-start-sample.gcb
    Program compiled successfully (Compile time: 1.875 seconds)
    
    Assembling program using C:\GCstudio\gcbasic\..\atmel\avrassembler\avrasm2.exe
    C:\GCstudio\gcbasic\demos\first-start-sample.build\first-start-sample.asm(98): error: syntax error, unexpected ':'
    
    Assembly failed, 1 errors, 0 warnings
    Program assembled successfully (Assembly time: 0.125 seconds)
    Done
    

    Generated ASM. Clearly has many errors and is not the reference ASM.

    ;Vectors
    ;Interrupt vectors
        .ORG    0
        jmp BASPROGRAMSTART
        .ORG    2
        reti    ;INT0
        .ORG    4
        reti    ;INT1
        .ORG    6
        reti    ;PCINT0
        .ORG    8
        reti    ;PCINT1
        .ORG    10
        reti    ;PCINT2
        .ORG    12
        reti    ;WDT
        .ORG    14
        reti    ;TIMER2_COMPA
        .ORG    16
        reti    ;TIMER2_COMPB
        .ORG    18
        reti    ;TIMER2_OVF
        .ORG    20
        reti    ;TIMER1_CAPT
        .ORG    22
        reti    ;TIMER1_COMPA
        .ORG    24
        reti    ;TIMER1_COMPB
        .ORG    26
        reti    ;TIMER1_OVF
        .ORG    28
        reti    ;TIMER0_COMPA
        .ORG    30
        reti    ;TIMER0_COMPB
        .ORG    32
        reti    ;TIMER0_OVF
        .ORG    34
        reti    ;SPI_STC
        .ORG    36
        reti    ;USART_RX
        .ORG    38
        reti    ;USART_UDRE
        .ORG    40
        reti    ;USART_TX
        .ORG    42
        reti    ;ADC
        .ORG    44
        reti    ;EE_READY
        .ORG    46
        reti    ;ANALOG_COMP
        .ORG    48
        reti    ;TWI
        .ORG    50
        reti    ;SPM_READY
    
    ;********************************************************************************
    
    .ORG    52
    :
    ;Initialise stack
        ldi SysValueCopy,high(RAMEND)
        out SPH, SysValueCopy
        ldi SysValueCopy,low(RAMEND)
        out SPL, SysValueCopy
    
    ;Start_of_the_main_program
    INITMCU:
    BASPROGRAMEND:
        sleep
        rjmp    BASPROGRAMEND
    

    **You can test the ASM ** as you change the ASM.

    avrasm2.exe is part of the GCSTUDIO install.

    %instdir%..\atmel\avrassembler
    command = %avrasm2%\avrasm2.exe
    params = -v0 "%FileName%" -I "%avrasm2%\Include" -e "%Fn_NoExt%.eep" -fI -o "%Fn_NoExt%.hex" -l "%Fn_NoExt%.lst"

    so, this is expanded from your USE.INI as ( use.ini is the configuration file ).

    c:\gcstudio\atmel\avrassembler\avrasm2 -v0 "C:\GCstudio\gcbasic\demos\first-start-sample.build\first-start-sample.ASM" -I "c:\gcstudio\atmel\avrassembler\Include" -e "C:\GCstudio\gcbasic\demos\first-start-sample.build\first-start-sample.eep" -fI -o "C:\GCstudio\gcbasic\demos\first-start-sample.build\first-start-sample.hex" -l "C:\GCstudio\gcbasic\demos\first-start-sample.build\first-start-sample.lst"

    Now you can change/hack the ASM to create a reference ASM file. Once you have a reference ASM ( the target ASM ) please share.

    Evan

     
  • Ralf Pagel

    Ralf Pagel - 1 day ago

    Hi,

    I found the entry for avrasm2 in the use.ini file.

    My GCB IDE (SynWrite) is using GCASM.

    Is there a way to select avrasm2 in the GCB IDE?
    Or do I have to call avrasm2 with these parameters from a command line?

    Ralf

     
  • Anobium

    Anobium - 1 day ago

    Open the Prefs Editor and select the compiler tab. Or, press Function F4, type Prefs, then select the compiler tab.

    If you are using SynWrite... Edit Program Preference.

    But, please use GCCODE. As we progress GCCODE will have the AVR debugger and all the new tools.

     
  • Ralf Pagel

    Ralf Pagel - 5 hours ago

    Hi Evan,

    I have managed to set up a tool for using avrasm2.
    I used this to check the reference ASM.
    Here is it:

    ;Vectors
    ;Interrupt vectors
        .ORG    0
        jmp INITMCU
    
    
    ;********************************************************************************
    
    ; The user text of the gcb file between the 'option UserCodeOnly' and the label 'INITMCU:' appears here:
    ; (Since the compiler don't know '.ORG', the user must use 'rawasm' for edit the row.)
    ; Interrupt vectors
    
    
    .ORG    52  ; first address after the vectors (depends on the chip)
    INITMCU:
    
    ; The compiled user text of the gcb file after the label 'INITMCU:' appears here:
    ; Stack
    ; SysInit
    ; Main Program
    
    BASPROGRAMEND:
        sleep
        rjmp    BASPROGRAMEND
    

    Result:
    Assembly complete, 0 errors, 0 warnings

    Ralf

     
    • Anobium

      Anobium - 5 hours ago

      ok. So, the interrupt vectors are all empty?
      And, the .ORG 52 is specific so the chip? So, this .ORG would be adapted specific to the mcu?

       

      Last edit: Anobium 5 hours ago

Log in to post a comment.