The code architecture is organized into three areas: Initialization, State Machine and ADC Interrupt Routine. In the next few sections we will go into the details of these areas.
A number of functions are called to initialize the main resources and peripherals of the chip. Specifically:
- CPU is initialized
- I/O ports are initialized
- Timer used to generate the local tick on which many functions are synchronized is initialized
- PWM 1 peripheral is initialized
- ADC pair 0 is initialized
- Variables needed by the state machine for the buck 1 converter are initialized
- PWM 2 peripheral is initialized
- ADC pair 1 is initialized
- Variables needed by the state machine for the buck 2 converter are initialized
In the state machine section, the main loop is an endless loop that continuously calls:
- The function that tests if any button on the board has been pressed
- The function that manages the state machine of buck 1
- The function that manages the state machine of buck 2
All the tasks performed by the routine is shown below. The routine essentially reads the new voltage value and computes the new duty cycle value.
The following slide show demonstrates the details of the ADC interrupt operations, click on each element for the details of the operation:
Context Save: The W registers used in the local code are pushed into the stack to preserve their value at the output of the ISR. Please be careful in using the instruction “push.s”. The reason is that there is only one level of shadow register that can be used to momentarily store the registers. If a second interrupt uses “push.s” then the first instance will be lost.
Init Pointers: Register W8 is used to point to the PID coefficients buffer. W10 is used to point to the input error values buffer. The instructions initialize the two pointers to the first location of the two buffers.
Read New Voltage Value: This routine is executed when the ADC has completed the conversion of the input channel. ADCBUF1 contains the new converted value (output voltage).
Voltage Scaling: The output voltage is multiplied by the reverse of the resistor divider to increase the dynamic range.
Voltage Error Computation: The error is defined as the reference voltage less the output voltage (from the ADC).
PID Computation: This is the core of the operation of the interrupt routine. The PID output is computed. The result (new active period of the PWM signal) is stored into W0.
Update Voltage Error Buffer: The new error is stored into the first entry of the error buffer.
Check Duty Limits: The newly computed active period must be within meaningful limits. This piece of code tests if they are indeed within the limits, otherwise the MIN or MAX value is used. This piece of code may be considered the digital counterpart of anti-wind-up.
Update Duty Cycle: The new value is stored into the duty cycle register so that it will be used at the next PWM period.
Context Restore: Before leaving the ISR, the original values of the used W registers are popped from the stack and restored.