RaspDCC: the software for the PIC
Hi! I haven’t written anything for a while… sorry I have been busy. But I still did something!
Online on github I created a RaspDCC repository where you can download the source code for the PIC of the expansion shield! Here are some information about the source code.
The PIC is configured to use the internal oscillator with an instruction clock of 8MHz.
The main program is divided in 2 sets of instructions: the interrupt and the normal code flows.
The interrupt (ISR function) is specificaly designed to manage the data transmission over the I2C channel. An interrupt is raised every time a package is transmittet to the address specified in the I2C_slave_address. The received pacakges are then stored in the I2C_RX_array. That’s it… nothing more!
On the other side, the main function handle all other tasks: it initialises the PIC and enters the infinite loop.
At every execution of the loop the following steps are processed:
- Check if the if the emergency button is pressed. If yes it does nothing, just waits for a while.
- Check if there are new data received from the I2C that are ready to be converted and transmitted to the track.
- If yes, converts the bytes received into DCC protocols and configure the timeout register for the CCP module.
Said in this way also the main loop doesn’t have such a huge tasks. It took me a while to complete the software section as I was using the CCP module of the PIC to generate an interrupt. The CCP module can generate various events when the Timer1 and the value written in the CCP register match. I thought, that if an interrupt request is raised, I can change polarity to the pin that controls the MOSFET bridge inside the ISR function. At an interrupt event the Timer1 was automatically reset by the CCP and I was able to change the polarity in the ISR, but I wasn’t able to predict exactely “when” the polarity would have been changed. That was the problem! I only have around 4us tolerance allowed by the DCC protocol. That means 32 instruction when running at 8MHz. If the interrupt from the CCP module raises while ISR is handling the interrupt for the I2C protocol, the 32 instruction are not enought and the tolerance allowed by the DCC protocol will be exceeded. I tried to solve the problem with various solutions, the more interesting were:
- implement a control to check if Timer1 counted more the 4us right after the polarity has been changed, if yes the package would have been retransmitted
- change for a more powerful PIC… the PIC18 series allow 2 interrupt sources, a low priority and a high priority. This would have worked, but was I really willing to use a much more elaborate microcontroller only for this little twick? It would have been a waste of power.
The solution to the problem came after a while. The CCP module can automatically change the polarity of a pin. On the other hand, chosing this option doesn’t reset the Timer1 automatically anymore. Resetting a Timer manually makes you loose the clock counted into the pre- and post-scalers and also stops the counting for 2 instruction’s clocks. Again I would have been loosing in precision with the risk to exceed again the allowed DCC tolerance.
The right idea came only after a while: I didn’t have to reset Timer1! I could have simply incremented the value of CCP registers with the number of counts till the next inversion of polarity (58us for a “1” and 100us for a “0”). 58us correspond to 464 instructions for the PIC. This is a sufficent number 🙂 I do not have to increment the CCP counter at the exact moment the polarity has change, I have at least 400 instruction clock time, and within this number I will certanly have the opportunity to update the CCP registers to the new value. In the meantime the Timer1 continues counting without interruption and without loosing a single “tick-tack” 🙂
As of today, the communication between the Raspberry and the PIC is unidirectional. The Raspberry sends at most 4 bytes and the PIC transfers those bytes to the track. In a future release, I will try to implement a sort of feedback to the Raspberry.
The code available on the rapository is written in C. I use the XC compiler from Microchip in free mode, but a short look at the generated assembly code, makes it clear that way to many instruction are generated for executing simple commands. So I started rewriting the code directely in assembler. It is way more compact than the one created by the XC compiler but not yet as refined as the C version. Therefore, up to now, the only version I dare share on the repository is the C one!