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.