Module 10Módulo 10

Cooperative MultitaskingMultitarea cooperativa

Many tasks, one CPU, no operating system. Each task does a little and steps aside. Muchas tareas, una CPU, sin sistema operativo. Cada tarea hace un poco y cede el paso.

Santi Scagliusi, PhD

Where we are goingA dónde vamos

Two LEDs, two rhythms, one sleeping CPU.Dos LEDs, dos ritmos, una CPU dormida.

superbucle call #tareaA
        call  #tareaB
        bis.w #LPM3|GIE, SR  ; dormir
        jmp   superbucle
tareaA  mov.w &tick, R12
        sub.w &dueA, R12
        jn    finA          ; aún no
        add.w #2, &dueA
        xor.b #BIT0, &P1OUT
finA    ret
WatchObserva

LED1 toggles every 2 ticks, LED2 every 3. No delay loops anywhere.LED1 conmuta cada 2 ticks, LED2 cada 3. Ningún bucle de retardo.

PausePausa

Why is the sign of tick − due enough?¿Por qué basta con el signo de tick − due?

▶ SimulatorSimulador · M10 · Demo: dos LEDs, dos ritmos, una CPU dormida

The superloopEl superbucle

No OS. Just one loop in main that calls each task in turn, forever.Sin SO. Un solo bucle en main que llama a cada tarea por turno, para siempre.

taskA
taskB
taskC
↘
←
↖
↻ foreverpara siempre
The contract: every task returns quickly. El contrato: cada tarea retorna rápido.
In exchange: the next task runs almost immediately. A cambio: la siguiente tarea corre casi de inmediato.

The whole module is about honoring that one contract. Todo el módulo trata de honrar ese único contrato.

A delay loop starves everyoneUn bucle de retardo deja sin CPU a todos

One task spins in a wait loop. The CPU is busy, so no other task runs.Una tarea gira en un bucle de espera. La CPU está ocupada, así que ninguna otra tarea corre.

taskA
delay mov.w #50000, r5
wait dec.w r5
jnz wait
ret
; ~50000 iterations of doing nothing; ~50000 vueltas sin hacer nada
taskA spins in delaytaskA gira en delay
B
C

B and C wait the whole delay before they get a turn. B y C esperan todo el retardo antes de tener turno.

Run it: the dead buttonEjecútalo: el botón muerto

LED2 should copy S1. Does it?LED2 debería copiar S1. ¿Lo hace?

superbucle xor.b #BIT0, &P1OUT
        call  #retardo     ; 300 vueltas
        bit.b #BIT1, &P1IN ; S1
        jz    pulsado
        bic.b #BIT7, &P9OUT
        jmp   superbucle
pulsado bis.b #BIT7, &P9OUT
        jmp   superbucle
WatchObserva

Tap S1 briefly: nothing. R15 is busy counting down inside retardo.Pulsa S1 un instante: nada. R15 está ocupado contando hacia abajo en retardo.

PausePausa

How long can a press last and still be missed?¿Cuánto puede durar una pulsación y aun así perderse?

▶ SimulatorSimulador · M10 · Demo: el retardo que bloquea el botón

A task is a finite state machineUna tarea es una máquina de estados finitos

Instead of waiting inside the task, the task remembers a state and returns.En vez de esperar dentro de la tarea, la tarea recuerda un estado y retorna.

ON LED onLED encendido
period elapsedpasó el periodo
→
←
period elapsedpasó el periodo
OFF LED offLED apagado

Each call checks the trigger, maybe changes state, then returns. No spinning. Cada llamada comprueba el disparo, quizás cambia de estado, y retorna. Sin girar.

The two-state blinker, in assemblyEl parpadeo de dos estados, en ensamblador

Not time yet: return. Time: run the code of the current state.¿Aún no? Retorna. ¿Ya? Ejecuta el código del estado actual.

blink
blink call #elapsed ; period over?
jz bDone ; no: return
mov.b &state, r14
br tabEst(r14)
sOn bic.b #BIT0, &P1OUT ; ON → OFF
mov.b #OFF, &state
bDone ret
sOff bis.b #BIT0, &P1OUT ; OFF → ON
mov.b #ON, &state
ret
state codes and tablecódigos de estado y tabla
ON .equ 0*2
OFF .equ 1*2
tabEst .word sOn
.word sOff
State × 2 indexes a word table. br jumps there.Estado × 2 indexa una tabla de palabras. br salta allí.

Wait without spinningEsperar sin girar

Do not burn cycles counting down. Compare the clock against a deadline.No quemes ciclos contando hacia atrás. Compara el reloj contra un plazo.

BlockingBloqueante dec.w r5 / jnz wait
taskA spins until the wait endstaskA gira hasta que acaba la espera
B
C

CPU held the whole wait. B and C never get a turn.CPU retenida toda la espera. B y C no tienen turno.

Non-blockingNo bloqueante cmp.w &deadline,r12 / jlo done
A?
B
C
A?
B
C
A!

A checks the clock and returns. B and C run every pass; A acts only when the deadline arrives.A mira el reloj y retorna. B y C corren en cada vuelta; A actúa solo cuando llega el plazo.

TA

Timer_A is the heartbeatTimer_A es el latido

Every CCR0 interrupt adds one to a 32-bit SystemTimer.Cada interrupción de CCR0 suma uno a un SystemTimer de 32 bits.

each pulse = one CCR0 interrupt → SystemTimer + 1cada pulso = una interrupción CCR0 → SystemTimer + 1

The tick ISR: count, rearm, wakeLa ISR del tick: contar, rearmar, despertar

stA2ISR inc.w &SystemTimer ; count
adc.w &SystemTimer+2
add.w &stPeriod, &TA2CCR0 ; rearm
bic.w #LPM4, 0(sp) ; wake
reti

TA2 in continuous mode, clocked by ACLK so it keeps ticking in LPM3.TA2 en modo continuo, con ACLK para que siga contando en LPM3.

The ISR produces, main consumesLa ISR produce, main consume

Keep the interrupt short. The real work happens in the cooperative loop.Mantén la interrupción breve. El trabajo real ocurre en el bucle cooperativo.

Producer · ISRProductor · ISR
inc.w &SystemTimer
write, return fastescribe, retorna rápido
→
Shared variableVariable compartida
SystemTimer
the handoffel relevo
→
Consumer · mainConsumidor · main
call #stTime
read with interrupts offlee sin interrupciones

The ISR never waits for main, and main never blocks the ISR. La ISR nunca espera a main, y main nunca bloquea a la ISR.

The cooperative schedulerEl planificador cooperativo

Round-robin: call each task once, in order, every pass of the loop.Round-robin: llama a cada tarea una vez, en orden, en cada vuelta del bucle.

riego
blink
alarma
↘
←
↖
↻
main
superloop
call #riego
call #blink
call #alarma
bis.w #LPM3+GIE, sr
jmp superloop

No priorities, no preemption. Order in the list is the whole policy. Sin prioridades, sin expropiación. El orden en la lista es toda la política.

Sleep when no task is readyDormir cuando ninguna tarea está lista

After one pass, the loop sleeps in LPM3. The tick interrupt wakes it.Tras una vuelta, el bucle duerme en LPM3. La interrupción del tick lo despierta.

Loop: run every task, then bis.w #LPM3+GIE, sr.Bucle: ejecuta cada tarea, luego bis.w #LPM3+GIE, sr.
ISR: clears the LPM bits in the stacked SR with bic.w #LPM4, 0(sp).ISR: borra los bits LPM en el SR apilado con bic.w #LPM4, 0(sp).
RETI: returns to an awake CPU, one pass per tick.RETI: retorna a una CPU despierta, una vuelta por tick.
awake: one passdespierta: una vuelta asleep: LPM3dormida: LPM3
run
LPM3
run
LPM3

The amber line is the tick. Between ticks the CPU draws almost nothing.La línea ámbar es el tick. Entre ticks la CPU consume casi nada.

Everything together: one task, one tickTodo junto: una tarea, un tick

blinkLed toggles the LED every ledPeriod ticks, scheduled by the SystemTimer.blinkLed conmuta el LED cada ledPeriod ticks, planificado por el SystemTimer.

the loopel bucle
superloop
call #blinkLed
bis.w #LPM3+GIE, sr
jmp superloop
the task: non-blocking deadline checkla tarea: comprobación de plazo no bloqueante
blinkLed call #stTime
mov.w &ledDue, r14
mov.w &ledDue+2, r15
call #cmpTiempo
jlo blinkDone ; not yet
add.w #ledPeriod, &ledDue
adc.w &ledDue+2
xor.b #BIT0, &P1OUT
blinkDone ret

Run it: the button answersEjecútalo: el botón responde

Same behaviour, no delays: two tasks, one tick.Mismo comportamiento, sin retardos: dos tareas, un tick.

superbucle call #tareaLed
        call  #tareaBoton
        bis.w #LPM3|GIE, SR
        jmp   superbucle
tareaBoton bit.b #BIT1, &P1IN
        jz    pulsado
        bic.b #BIT7, &P9OUT
        ret
WatchObserva

Tap S1: LED2 lights on the next tick. LED1 keeps its rhythm.Pulsa S1: LED2 se enciende en el siguiente tick. LED1 mantiene su ritmo.

PausePausa

What is the worst-case latency of the button?¿Cuál es la latencia peor caso del botón?

▶ SimulatorSimulador · M10 · Demo: el botón ya responde (planificador cooperativo)

Cooperation is only as good as the worst taskLa cooperación vale lo que la peor tarea

One task that refuses to return on time blocks every other task.Una tarea que se niega a retornar a tiempo bloquea a todas las demás.

The deal holdsEl trato se cumple every task returns in µscada tarea retorna en µs
A
B
C
A
B
C
A
B

Short slices. Each task waits one quick lap for its turn.Rebanadas cortas. Cada tarea espera una vuelta rápida su turno.

The deal breaksEl trato se rompe one task loops 10 msuna tarea gira 10 ms
A
B hogs the CPU for 10 msB acapara la CPU 10 ms
C

For those 10 ms nothing else runs, no matter how urgent.Durante esos 10 ms nada más corre, por urgente que sea.

There is no kernel to step in. Timing is a shared responsibility of every task. No hay un kernel que intervenga. El tiempo es una responsabilidad compartida de cada tarea.

Cooperative vs preemptiveCooperativo vs expropiativo

When tasks cannot be trusted to yield, a kernel takes the CPU by force.Cuando no se confía en que las tareas cedan, un kernel toma la CPU por la fuerza.

Cooperative · this moduleCooperativo · este módulo switch only when a task returnscambia solo cuando una tarea retorna
A
B
C
B

Switches land at task boundaries. No kernel, tiny RAM, but one bad task freezes the rest.Los cambios caen en los bordes de tarea. Sin kernel, poca RAM, pero una mala tarea congela al resto.

Preemptive RTOS · the outlookRTOS expropiativo · lo que viene a timer can cut any taskun timer puede cortar cualquier tarea
A
B
A
B
A
⚡
⚡
⚡
⚡

The tick cuts any task. Costs RAM, but no task can starve the rest.El tick corta cualquier tarea. Cuesta RAM, pero ninguna tarea deja sin CPU al resto.

Three ideas to take with youTres ideas para llevarte

Structuring firmware without an operating system.Estructurar firmware sin sistema operativo.

Return fastRetorna rápido

Never block in a task.Nunca bloquees en una tarea.

Model each task as an FSM. Check, maybe change state, return.Modela cada tarea como una FSM. Comprueba, quizás cambia de estado, retorna.

One tickUn tick

Timer_A is the clock.Timer_A es el reloj.

Compare against a deadline. The ISR produces, the loop consumes.Compara contra un plazo. La ISR produce, el bucle consume.

Then sleepY duerme

Sleep until the next tick.Duerme hasta el próximo tick.

LPM3 between passes. Cooperation only works if every task yields.LPM3 entre vueltas. La cooperación solo funciona si toda tarea cede.