Thursday, January 1, 2015

USB getDeviceDescriptor

In my last post I talked about making a successful USB transfer. It was a getDeviceDescriptor transfer, which transfers info about the device to the host. The transferred data was:0100 0201 0150 0121 0944 4000 0000 0110 0112
The data was received from the same Korg Microkey-25 as previously used.
Byte Field Value Meaning
0 bLength 0x12 The Device description consists of 18 bytes
1 bDescriptorType 0x01 Descriptor type DEVICE
2-3 BCD 0x0110 USB Spec Release Number 1.10
4 Class 0x00, No class per interface defined
5 SubClass 0x00 Must be 0, since Class code is 0
6 bDeviceProtocol 0x00 No class specific protocol used
7 bMaxPacketSize0 0x40 Max packet size 64 for endpoint 0
8-9 idVendor 0x0944 Korg
10-11 idProduct 0x0121
12-13 bcdDevice 0x0150 Device release number 1.50
14 iManufacturer 0x01 Index of string descriptor describing manufacturer
15 iProduct 0x02 Index of string descriptor describing product
16 iSerialNumber 0x00 Index of string descriptor describing serial number
17 bNumConfigurations 0x01 Device has only one configuration

So all of this looks fine to me. Apart from this, I have also addressed the device, which should mean that I only need to set the device configuration to get the Microkey up and going. I do need to spend some time on the code though, I can't keep hard coding all this stuff, I will need some level of abstraction, even though I'd prefer to keep things as simple as possible...

Monday, November 24, 2014

PIC24FJ64GB004, first successful USB data transfer

I just got my first successful data transfer through to my PIC.The first transfer in a enumeration process is the "get device descriptor" transfer, which consists of three transfers, setup, in and out transfer. Here is the UART output of the transfer:

***************************

Welcome to MIDI2VC+
Version 0.15
Build date Nov 24 2014

***************************
0x01bf> USB device attached.
0x01bf> Waiting for device power stabilization
0x01ca> Device power stabilized
0x01ca> Full speed device found
0x01ca> Device reset initiation
0x01d3> Device reset complete
0x01d3> Setup token sent
0x01d3> Setup token transfer complete
0x01d3> Handshake was: 0002
0x01d3> In token sent
0x01d3> In token transfer complete
0x01d3> Handshake was: 000b

***************************
Selected register dump:
***************************
0x01d3> U1CON   = 0x0089
0x01d3> U1ADDR  = 0x0000
0x01d3> U1TOK   = 0x0090
0x01d3> U1BDTP1 = 0x0012
0x01d3> U1EP0   = 0x000d
0x01d3> U1CNFG1 = 0x0000
0x01d3> BDT[0]  = 0x6c12
0x01d3> BDT[1]  = 0x0800
0x01d3> BDT[2]  = 0x0808
0x01d3> BDT[3]  = 0x0840
0x01d3> &BDT[0] = 0x1200
0x01d3> &ep0TxBuffer[0] = 0x0840
0x01d3> ep0TxBuffer[0] = 0x0680
0x01d3> &ep0RxBuffer[0] = 0x0800
0x01d3> ep0RxBuffer[0] = 0x0112
0x01d3> U1IR = 0x0044
0x01d3> U1STAT = 0x0000
***************************
***************************


***************************
ep0RxBuffer dump:
***************************
0x01d3> ep0RxBuffer = 0x0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0100 0201 0150 0121 0944 4000 0000 0110 0112 
***************************
***************************

0x01d3> Out token sent
0x01d3> Out token transfer complete
0x01d3> Handshake was: 000e

Now, everything is not great here. The last transfer has an 0xe handshake, which is a stall handshake. This can't be right since I have disabled stalling. The second thing that is fishy is the content of the RxBuffer. I analyzed the USB data transfer of my MicroKey keyboard, by using  Device Monitoring Studio (demo version). Here I can see that the transferred data should actually be:

12 01 10 01 00 00 00 40 44 09 21 01 50 01 01 02 00 01

As you can see, bytes are in the wrong order. I'll look into these issues next...
I'm really happy for this road mark, it means that I get the hardware and it's working! 

Thursday, November 13, 2014

PIC24FJ64GB004, enumeration process

Last post I wrote about the first steps of the enumeration process on the USB host, finding an attached device. The whole process includes quite a number of steps, which are not that easy to wrap your head around.
Firstly, I hadn't configured the clocks properly. The USB host mode is quite picky about the clocks, so getting it right is essential. One problem was that I haven't designed in a crystal as oscillator. The data sheet says the internal RC-clock isn't precise enough. This also means that even if everything actually seems to be working with the RC-clock, the instructions don't address this configuration. The setup is available in the source code.
When I troubleshooted the enumeration process, I made a pseudocode version of it, and I thought it would be suitable to post that here. I'm getting as far as to get a transfer complete-interrupt, which probably is a good step on the way to get through the whole enumeration. So here it is:

 [setup]  
   
 [global variables]  
 static uint16_t __attribute__((aligned(512))) BDT[4];  
 volatile uint16_t ep0RxBuffer[32];  
 volatile uint16_t ep0TxBuffer[32];  
   
 [in main()]  
 //USB1 host mode setup  
 U1CONbits.HOSTEN = 1; //enable host mode  
 U1OTGCONbits.DPPULDWN = 1; //enable pulldowns on lanes  
 U1OTGCONbits.DMPULDWN = 1;  
 U1OTGCONbits.DPPULUP = 0;  
 U1OTGCONbits.DMPULUP = 0;  
   
 U1IRbits.ATTACHIF = 0; //setup and enable attach interrupt  
 U1IEbits.ATTACHIE = 1;  
 IEC5bits.USB1IE = 1;  
   
 U1EP0 = 0x4d; //EP0 Setup for bidirectional control transfers  
 U1CNFG1 = 0x00; // PING-PONG disabled  
   
 U1BDTP1 = (uint16_t) (&BDT) >> 8; //set BDT upper byte  
 BDT[1] = (uint16_t) & ep0RxBuffer; //point first BDT entry, second byte, to RX buffer adress  
 BDT[3] = (uint16_t) & ep0TxBuffer;//point second BDT entry, second byte, to RX buffer adress  
   
   
   
 [enumeration]  
 after attach interrupt is thrown:  
 wait 100ms  
   
 if device is low speed:  
           U1ADDRbits.LSPDEN = 1;//module operates at low speed  
           U1EP0bits.LSPD = 1;  
 else:  
           U1ADDRbits.LSPDEN = 0; //module operates at full speed  
           U1EP0bits.LSPD = 0;  
   
   
 U1CONbits.USBRST = 1; //reset device  
 U1CONbits.SOFEN = 1; //enable start of frame generation  
   
 wait 60ms  
   
 U1CONbits.USBRST = 0;//release reset  
   
 wait 10ms  
   
 //send GET_DEVICE_DESCRIPTOR  
 ep0TxBuffer[0] = 0b0000 0110 1000 0000; //GET_DESCRIPTOR  
 ep0TxBuffer[1] = 0x01; //DEVICE  
 ep0TxBuffer[2] = 0x00; //NO LANGUAGE ID  
 ep0TxBuffer[3] = 0x40; //DESCRIPTOR LENGTH  
 U1ADDR = 0x00; //device adress, 0 until enumeration is finsished  
 BDT[2] = 0x8008; //Byte count=8 and BD1STAT handed over to USB module  
 U1TOK = 0xd0; //send setup token  
   

UART output functions

Also, I have done quite a bit of work in functions to output important data on the UART. This way I can program the PIC with the PICKIT 2 tool and use the same tool for reading the UART output. Even more useful than the debug tool available when using the PICKIT 3. Here are the functions:

 //*********************************************************  
 //*******Function timeStamp**********************  
 //Returns a string that begins with the hex value of the  
 //10ms system tick followed by bracket and space: "0xabcd> "  
   
 char* timeStamp() {  
   extern volatile uint16_t ms10Tick;  
   static char hexChars[9];  
   char* tempChars;  
   uint16_t i;  
   
   hexChars[0] = '0';  
   hexChars[1] = 'x';  
   hexChars[6] = '>';  
   hexChars[7] = 0x20; //space  
   hexChars[8] = 0;  
   
   
   tempChars = uint16_t2String(ms10Tick);  
   for (i = 0; i < 4; i++) {  
     hexChars[i + 2] = tempChars[i];  
   }  
   
   return hexChars;  
 }  
   
   
 //*********************************************************  
 //*******Function string2UARTTXQueue**********************  
 //Takes a c-string and sends it to the UART transmit Queue  
   
 void string2UARTTXQueue(char str[]) {  
   
   uint16_t i = 0;  
   while (str[i] != 0) {  
   
     pushUARTTXQueue(str[i]);  
     i++;  
   }  
   return;  
 }  
   
   
   
 //*********************************************************  
 //*******Function popUARTTXQueue**********************  
 //Returns next value in UART transmit Queue and  
 //sets queue values apropriately  
   
 char popUARTTXQueue() {  
   char UARTVal;  
   extern volatile uint16_t UARTTXQueueTail, UARTTXQueueHead, UARTTXQueueLength;  
   extern volatile char UARTTXQueue[UART_TXQueue_SIZE];  
   
   if (UARTTXQueueLength == 0) {  
     return 0;  
   }  
   
   
   UARTTXQueueTail = (UARTTXQueueTail + 1) & (UART_TXQueue_SIZE - 1);  
   UARTVal = UARTTXQueue[UARTTXQueueTail];  
   UARTTXQueueLength--;  
   
   return UARTVal;  
 }  
   
   
 //*********************************************************  
 //*******Function pushUARTTXQueue**********************  
 //Puts a char to the UART transmit Queue and  
 //sets queue values apropriately  
   
 void pushUARTTXQueue(char UARTVal) {  
   extern volatile uint16_t UARTTXQueueTail, UARTTXQueueHead, UARTTXQueueLength;  
   extern volatile char UARTTXQueue[UART_TXQueue_SIZE];  
   
   if (UARTTXQueueLength == (UART_TXQueue_SIZE - 1)) {  
     return;  
   }  
   
   UARTTXQueueHead = (UARTTXQueueHead + 1) & (UART_TXQueue_SIZE - 1);  
   UARTTXQueue[UARTTXQueueHead] = UARTVal;  
   UARTTXQueueLength++;  
   
   return;  
 }  
   
 //*********************************************************  
 //*******Function uint16_t2String**********************  
 //converts a uint16_t to a string in hex format without 0x  
   
 char* uint16_t2String(uint16_t buffer) {  
   static char hexChars[5];  
   const uint16_t asciiTable[16] = {0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66};  
   uint16_t i;  
   for (i = 4; i > 0; i--) {  
     hexChars[i - 1] = (char) asciiTable[((0xf000 >> 4 * (i - 1)) & buffer) >> 4 * (4 - i)];  
   }  
   hexChars[4] = 0;  
   return hexChars;  
 }  
   
 void dumpRegisters() {  
   string2UARTTXQueue("\r\n***************************\r\n");  
   string2UARTTXQueue("Selected register dump:\r\n");  
   string2UARTTXQueue("***************************\r\n");  
   
   string2UARTTXQueue(timeStamp());  
   string2UARTTXQueue("U1CON  = 0x");  
   string2UARTTXQueue(uint16_t2String(U1CON));  
   string2UARTTXQueue("\r\n");  
    
   string2UARTTXQueue(timeStamp());  
   string2UARTTXQueue("U1ADDR = 0x");  
   string2UARTTXQueue(uint16_t2String(U1ADDR));  
   string2UARTTXQueue("\r\n");  
   
   string2UARTTXQueue(timeStamp());  
   string2UARTTXQueue("U1TOK  = 0x");  
   string2UARTTXQueue(uint16_t2String(U1TOK));  
   string2UARTTXQueue("\r\n");  
   
   string2UARTTXQueue(timeStamp());  
   string2UARTTXQueue("U1BDTP1 = 0x");  
   string2UARTTXQueue(uint16_t2String(U1BDTP1));  
   string2UARTTXQueue("\r\n");  

   
   string2UARTTXQueue("***************************\r\n");  
   string2UARTTXQueue("***************************\r\n\r\n");  
   return;  
 }  

Tuesday, October 14, 2014

MIDI2VC+, USB device detection

Work on the MIDI2VC+ is slow but steady. The USB protocol is pretty complicated, especially for a host. But I'm taking it one step at a time. The implementation of a UART with functions for outputting strings, makes the whole thing more manageable. I've gotten so far as to identifying an attached device as "Full Speed" or "Low Speed" and managing the detaching. Here's the code for the project so far:

 #include <xc.h>  
 #include <stdint.h>  
 #define STRING_LENGTH 64  
 #define VERSION "0.1"  
 #define POWER_ON_LED PORTCbits.RC3  
 #define LED1 PORTBbits.RB2  
 #define USB_CONNECTED PORTCbits.RC1  
 #define LED4 PORTCbits.RC0  
 #define UART_TXQueue_SIZE 256  
 _CONFIG1(JTAGEN_OFF & GCP_OFF & GWRP_OFF & FWDTEN_OFF & WINDIS_OFF & ICS_PGx3)  
 _CONFIG2(IESO_OFF & POSCMOD_NONE & OSCIOFNC_ON & FCKSM_CSDCMD & FNOSC_FRCPLL & PLL96MHZ_ON & PLLDIV_DIV2)  
 _CONFIG3(WPFP_WPFP0 & SOSCSEL_IO & WUTSEL_FST & WPDIS_WPDIS & WPCFG_WPCFGDIS & WPEND_WPENDMEM)  
 _CONFIG4(DSWDTPS_DSWDTPS3 & DSWDTOSC_LPRC & RTCOSC_LPRC & DSBOREN_OFF & DSWDTEN_OFF)  
 volatile uint16_t UARTTXQueueTail, UARTTXQueueHead, UARTTXQueueLength, USBEnumerationProcess;  
 volatile char UARTTXQueue[UART_TXQueue_SIZE];  
 void string2UARTTXQueue(char str[]);  
 char popUARTTXQueue();  
 void pushUARTTXQueue(char UARTVal);  
 //*** UART1 Receive interrupt function ***  
 //**************************************** k  
 void __attribute__((__interrupt__, __auto_psv__)) _U1RXInterrupt(void) {  
   IFS0bits.U1RXIF = 0; //Reset UART1 Receive interrupt bit  
   U1TXREG = U1RXREG; //Transmit received character  
   return;  
 }  
 //*** USB1 interrupt function ***  
 //****************************************   
 void __attribute__((__interrupt__, __auto_psv__)) _USB1Interrupt(void) {  
   extern volatile uint16_t USBEnumerationProcess;  
   if (U1IRbits.ATTACHIF == 1 && U1IEbits.ATTACHIE == 1) {  
     string2UARTTXQueue("USB device attached.\r\n");  
     USBEnumerationProcess = 1;  
     U1IR = 0x41;  
     U1IE = 0x01;  
     PORTCbits.RC1 = 1; //Light an LED  
   } else if (U1IRbits.DETACHIF == 1 && U1IEbits.DETACHIE == 1) {  
     string2UARTTXQueue("USB device detached.\r\n");  
     USBEnumerationProcess = 0;  
     U1IR = 0x41;  
     U1IE = 0x40;  
     U1ADDRbits.LSPDEN = 0; //The low speed registers need to be reset here  
     U1EP0bits.LSPD = 0; //or the device will be misidentified at the next attachement  
     PORTCbits.RC1 = 0; //Unlight an LED  
   }  
   IFS5bits.USB1IF = 0; //Clear  
   return;  
 }  
 int16_t main() {  
   extern volatile uint16_t UARTTXQueueTail, UARTTXQueueHead, UARTTXQueueLength, USBEnumerationProcess;  
   UARTTXQueueTail = 0;  
   UARTTXQueueHead = 0;  
   UARTTXQueueLength = 0;  
   USBEnumerationProcess = 0;  
   TRISB = 0x00;  
   TRISC = 0x00;  
   PORTC = 0x08;  
   uint16_t pll_startup_counter = 600;  
   CLKDIVbits.PLLEN = 1;  
   while (pll_startup_counter--);  
   PORTC = 0x09; //Turn on LED when PLL is locked  
   U1PWRCbits.USBPWR = 1;  
   CLKDIVbits.CPDIV = 0b10;  
   TRISA = 0x02; //RA1 as input  
   AD1PCFG = 0xffff; //No analogue inputs  
   IFS0 = 0x0000; //Interrupts reset  
   IEC0 = 0x0800; //Uart recieve interrupt enabled  
   POWER_ON_LED = 1;  
   //Reconfigurable pin setup  
   __builtin_write_OSCCONL(OSCCON & 0xBF);  
   RPOR2bits.RP5R = 3; //RP5 as UART1 TX  
   RPINR18bits.U1RXR = 0x06; //RP6 as UART1 RX  
   __builtin_write_OSCCONL(OSCCON | 0x40);  
   U1BRG = 8; //Baud rate set to 56k, U1BRG = (8MHz/2)/(4*56000) - 1  
   U1MODE = 0x8808; //UART1 enabled in simplex mode  
   U1STA = 0x8400; //Interrupt when char is transferred to TSR and Transmit enabled  
   U1MODEbits.BRGH = 1;  
   //USB1 host mode setup  
   U1CONbits.HOSTEN = 1;  
   U1OTGCONbits.DPPULDWN = 1;  
   U1OTGCONbits.DMPULDWN = 1;  
   U1OTGCONbits.DPPULUP = 0;  
   U1OTGCONbits.DMPULUP = 0;  
   U1IRbits.ATTACHIF = 0;  
   U1IEbits.ATTACHIE = 1;  
   IEC5bits.USB1IE = 1;  
   char build_date[] = __DATE__;  
   string2UARTTXQueue("***************************");  
   string2UARTTXQueue("\r\n\r\n");  
   string2UARTTXQueue("Welcome to MIDI2VC+\r\nVersion ");  
   string2UARTTXQueue(VERSION);  
   string2UARTTXQueue("\r\n");  
   string2UARTTXQueue("Build date ");  
   string2UARTTXQueue(build_date);  
   string2UARTTXQueue("\r\n\r\n");  
   string2UARTTXQueue("***************************\r\n");  
   while (1) {  
     switch (USBEnumerationProcess) {  
       case 0:  
         break;  
       case 1:  
         if (U1CONbits.JSTATE == 0) {  
           string2UARTTXQueue("Low speed device found\r\n");  
           U1ADDRbits.LSPDEN = 1;  
           U1EP0bits.LSPD = 1;  
           USBEnumerationProcess = 2;  
         } else {  
           string2UARTTXQueue("Full speed device found\r\n");  
           U1ADDRbits.LSPDEN = 0;  
           U1EP0bits.LSPD = 0;  
           USBEnumerationProcess = 2;  
         }  
         break;  
       default:  
         break;  
     }  
     if (UARTTXQueueLength > 0 && U1STAbits.UTXBF == 0) {  
       U1TXREG = popUARTTXQueue();  
     }  
   }  
   return 0;  
 }  
 //*********************************************************  
 //*******Function string2UARTTXQueue**********************  
 //Takes a c-string and sends it to the UART transmit Queue  
 void string2UARTTXQueue(char str[]) {  
   uint16_t i = 0;  
   while (str[i] != 0) {  
     pushUARTTXQueue(str[i]);  
     i++;  
   }  
   return;  
 }  
 //*********************************************************  
 //*******Function popUARTTXQueue**********************  
 //Returns next value in UART transmit Queue and  
 //sets queue values apropriately  
 char popUARTTXQueue() {  
   char UARTVal;  
   extern volatile uint16_t UARTTXQueueTail, UARTTXQueueHead, UARTTXQueueLength;  
   extern volatile char UARTTXQueue[UART_TXQueue_SIZE];  
   if (UARTTXQueueLength == 0) {  
     return 0;  
   }  
   UARTTXQueueTail = (UARTTXQueueTail + 1) & (UART_TXQueue_SIZE - 1);  
   UARTVal = UARTTXQueue[UARTTXQueueTail];  
   UARTTXQueueLength--;  
   return UARTVal;  
 }  
 //*********************************************************  
 //*******Function popUARTTXQueue**********************  
 //Puts a char to the UART transmit Queue and  
 //sets queue values apropriately  
 void pushUARTTXQueue(char UARTVal) {  
   extern volatile uint16_t UARTTXQueueTail, UARTTXQueueHead, UARTTXQueueLength;  
   extern volatile char UARTTXQueue[UART_TXQueue_SIZE];  
   if (UARTTXQueueLength == (UART_TXQueue_SIZE - 1)) {  
     return;  
   }  
   UARTTXQueueHead = (UARTTXQueueHead + 1) & (UART_TXQueue_SIZE - 1);  
   UARTTXQueue[UARTTXQueueHead] = UARTVal;  
   UARTTXQueueLength++;  
   return;  
 }  

Wednesday, October 8, 2014

SA0***

I finally got my amateur radio license, which feels nice. The test was quite hard. Today I got a call from the license issuer, who asked what I call sign I wanted. Apparently I'm the first in the region who got to choose my own call sign, as long as it wasn't taken previously.

Sunday, September 21, 2014

MIDI2VC+ UART loop test and analogue synth prototype demo

MIDI2VC+ UART loop test

Work on the MIDI2VC+ has been a bit down lately, since I'm studying for my ham radio license! It's seems like a fun hobby, so maybe I'll be building RF-stuff soon...
Anyway, my MIDI2VC submission to the hackaday prize got med a T-shirt, which I think is nice. I'm happy to get anything. I mean, the contest was about electronics connected to the Internet, which my project very much wasn't!
 In the MIDI2VC project I've finally gotten the mandatory UART loop test working. This is an important step when working with a new MCU, since a successful test means that the following is working:
  1. Oscillators are running
  2. Correct bad rate calculated means that oscillators are running at the frequency we expect them to be running at
  3. Interrupts are working
  4. IO's are working
Also, we now have a great output for debug info.
Here's the code:

 //PIC24FJ64GB004 UART loop test using interrupts
 //http://electev.blogspot.com  
 /*@ignore@*/  
 #include <xc.h>  
 /*@end@*/  
 _CONFIG1(JTAGEN_OFF & GCP_OFF & GWRP_OFF & FWDTEN_OFF & WINDIS_OFF & ICS_PGx3)  
 _CONFIG2(IESO_OFF & POSCMOD_NONE & OSCIOFNC_ON & FCKSM_CSDCMD & FNOSC_FRC & PLL96MHZ_OFF)  
 _CONFIG3(WPFP_WPFP0 & SOSCSEL_IO & WUTSEL_FST & WPDIS_WPDIS & WPCFG_WPCFGDIS & WPEND_WPENDMEM)  
 _CONFIG4(DSWDTPS_DSWDTPS3 & DSWDTOSC_LPRC & RTCOSC_LPRC & DSBOREN_OFF & DSWDTEN_OFF)  
 //*** UART1 Receive interrupt function ***  
 //**************************************** k  
 void __attribute__((__interrupt__, __auto_psv__)) _U1RXInterrupt(void) {  
   IFS0bits.U1RXIF = 0; //Reset UART1 Receive interrupt bit  
   U1TXREG = U1RXREG; //Transmit received character  
   return;  
 }  
 int main() {  
   TRISA = 0x02; //RA1 as input  
   AD1PCFG = 0xffff; //No analogue inputs  
   IFS0 = 0x0000; //Interrupts reset  
   IEC0 = 0x0800; //Uart recieve interrupt enabled  
   //Reconfigurable pin setup  
   __builtin_write_OSCCONL(OSCCON & 0xBF);  
   RPOR2bits.RP5R = 3; //RP5 as UART1 TX  
   RPINR18bits.U1RXR = 0x06; //RP6 as UART1 RX  
   __builtin_write_OSCCONL(OSCCON | 0x40);  
   U1BRG = 25;//Baud rate set to 9600, U1BRG = (8MHz/2)/(16*9600) - 1  
   U1MODE = 0x8800; //UART1 enabled in simplex mode  
   U1STA = 0x8400; //Interrupt when char is transferred to TSR and Transmit enabled  
   while (1) {  
   }  
   return 0;  
 }  

Analogue synth prototype demo

I realized that I don't have a proper demo video of the analogue synth prototype I built, so I made one and here it is:

Saturday, August 2, 2014

Button debounce, analogue VS digital

On the MIDI2VC, there is an unused button (named DEMO), which I want to use for an extra feature. For this new feature I need to debounce the button, one button press shall change state once, and only once. My first approach was to do this in software. After some fiddling I ended up with this code:
 //PIC16F1823 Button debounce using Interrupt On Change and timer overflow interrupts  
 /*@ignore@*/  
 #include <xc.h>  
 /*@end@*/  
 #include "header.h"  
 //Configuration bits  
 #pragma config WDTE=OFF, PWRTE = OFF, MCLRE=ON, BOREN=OFF, FCMEN=OFF, CLKOUTEN = OFF, IESO=OFF, FOSC=INTOSC, CPD=OFF, LVP = OFF, BORV = 0, PLLEN = OFF  
 #pragma switch speed  
 #define _XTAL_FREQ 32000000  
 void main() {  
   //TRISA  
   //TRISC  
   //RX(RC5), SCL(RC0) and SDA(RC1) as inputs  
   TRISA = 0b00010000;  
   TRISC = 0b00100011;  
      //Weak pull ups enabled on RA4  
   WPUA = 0b00010000;  
   //Set all I/O's to digital  
   ANSELA = 0x00;  
   ANSELC = 0x00;  
   PORTA = 0b00110000;  
   PORTC = 0x00; //Clear RC2 to unlight LED  
      //Enable Interrupt On Change on neagative slope on RA4  
   IOCAN = 0b00010000;  
      //No interrupt on positive slope  
   IOCAP = 0x00;  
      //Reset interrupt flag  
   IOCAF = 0x00;  
   //0 Internal oscillator, 3 <fosc> on, 6-4 31kHz  
   // OSCCON = 0b00000000;  
   OSCCON = 0b11110000;  
   //Interrupt controller  
   //5 Timer0 overflow interrupt enabled  
      //6 Peripheral interrupt enabled  
   //7 Global interrupt enabled  
      //3 Interrupt on change enabled  
   INTCON = 0b11101000;  
   //Timer0  
   TMR0 = 0x00;  
   //Option Register  
   //2-0 Prescaler 1:4  
   //3 prescaler assigned to Timer0  
   //4 timer edge, high to low  
   OPTION_REG = 0b01000101;  
   //Loop forever, interrupts when Timer0 overflows  
   while (1) {  
   }  
 }  
 //Interrupt routine  
 interrupt void isr(void) {  
   static char overFlow = 0;  
   if (TMR0IF == 1)  
   {  
     TMR0IF = 0;  
     overFlow++;  
     if (overFlow == 0)  
     {  
                //Reenable Interrupt On Change  
       IOCAN = 0b00010000;  
       INTCON = 0b11101000;  
     }  
   }  
   else if (IOCAF4 == 1)  
   {  
           //Disable Interrupt On Change  
     INTCON = 0b11100000;  
           //Toggle LED  
     LATC ^= 1 << 2;  
           //Reset Interrupt On Change flag  
     IOCAF4 = 0;  
   }  
   return;  
 }  

This is a very well controlled way to specify at which rate the button can be pressed without missing push-events, but as you can see, it adds quite a lot of code to the interrupt service routine. Since I have optimized my ISR quite a bit, I want to avoid adding code to it. I am also running out of data space in general, so that is also a reason not to add more code.
 So, I tried out debouncing the analog way, by adding a low pass filter between the button and the IO pin.
Analogue Switch Debouncer
The pull-up resistor in the MCU is of unknown value, but the data sheet calls it weak, so it's probably over 10kΩ.
 The analogue solution worked fine, but I need to do some strapping for it to work. I'll make a new version of the board that incorporates this.
Analogue Debounce strap