This thread has been locked.

If you have a related question, please click the "Ask a related question" button in the top right corner. The newly created question will be automatically linked to this question.

MSP430FR4133: Building a Simple Scheduler in Assembler

Part Number: MSP430FR4133

I am trying to build a very simple operating system in assembler for my MSP430. I want to use a preemptive scheduler and go round the tasks in a round robin fashion. All of the tasks will operate indefinitely so I am not interested in any fancy prioritisation or wait states.

I have looked at an example implementation in C so I have quite a good grasp of the order that things have to happen in. I am struggling a bit to divide the available RAM into stacks for each task though.

In the C implementation: 

  stack_pointer[0] = initialise_stack(task1, &task1ram[STACK_TOP]);
  stack_pointer[1] = initialise_stack(task2, &task2ram[STACK_TOP]);
  stack_pointer[2] = initialise_stack(task3, &task3ram[STACK_TOP]);

Each stack is just an array of RAM, so the stack pointer is set to the first address.

In assembler though, I don't know where in memory my stack will be located. Is it bad practice to just divide up the RAM on paper and hard code addresses for each stack pointer? 

For example, can I just say:

;-------------------------------------------------------------------------------
                RSEG    CODE                                            ; Assemble to Flash memory
                RSEG    CSTACK
                DC16    0x20E4
                DC16    0x21E4
                DC16    0x22E4
;-------------------------------------------------------------------------------

Where each of the constants is a hard coded memory location where I want my three stacks to begin. I then want to just set my stack pointer to one of these constants when I do a context switch and then restore the rest of the context using:

restoreContext: pop r15
                pop r14
                pop r13
                pop r12
                pop r11
                pop r10
                pop r9
                pop r8
                pop r7
                pop r6
                pop r5
                pop r4
                reti

So my question's are:

Does anyone have a good example of a simple scheduler in assembler?

What is the recommended way to divide up the RAM into stacks and produce the stack pointers?

  • I'd encourage you to peruse Miro Samek's "SST" (alternatively: "Super Simple Tasker" or "Single Stack Tasker"), which is a preemptive (fixed-)priority kernel with quite low overhead that runs on a single stack. Even if you don't adopt his design, his original paper mentions considerations that you may not have thought of (yet).

    As for defining the stacks, just (1) declare them as (uint16_t) global arrays, and let the linker figure it out or (2) use the linker control file to define the sizes and names. Option (2) has the advantage that you can put the stacks outside the .bss so the startup code won't waste time 0-initializing them.
  • Thanks for the reply.

    I will check out Miro Samek's SST when I revisit this project.

    As for defining the stacks, I see what you mean about defining them as arrays and letting the linker figure it out and I have seen this done in C. However, I am not sure how I would go about this in assembler. My approach so far has been to use the C code debugger to find out where it puts the arrays and then try to use those addresses in my assembler implementation.

    The example C code I have declares 3 stacks using arrays:

    uint16_t task1ram[STACK_SIZE]; //Stack size = 128
    uint16_t task2ram[STACK_SIZE];
    uint16_t task3ram[STACK_SIZE];

    Then it gets the start address using:

      stack_pointer[0] = initialise_stack(task1, &task1ram[STACK_TOP]);
      stack_pointer[1] = initialise_stack(task2, &task2ram[STACK_TOP]);
      stack_pointer[2] = initialise_stack(task3, &task3ram[STACK_TOP]);

    The result of this code is that stack_pointer[] takes the values: 0x20E4, 0x21E4, 0x22E4

    Cross checking this with the device data sheet shows that these are indeed three blocks of memory in RAM, each one 256B long and all one after the other.

    This is exactly what I would like to have in assembler but I am unsure how to get and store these three addresses.

    Should I use an RSEG and let the linker put each block where it wants or should I force them to go to the same addresses as the C compiler did?

     

  • I haven't done (MSP430) assembly in a long time, but I think that if you define something like

    .global stack1
    .common stack1,256,2 ; 256 bytes, 16-bit aligned

    the symbol "stack1" will be visible outside the module.

    There are some assembly wizards out there who will give you a better answer.
  • Euan Andrew said:
    This is exactly what I would like to have in assembler but I am unsure how to get and store these three addresses.

    One option is to get the C compiler to generate an assembly listing file, or keep the generated assembly language file. You can see what assembler statements to use for some example C code.

    If you are using the TI MSP430 Compiler, in the project properties under Build -> MSP430 Compiler -> Advanced Options -> Assembler Options are the options to get the C compiler to generate an assembly listing file or keep the generated assembly language file.

  • Thanks for the advice everyone. Unfortunately I'm using the kick start version of IAR so it doesn't allow the generation of assembler listings.

    I'm going to peruse some of the above links and I'll hopefully figure it out as I go along.

**Attention** This is a public forum