CALVIN CODE RELEASED IN THE C LANGUAGE!
Calvin Rev 2.0 coded for Pavel Baranov's C2C++ Compiler
Here is the Link to the new code page
Here is a link to Pavel's C2C++ Compiler page
NOTE : development in Calvin 1.x discontinued...
1.0 Program Structure
Calvin really resides in the Interrupt Service Routine (ISR). The ISR is just one part of the program however
2.0 ISR (Calvin) - Current Version: 0.2beta
Follow this link to view the ISR code (assembly).
The ISR code uses DEFINEs to configure IO tasks. This allows the entire core code to be used without having to strip out extraneous code segments which are not needed. As an illustration, the following code segment shows the ADC Task being activated;
;* Set Definitions here. Define all IO Interrupts
;* which will be implemented. Defines recognized are:
; SAVE_FSR save the current FSR value on
the ISR Stack
; EXT_INT Ext Int enabled (RB0/INT)
; PORT_CHG State change INT on pins RB[4..7] enabled
; PPORT_INT Parallel Port Int
; ADC_INT ADC Conversion done Int
; Rx_INT USART Rx Int
; Tx_INT USART Tx Int
; SSP_INT Sync Serial Port Int
; CCP1_INT CCP1 Int (depends on mode)
; TMR2_M_INT TMR2=PR2 Match Int
; TMR1_V_INT TMR1 overflow Int
; CCP2_INT CCP2 Int (depends on mode)
; TMR0_INT TMR0 overflow Int. Must be set to use
; background tasks Task[0..t]
#DEFINE ADC_INT ;ADC INT Enabled!
In Calvin, any of the above IO Tasks which are defined as shown here will have their code automatically inserted at compilation. For a description of each type of task, see section 4.1
The ISR treats every task with the same priority. Tasks can be masked out by writing to the T_Mask registers. Any program segment (task or main loop) can alter these masks.Tasks are checked one at a time, starting with the Program Tasks.
There is only one interrupt flag which generates an ISR. This flag is the logical OR of all other flags which are enabled. The ISR must then sequentially check each tasks to see if it generated the interrupt. The last check in the ISR catches any illegal flags. This may happen if an ISR is left out by accident.
2.1 ISR Stack
The ISR incorporates an ISR Task Stack which is configured upon compilation. The stack allows tasks to interrupt each other a total of n times, without losing data in the STATUS, W, and FSR registers. Saving the FSR is an option and can be disabled if no other task(s) use indirect addressing (LUTs etc). The Stack is located at the bottom of Bank0. Care should be taken not to use these registers. If the tasks will never interrupt one another, the ISR Stack could be cut out of the ISR, or set to only take up the bottom two registers (one save for STATUS & W).
Hobbes (the next generation RTK) will extend this feature to adopt semaphores and to control task execution. (ie partial task execution to add full multi-tasking).
3.0 Main Loop Code
The main loop is where you can put code which can run at the maximum CPU speed. It can be treated as the lowest priority 'task' as it will be interrupted by everything else. It can be bumped to highest priority by allowing it to disable global (or other) interrupts. I find that most of my smaller embedded programs have no code at all in this portion of the OS (except a loop and several NOPs) as it is not needed. Another program that I developed has a trigger detect in the loop which, when triggered, runs once through a PID loop. In this case, the PID values would only be calculated when a task had finished obtaining data. The PID code is also pre-emptable by all other tasks, to maintain low INT latency.
All tasks are set up as 'one-shot'. That is, they do not contain an outer loop (like the main loop). Looping is accomplished by running the task every n Clock Ticks. Each task can be disabled by clearing its Interrupt mask bit. Any other task, or the main loop, is able to do this. There are no access restrictions. Modifying the tasks execution is simple. Below is a short list of the modifications you can do.
4.1 IO Task
The ISR assembly code contains the ISR's for all
of the IO events in the PIC 16Cxx chipset. Not all IO is used at once though,
and so I have used DEFINEs to determine when ISR code segments should be
inserted or not. The IO DEFINEs are listed in section 2.0. This is a brief
detail of each ISR.
|EXT_INT||External interrupt on pin RB0|
|PORT_CHG||One of the pins has changed state in the group RB[4..7]|
|PPORT_INT||Parallel slave port INT request driven by ->
(/RD AND /CS) OR (/WR AND /CS)
|ADC_INT||Analog to Digital Convertor finished|
|Rx_INT||USART receive buffer full|
|Tx_INT||USART transmit buffer empty|
|SSP_INT||SSP Buffer full/empty (Read/Write finished)|
|CCP1_INT||CCP1 System INT (read PIC data sheet for more info)|
|TMR2_M_INT||INT generated when Timer2 matches the PR2 register|
|TMR1_V_INT||Timer 1 overflow INT|
|CCP2_INT||CCP2 System INT (read PIC data sheet for more info)|
|TMR0_INT||Timer 0 overflow INT|
|SADC_TRIP||Slope A/D Converter Trip INT|
|OVF_INT||Slope A/D Timer Overflow INT|
|EE_INT||EEPROM Write Complete|
|CMP_INT||Comparator Input Changed|
4.2 Program Task
A program task is a software program which executes once every n Clock_Ticks. Several Tasks can be included (up to the point where ISR stack overflow becomes an issue). For example, a task could be designed to generate a PWM signal to implement a DAC convertor in the controller. I am currently working on a library of Tasks which work with displays, tachometers, servos and PWM signalling. I will add them to this website as time permits.
4.3 Clock_Ticks (Timer 0)
The Clock_Tick is the heartbeat of Calvin. A tick is generated whenever TMR0 overflows. When the ISR detects this, it will increment all Task_Counters and check them for overflow. If a Task_Counter overflows, then it is executed. The Clock_Tick speed can be set by the Timer 0 prescaler. If a Clock_Tick frequency faster than 256 program cycles is needed, then code can be added to the ISR to pre-set Timer 0 when it overflows, similarly to the pre-sets applied to the Task_Counters. CAUTION: Setting the Clock_Tick low (<256) can cause an ISR Stack overflow, if a number of tasks execute within several Clock_Ticks AND each task is quite lengthy.