Saturday, January 31, 2015
MIDI to VC conversion is working
I am now actually having a working path from USB to control voltage. I tried hooking it to my messy synthesizer,which doesn't seem to work. I then discovered that the converter only works if PicKit2 or the I2C analyzer is connected to it. My thought is that there is some issue with grounding in the board. I'll look into this. The actual working code and HEX is here. It still contains a lot of debug code though, and it doesn't sport all features yet...
Tuesday, January 20, 2015
I2C, UART and USB
I finally got all three interfaces working at the same time. While the PIC24FJ64GB004 hammers out I2C data, it configures and reports about an USB device! This is so cool, I took a not so cool screenshot:
All that is left now is to write the algorithms for how to handle received data.
All three interfaces used at the same time! |
Monday, January 19, 2015
PIC24FJ64GB004 I2C setup
I've been working on the I2C-setup on the MIDI2VC+ for a couple of days. First off I soldered the DAC and accompanying components to the board. I have been a bit worried about the I2C bus since it is connected to both 5V and 3V3 interfaces. The PIC has 3.3V logic and the DAC 5V. The I2C bus runs on 5V and the PIC I2C pins can tolerate 5.5V, so I thought that it might work since both devices compatible logic levels.
Running an I2C-bus this way is out of spec and may mean that you cannot run it full speed. Some testing proved that it was possible to run the bus at 360MHz without errors. I used the Beagle I2C analyzer from TotalPhase, and it was really good for analyzing lots of I2C data to see how much errors there were in the transfers. I ended up running the bus at 100kHz, to save power and add robustness.
Since I didn't have a digital oscilloscope previously, I adopted an old Tektronix 4030 that was being scrapped at work. This must be one of the earliest generations of DSO's, the scope looks very similar to my Tek 4065. I did get it running the way I wanted it to, but it wasn't that user friendly. You had to go into a menu blip yourself to the "Normal" trigger mode, a function that usually have it's own front panel button on modern scopes...
Running an I2C-bus this way is out of spec and may mean that you cannot run it full speed. Some testing proved that it was possible to run the bus at 360MHz without errors. I used the Beagle I2C analyzer from TotalPhase, and it was really good for analyzing lots of I2C data to see how much errors there were in the transfers. I ended up running the bus at 100kHz, to save power and add robustness.
Since I didn't have a digital oscilloscope previously, I adopted an old Tektronix 4030 that was being scrapped at work. This must be one of the earliest generations of DSO's, the scope looks very similar to my Tek 4065. I did get it running the way I wanted it to, but it wasn't that user friendly. You had to go into a menu blip yourself to the "Normal" trigger mode, a function that usually have it's own front panel button on modern scopes...
Tektronix 4030 capture of I2C transmission. Data on top trace, clock on bottom trace. |
//I2C setup:
I2C1CON = 0x8000; //I2C module enabled
I2C1BRG = 0x13c; //= (32000000/100000 - 32000000/10000000) - 1, 100kHz SCL
//Function i2cTransmission
//Polls flag to see if there is I2C data to be sent and
//walks through the transmission process
uint16_t i2cTransmission(uint16_t i2cTransmitCycle, uint16_t *i2cstatus, uint16_t i2cData[]) {
//Polls transmit cycle flag, I2C interrupt flag and ACK-status
switch (i2cTransmitCycle) {
case 0:
if (*i2cstatus == 1) {
i2cTransmitCycle = 1;
I2C1CONbits.SEN = 1; //start condition
}
break;
case 1:
if (I2C1CONbits.SEN == 0) { //when start condition is complete, load slave address
IFS1bits.MI2C1IF = 0;
I2C1TRN = (0x60 << 1);//load DAC address
i2cTransmitCycle++;
}
break;
case 2:
//when address is ACKed:
if (IFS1bits.MI2C1IF == 1 && I2C1STATbits.ACKSTAT == 0) {
IFS1bits.MI2C1IF = 0;
I2C1TRN = i2cData[0]; //load first data byte
i2cTransmitCycle++;
}
break;
case 3:
if (IFS1bits.MI2C1IF == 1 && I2C1STATbits.ACKSTAT == 0) {
IFS1bits.MI2C1IF = 0;
I2C1TRN = i2cData[1]; //load second data byte
i2cTransmitCycle++;
}
break;
case 4:
if (IFS1bits.MI2C1IF == 1 && I2C1STATbits.ACKSTAT == 0) {
I2C1CONbits.PEN = 1; //stop condition
i2cTransmitCycle++;
}
break;
case 5:
if (I2C1CONbits.PEN == 0) { //when stop condition is finished, transfer is complete
i2cTransmitCycle = 0;
*i2cstatus = 0;
}
break;
default:
break;
}
return i2cTransmitCycle;
}
Sunday, January 4, 2015
Receiveing MIDI data!
Thursday, January 1, 2015
USB reached configured state!
OK, I kind of gave up on extracting and reading all configuration data from the Microkey-25, so I cheated a bit and read the USB packets from Free Device Monitoring Studio. Anyway, I sent the SetConfiguration command to the Device, and lo and behold, the red LED on the keyboard lit up. This must mean that the device is configured! Now all I need to do is start extracting data from the keyboard...
USB getConfigurationDescription
Let's continue by receiving the descriptor for configuration 1 (the only configuration supplied by the device)
4002 0105 0900 2002 0224 0604 0120 0130 0103 2409 0001 1001 4002 0324 0903 1001 0224 0600 2501 0001 2407 0000 0301 0200 0004 0932 8000 0101 0053 0209
The rest of the supplied data should be descriptors for interfaces and endpoints:
Now, the next entry puzzles me, descriptor is of type 0x24. I found this post, that explaines that this is a class specific interface descriptor. I'll have to look into this some more.
4002 0105 0900 2002 0224 0604 0120 0130 0103 2409 0001 1001 4002 0324 0903 1001 0224 0600 2501 0001 2407 0000 0301 0200 0004 0932 8000 0101 0053 0209
Byte | Field | Value | Meaning |
---|---|---|---|
0 | bLength | 0x09 | The Configuration description consists of 9 bytes |
1 | bDescriptorType | 0x02 | Descriptor type CONFIGURATION |
2-3 | wTotalLength | 0x0053 | Total length of configuration, including descriptors for configuration, interfaces and endpoints |
4 | bNumInterfaces | 0x01 | Configuration has 1 interface |
5 | bConfigurationValue | 0x01 | The value of this configuration is 1 |
6 | iConfiguration | 0x00 | String index 0 describes this configuration |
7 | bmAttributes | 0x80 | Device powered by bus and has no remote wake up feature |
8 | bMaxPower | 0x32 | Max power consumption is 50*2mA = 100mA |
The rest of the supplied data should be descriptors for interfaces and endpoints:
Interface descriptor
This descriptor starts with byte 9 in the data above. The first value is the length of the descriptor, which we can see is 0x09. That means that the data to interpret is:
0000 0301 0200 0004 09
Byte | Field | Value | Meaning |
---|---|---|---|
0 | bLength | 0x09 | The Interface description consists of 9 bytes |
1 | bDescriptorType | 0x04 | Descriptor type INTERFACE |
2 | bInterfaceNumber | 0x00 | Interface is number 0 |
3 | bAlternateSetting | 0x00 | Value to select this alternate setting |
4 | bNumEndpoints | 0x02 | This interface uses two endpoints |
5 | bInterfaceClass | 0x01 | Interface class is 1 |
6 | bInterfaceSubClass | 0x03 | Interface sub class is 3 |
7 | bInterfaceProtocol | 0x00 | Device does not use class-specific protocol |
8 | iInterface | 0x00 | String index for this descriptor is 0 |
Now, the next entry puzzles me, descriptor is of type 0x24. I found this post, that explaines that this is a class specific interface descriptor. I'll have to look into this some more.
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.
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...
Subscribe to:
Posts (Atom)