When I first started at MNS, one of my main tasks was to decode new TV’s and remotes we receive from installers and add that remotes functionality into our IRU firmware. The firmware we were using was created by my boss and mentor @VernonBreet. The earliest date of the firmware I could find was version 6.1.00, dated 06 September 2011 but it was derived from versions dating back to 2008 (if not earlier). The last major update in the firmware was done on the 4th June 2012. Since then, I have added numerous models of TV and remote combinations to the firmware. The only minor change I have made to the functionality of the FW was adding a new hand held unit (HHU10) to the code which incorporated light dimming for the patients. Other than that, there has been no fundamental changes to the FW.
So, if the FW works and has been working for years, why change it?
There are several reasons why the firmware needs to be recreated. The FW was done in MPLAB IDE v8.66 using BoostC Complier version 7.03 (from SourceBoost). Currently, I am still doing the TV updates in the firmware using MPLAB v8.89 and BoostC v7.051. At the time of writing, the FW consists of – 25 C files, 4 header files and over 12992 lines of code. The code has become confusing. I’m sure it would take me a month to explain to someone how it all works and how to add new code for TV’s. The complier is old, the IDE is old and giving issues when using debug headers. It normally takes about half a day for me to decode a TV and program a new PIC, doing it the same way I have since I started. The FW was created for a PIC12F683. We are planning on using the PIC12F1822 which is half the price of the 683. These are just a few of the reasons for the overhaul. But, frankly, I am just tired of having to manually create a new FW version for each TV, remote and DSTV combination we get. I want to create a more automated way of programming remotes into the FW (think of universal remotes). Even though I was told that if I were to do this, that there would no longer be a reason to employ me J.
What are some of the challenges and issues?
New IDE, new complier. MPLAB X has the option to import MPLAB v8 projects. I have tried this before but was put off it immediately due to the number of macros that would need to be changed because the complier would now be XC8. Also, the code is complicated. I felt that it would be better to redo it from scratch, adding functionality that I want. Another issue is that the new PIC we use must be pin for pin compatible to the 683. We have so many TVIR boards in the market, that the new PIC and FW would have to offer backwards compatibility. This is great because the 12F1822 has all the peripherals that I would need so it shouldn’t be an issue as I could easily and quickly set that all up using MCC. BUT, I can’t. The 12F683 didn’t have built in PWM, UART and DSM. So, when the board was designed and the pin functions were assigned, I’m guessing they were assigned at random. This is now an issue as I can’t use the built-in peripherals on the 1822 as the pin assignment does not align to the 683. But it’s not an issue in the bigger scheme of things. It’s just an issue to me because I can’t quickly setup peripherical such as the UART using MCC and I must manually bit bang the data coming into the RX pin. So, this is where we start.
Below is out MP-TVR board which connects to the Bed Head Unit. This receives the 485 comms from the BHU and controls the IR and light relay, among other things. Pro editing skills.
UART
I decided to start with getting the comms working first as I knew this would probably be the most difficult to get correct. We have both the TX and RX connected to the 683 BUT we only make use of the RX in the old FW as there was no real need for the TX.
From the above image, you will see that we use a SN75176 to convert the RS-485 comms that come from the BHU to UART for the 683. The RX output pin of the SN75176 goes to RA4 (pin 3) of the 683 and the TX input of the SN75176 comes from RA1 (pin 6) of the 683. The old FW used a UART.c file for the comms but the RX function has been modified to read the incoming TTL on the pin by bit banging. I had hoped that the RA4 pin on the 12F1822 was the RX peripheral but when I looked at the data sheet this was not the case, as per the below.
Most newer microcontrollers will have built in UARTs that can be used to receive and transmit data serially. UARTs transmit one bit at a time at a specified data rate or BAUD rate. This method of serial communications is sometimes referred to as TTL serial (transistor-transistor logic). Serial communications at a TTL level will always remain between the limits of 0V and Vcc. A logical high is represented by Vcc and a logic low by 0V.
The above picture shows a TTL signal sending a 0b01010101
You will see that the signal initializes with a start bit which is a logical low. It then transmits 8 bits of data starting with the least significant bit. After 8 bits of data have been sent, there is a stop bit which is a logical high. You could also have an optional parity bit in between the MSB and the stop bit. But for our purpose we are not using the parity bit.
It is easy to calculate the timing of the bits using the formula – Bit Length = 1 / Baud Rate. In our case, I thought we were using a Baud rate of 9600 to send serial comms from our BHU. This meant that I should be able to scope the bit lengths to 104us but this was not the case. I was in fact getting about 50us which meant the actual baud rate that was used was 19200. I will try find the BHU source code and check that just to confirm.
Bit Banging the UART RX
Knowing the above, we now just need to write a function that would wait for the start bit to end then read the value of the Rx pin half way through the bit time, 8 times over. We can just ignore the stop bit at this stage. Below is a screen shot of the scoping that I did on the Rx Pin receiving a 0x35. You will see my sample timing is not 100% perfect but it is still working none the less. I am toggling a pin (the red scope) every time I read the Rx pin.
Below is the function I used to obtain the above. *** trying code wrapping again ***
char receiveChar (void){ char RxBuffer = 0x00; // used to store received character if (RX_PIN_GetValue() == 0){ // is this a start bit __delay_us(HalfBitTime); // delay half a bit time into the start bit // Receive 8 bits of data for (int bitCount = 0; bitCount < 8; bitCount++) { //DEBBUG_LED_SetHigh(); // Only here to scope and make sure the pin is being read at the correct time if (RX_PIN_GetValue() == 1){ // is the RX Pin high? RxBuffer = RxBuffer | 0b10000000; //set least significant bit } //DEBBUG_LED_SetLow(); // Only here to scope and make sure the pin is being read at the correct time if (bitCount < 7){ // check for the last bit RxBuffer = RxBuffer >> 1; //bit shift 1 to the right } __delay_us(BitTime); // delay 1 bit time before reading the pin. This should sample the pin half way through the bit } NOP(); // here for debugging } return RxBuffer; }