CALVIN CODE RELEASED IN THE C LANGUAGE!
Calvin Rev 2.0 coded for Pavel Baranov's C2C++ Compiler
Here
is a link to Pavel's C2C++ Compiler page
NOTE : development in Calvin 1.x discontinued...
Greetings all!
Thanks for all the emails. I know that you have been waiting for awhile for some new stuff to occur here, well here it is! I have released Rel.2.0 of Calvin for the C Language. The new OS has some added Tasks, including onboard EEPROM and an improved ISR stack. I have used Pavel's C2C++ Compiler as it is the best & easiest one that I have found to-date, and his ISR can be easily merged with my ISR stack. On this page, you will find the Code and several useful header files. I will add code snippets as I release them. For now, the Calvin C-code will show one task blinking at the TICK rate.
New Stuff in Release 2.0
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 C) - Current Version: 2.0
Calvin C code example link. Click here to get the code!
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 Timer 0 Overflow INT Task being activated;
//*******************************************************************************
//* Set Definitions here. Define all IO Interrupts
*
//* which will be implemented. Defines recognized
*
//* are:
*
//*******************************************************************************
//* 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
*
//* SSPBC_INT Sync Serial Port (I2C Mode)
Bus Collision Detected
*
//* 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)
*
//* EEWR_INT EEPROM (Finished Write Cycle)
Interrupt
*
//* TMR0_INT TMR0 overflow Int. Must be set
to use
*
//*******************************************************************************
#define TMR0_INT
1 // Using TMR0 for the Master Task
Counter
In Calvin, any of the above IO Tasks which are defined as shown here will have their code automatically inserted at compilation.
The ISR treats every task with the same priority. Tasks can be masked out by writing to the TMask registers. Any program segment (task or main loop) can alter these masks.Tasks are checked one at a time, starting with the Program Tasks.
//* Task Enable Masks
char TMask1 = 0; //
Tasks (1-8) mask bits
#define TM1_En0 0 //
Task 1 Mask Bit
#define TM2_En1 1 //
Task 2 Mask Bit
#define TM3_En2 2 //
Task 3 Mask Bit
#define TM4_En3 3 //
Task 4 Mask Bit
#define TM5_En4 4 //
Task 5 Mask Bit
#define TM6_En5 5 //
Task 6 Mask Bit
#define TM7_En6 6 //
Task 7 Mask Bit
#define TM8_En7 7 //
Task 8 Mask Bit
// Add more here if required...
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
Below is a printout of the new ISR Stack. It adds on to the built-in ISR routine offered in C2C++ by saving 4 variables into the ISR Stack. ISR Stack overflow is now handled by the __StackOverFlow() function.
//*******************************************************************************
//* ISR Stack Equates *
*
//*******************************************************************************
//* The ISR Stack is a software stack for
storing multiple instances of : *
//* {W, STATUS, FSR, PCLATH } = STATE. This
version of Calvin saves all these *
//* values, with no option for saving just
some. If the Maximum stack size is *
//* zero, the entire stack operation is disabled.
Stack size now refers to the *
//* number of STATE saves, so the numbewr
of bytes involved is ( #SAVES * 4 ) *
//*******************************************************************************
//* C2C++ Interrupt Routine saves the four
registers into
*
//* __int_save_cont_W
*
//* __int_save_cont_STATUS
*
//* __int_save_cont_FSR
*
//* __int_save_cont_PCLATH
*
//* Save these registers into the stack in
the interrupt() function.
*
//*
*
//*******************************************************************************
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.
4.0 Tasks
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 16F877 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) |
| SSPBC_INT | Sync Serial Port (I2C Mode) Bus Collision Detected |
| 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) |
| EEWR_INT | EEPROM (Finished Write Cycle) Interrupt |
| TMR0_INT | Timer 0 overflow INT |
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.