Trouble sending MIDI data over serial/COM port in C - c

I am writing a C program in Visual Studio 2013 to send MIDI data to a MIDI device over a serial (COM) port. My code thus far is as follows:
Opening the serial/COM port:
unsigned int SERIALCOMMS_OpenPort(HANDLE *hSerialPort,
unsigned int comPortNum,
unsigned int baudRate)
{
DCB dcbSerialParams = {0};
COMMTIMEOUTS timeouts = {0};
unsigned char portStr[COM_PORT_LEN_MAX];
/* Initialisations */
memset(portStr, 0x00, sizeof(portStr));
/* Construct the COM port string */
sprintf(portStr, "%sCOM%d", COM_PORT_PREFIX, comPortNum);
printf("Opening serial port...");
*hSerialPort = CreateFile((LPCSTR)portStr,
(GENERIC_READ | GENERIC_WRITE),
0,
NULL,
OPEN_EXISTING,
FILE_ATTRIBUTE_NORMAL,
NULL);
if (*hSerialPort == INVALID_HANDLE_VALUE)
{
if (GetLastError() == ERROR_FILE_NOT_FOUND)
{
printf("\nError: \nThe system cannot find the file specified (%s)\n", portStr);
return 1;
}
else if (GetLastError() == ERROR_INVALID_NAME)
{
printf("\nError: \n%s port name syntax is incorrect'\n", portStr);
return 1;
}
else
{
printf("\nHandle creation error code: %x\n", GetLastError());
return 1;
}
puts("\t...CreateFile returned an invalid handle value");
}
printf("OK\n");
/* Set device parameters */
dcbSerialParams.DCBlength = sizeof(dcbSerialParams);
if (GetCommState(*hSerialPort, &dcbSerialParams) == 0)
{
printf("Error getting device state\n");
CloseHandle(*hSerialPort);
return 1;
}
dcbSerialParams.BaudRate = baudRate;
dcbSerialParams.ByteSize = 8;
dcbSerialParams.StopBits = ONESTOPBIT;
dcbSerialParams.Parity = NOPARITY;
if (SetCommState(*hSerialPort, &dcbSerialParams) == 0)
{
printf("Error setting device parameters\n");
return 1;
}
/* Set COM port timeout settings */
timeouts.ReadIntervalTimeout = 50;
timeouts.ReadTotalTimeoutConstant = 50;
timeouts.ReadTotalTimeoutMultiplier = 10;
timeouts.WriteTotalTimeoutConstant = 50;
timeouts.WriteTotalTimeoutMultiplier = 10;
if (SetCommTimeouts(*hSerialPort, &timeouts) == 0)
{
printf("Error setting timeouts\n");
return 1;
}
return 0;
}
The constant COM_PORT_PREFIX is defined as follows:
#define COM_PORT_PREFIX "\\\\\.\\"
The port opens fine. However, when I send data to it, it seems that the received data is much different than what is supposed to be sent. I am testing this with an Arduino that is programmed to spool out the received data as integer/hex values, for purposes of testing what is actually being sent by the PC.
Here is the code of the function used to send the data:
unsigned int SERIALCOMMS_Send(HANDLE hSerialPort,
unsigned char *txData,
unsigned int *byteCount)
{
unsigned int bytesWritten = 0u;
/* Transmit data */
if (!WriteFile(hSerialPort, txData, *byteCount, &bytesWritten, NULL))
{
printf("Error transmitting data\n");
return 1;
}
printf("\n%d bytes written\n", bytesWritten);
return 0;
}
Using the following method with the above "Send" function:
unsigned int byteCount = 1u;
unsigned char dataByte[1];
SERIALCOMMS_Send(hSerialPort, dataByte, &byteCount);
When I send the following MIDI data (hex values), it gets received as follows:
0x91 gets received as 0xC9
0x92 gets received as 0xC8
0x93 gets received as 0xC9
0x94 gets received as 0xCA
0x95 gets received as 0xCB
0x24 gets received as 0xD2
Clearly, nothing of this makes sense. I am unable to figure out what is causing this. Some of the project properties in Visual Studio are configured as follows:
Project settings
One possible aspect might be the specified character set (currently set as "Use Multi-Byte Character Set"). If I change this to "Use Unicode Character Set", then the program is unable to connect with the COM port.
Thinking logically of the problem, it must have to do with the way I am sending the data. I am most probably passing the MIDI data to be sent in the wrong manner, but I honestly cannot figure out what is causing the problem and what I am doing wrong.
Any help will be greatly appreciated.
UPDATE:
The baud rate is set at 31250 bps (as per MIDI standard) on both the PC and the Arduino.

It seems that according to this answer on another thread on stackoverflow it is not that simple to just use non-standard baud rates on the Windows platform due to the crystal oscillation frequency used in PCs for calculating the UART baud rates and the way the baud rates are derived therefrom. Thus it seems that it is best to stick to standard baud rates.
Using a standard baud rate solved my problem. However, it thus enforces a change in the specifications on the hardware used in my case, which is not ideal.
This, of course, raises the following question - what does one have to do to be able to use non-standard baud rates? Would one have to write an additional/custom driver for that?

Related

C PIC32 USART_BufferAddRead lost bytes

in my project I need to connect over UART a PIC32MZ2048EFH144 and an external device. I set the USART peripheral in this way using Harmony v1.1:
CONFIG_USE_DRV_USART=y
CONFIG_DRV_USART_DRIVER_MODE="STATIC"
CONFIG_DRV_USART_INTERRUPT_MODE=y
CONFIG_DRV_USART_BYTE_MODEL_SUPPORT=n
CONFIG_DRV_USART_READ_WRITE_MODEL_SUPPORT=n
CONFIG_DRV_USART_BUFFER_QUEUE_SUPPORT=y
CONFIG_DRV_USART_SUPPORT_TRANSMIT_DMA=n
CONFIG_DRV_USART_SUPPORT_RECEIVE_DMA=n
CONFIG_DRV_USART_INSTANCES_NUMBER=2
CONFIG_DRV_USART_CLIENTS_NUMBER=2
CONFIG_DRV_USART_PERIPHERAL_ID_IDX1="USART_ID_4"
CONFIG_DRV_USART_BAUD_RATE_IDX1=9600
CONFIG_DRV_USART_XMIT_INT_PRIORITY_IDX1="INT_PRIORITY_LEVEL1"
CONFIG_DRV_USART_XMIT_INT_SUB_PRIORITY_IDX1="INT_SUBPRIORITY_LEVEL0"
CONFIG_DRV_USART_RCV_INT_PRIORITY_IDX1="INT_PRIORITY_LEVEL1"
CONFIG_DRV_USART_RCV_INT_SUB_PRIORITY_IDX1="INT_SUBPRIORITY_LEVEL0"
CONFIG_DRV_USART_ERR_INT_PRIORITY_IDX1="INT_PRIORITY_LEVEL1"
CONFIG_DRV_USART_ERR_INT_SUB_PRIORITY_IDX1="INT_SUBPRIORITY_LEVEL0"
CONFIG_DRV_USART_OPER_MODE_IDX1="DRV_USART_OPERATION_MODE_NORMAL"
CONFIG_DRV_USART_INIT_FLAG_WAKE_ON_START_IDX1=n
CONFIG_DRV_USART_INIT_FLAG_AUTO_BAUD_IDX1=n
CONFIG_DRV_USART_INIT_FLAG_STOP_IN_IDLE_IDX1=n
CONFIG_DRV_USART_LINE_CNTRL_IDX1="DRV_USART_LINE_CONTROL_8NONE1"
CONFIG_DRV_USART_HANDSHAKE_MODE_IDX1="DRV_USART_HANDSHAKE_NONE"
CONFIG_DRV_USART_XMIT_QUEUE_SIZE_IDX1=10
CONFIG_DRV_USART_RCV_QUEUE_SIZE_IDX1=10
CONFIG_DRV_USART_STATIC_RX_MODES_IDX1="USART_HANDSHAKE_MODE_FLOW_CONTROL"
CONFIG_DRV_USART_STATIC_OP_MODES_IDX1="USART_ENABLE_TX_RX_USED"
CONFIG_DRV_USART_STATIC_LINECONTROL_MODES_IDX1="USART_8N1"
CONFIG_DRV_USART_STATIC_TX_ENABLE_IDX1=y
CONFIG_DRV_USART_STATIC_RX_ENABLE_IDX1=y
CONFIG_DRV_USART_STATIC_TX_INTR_MODES_IDX1="USART_TRANSMIT_FIFO_NOT_FULL"
CONFIG_DRV_USART_STATIC_RX_INTR_MODES_IDX1="USART_RECEIVE_FIFO_ONE_CHAR"
At the start, the external device sends a wake-up message that I receive correctly and reply to with a wake-up ack.
After this sequence, I send a requestDevID ... at this point I have some trouble. Through the oscilloscope, I can see that the external device answers correctly to this request but in my code I don't get the whole message.
The answer is: 0xFA 0xFF 0x01 0x04 0x07 0x78 0x26 0x1A 0x3D
What I see (when I stop the debug) is: 0x78 0x26 0x1A 0x3D 0x07
My code is as follow:
void mti710USART1BufferHandler(DRV_USART_BUFFER_EVENT bufferEvent, DRV_USART_BUFFER_HANDLE hBufferEvent, uintptr_t context){
switch(bufferEvent){
case DRV_USART_BUFFER_EVENT_COMPLETE:{
if (context == 1){
// to-do
flag = 1;
countFlag += 1;
}
break;
case DRV_USART_BUFFER_EVENT_ERROR:{
if (context == 1){
// to-do
flag = -1;
}
}
break;
case DRV_USART_BUFFER_EVENT_ABORT:
break;
default:
break;
}
}
bool mti710Initialize(MTi710INSInitDriver_t mti710Init){
mtiData.dvrMTi710INSIndex = mti710Init.dvrMTi710INSIndex;
mtiData.drvUART.handle = DRV_HANDLE_INVALID;
mtiData.drvUART.baudrate = 115200;
memset(&mtiData.drvUART.TX.buffer, 0x00, sizeof(mtiData.drvUART.TX.buffer));
memset(&mtiData.drvUART.RX.buffer, 0x00, sizeof(mtiData.drvUART.RX.buffer));
mtiData.drvUART.handle = DRV_USART_Open(mtiData.dvrMTi710INSIndex, DRV_IO_INTENT_READWRITE | DRV_IO_INTENT_NONBLOCKING);
if (mtiData.drvUART.handle != DRV_HANDLE_INVALID) {
if (mti710SetBaudrate(mtiData.drvUART.handle, mtiData.drvUART.baudrate)){
DRV_USART_BufferEventHandlerSet(mtiData.drvUART.handle, mti710USART1BufferHandler, (uintptr_t) 1);
mtiData.drvMti710INSState = MTi710INS_STATE_IDLE;
return true;
}
}
return false;
}
static void UARTRead(uint8_t* readBuffer, uint32_t bufferSize){
USART_ReceiverOverrunErrorClear_Default(DRV_USART_INDEX_1);
while (DRV_USART_ClientStatus(mtiData.drvUART.handle) != DRV_USART_CLIENT_STATUS_READY);
DRV_USART_BufferAddRead(mtiData.drvUART.handle, &(mtiData.drvUART.RX.bufferHandle), readBuffer, bufferSize);
}
...
...
uint32_t mti710ReadDeviceID(struct XbusParser* parser, const uint32_t timeout_us){
struct XbusMessage requestId = {XMID_ReqDid, 0, NULL};
mtiData.drvMti710INSState = MTi710INS_REQ_READ_ID;
if (flag == 0){
mti710WriteData(&requestId);
flag = 0;
}
mti710ReadData(9);
if (flag == 1){
XbusParser_parseBuffer(parser, (uint8_t*)&mtiData.drvUART.RX.buffer[0], sizeof(mtiData.drvUART.RX.buffer));
flag = 0;
return parser->currentMessage.mid == XMID_DeviceId ? (uint32_t)parser->currentMessage.data : -1;
} else {
return -1;
}
}
Any idea of my mistakes?
regards,
Vincenzo.
First thing:
When you read a hardware register, like the UART RX register, from within your application code, you must disable the UART RX interrupt.
The UART RX register is a shared resource.
UART RX register is shared by the the application code, (executed in background), and the interrupt code (executed in foreground).
If you don't disable the UART RX interrupt than your application code might be interrupted in the middle of the reading and get errors.
Shared resources must be read this way:
char a;
uart__disable_rx_interrupt(); // Begin of critical section
a = UART_RX_REGISTER;
uart__enable_rx_interrupt(); // End of critical section
Yet:
The application code should not disable too frequently the UART RX interrupt because the UART interface may miss some incoming data.
It happened to me back in 1996.
The ideal code application code would be at 9600 Baudrate:
char a;
sleep(100); // 100 ms
uart__disable_rx_interrupt(); // Begin of critical section
a = UART_RX_REGISTER;
uart__enable_rx_interrupt(); // End of critical section
printf(a);
One last thing;
Often, data are placed in a ring buffer
sleep(100); // 100 ms
uart__disable_rx_interrupt(); // Begin of critical section
a = UART_RX_REGISTER;
uart__write_in_ring_buffer(a);
uart__enable_rx_interrupt(); // End of critical section
uart__write_in_ring_buffer(&ch);
printf(ch);
I suggest you to read Jean Labrosse's book: "https://www.amazon.it/Embedded-Systems-Building-Blocks-Ready/dp/0879304405"
Study the UART device driver which Jean wrote making use of ring buffer.

Device or resource busy while configuring gpio as a char device

I am trying to configure a GPIO pin as output but it is failing with the reason of device or resource busy. The pin is configured as output, open-drain and belongs to the group of gpiochip24 at offset 3. On reading the information from line info IOCTL I can see that the flag is 3 (OPEN_DRAIN) and is assigned a consumer. But when I try to configure the pin as output with a default value using the GPIO_GET_LINEHANDLE_IOCTL, the IOCTL fails.
int gpioFd = open("/dev/gpiochip24", 0);
if (gpioFd < 0) {
printf("ERROR: GPIO chip fail\n");
return -1;
}
struct gpiohandle_request req;
req.flags |= GPIOHANDLE_REQUEST_OUTPUT;
req.lineoffsets[0] = 3;
req.lines = 1;
req.default_values[0] = 0;
strcpy(req.consumer_label, "P_EN");
int lhfd = ioctl(gpioFd, GPIO_GET_LINEHANDLE_IOCTL, &req);
if(lhfd < 0)
{
int err = errno;
printf("Error No: %d\n", err);
printf("ERROR: Gpio Line handle\n");
return -1;
}
Output:
Error No: 16
ERROR: Gpio Line handle
I looked inside /sys/kernel/debug/gpio to understand who is using the resource but I get the following response:
gpiochip24: GPIOs 99-106, parent: platform/139b0000.pinctrl, gpg2
How do I resolve this error of device busy?
Because req is local, it has garbage when allocated, and it doesn't look like the code is initializing it properly, and - in particular - the flags value probably has junk in it.
req.flags |= GPIOHANDLE_REQUEST_OUTPUT; // no
req.flags = GPIOHANDLE_REQUEST_OUTPUT; // yes
would work around this particular issue, but be sure all the other fields in this structure are not relying on junk.

PIC16LF1824 SPI Slave Interface

I am trying to receive multiple bytes over SPI. The aim is when the master starts the SPI transfer, slave MCU is interrupted, and it should read the data via SPI and store it in an array, which will be then used by my application for other operations such as determining the device ID and the contents of the packet.
void interrupt __high_priority my_isr_high(void) {
if (PIR1bits.SSP1IF) { // Interrupt from SPI?
rx[buffer_pointer] = SSP1BUF; // Get data from MSSP and store in RX buffer
buffer_pointer++; // Next data
if (buffer_pointer < FRAME_SIZE) // Ended?
SSP1BUF = tx[buffer_pointer]; // Send next byte to SPI
else
buffer_pointer = FRAME_SIZE;
PIR1bits.SSP1IF = 0; // Clear interrupt flag
}
}
However, I am not receiving the 3 bytes correctly. I am sending the following from the master:
dataPacket[0] = 0x43; // Decimal 67
dataPacket[1] = 0x42; //66
dataPacket[2] = 0x41; //65
While I am receiving as follows from the ISR():
rx[0]: 67
rx[1]: 65
rx[2]: 67
Am I missing something or handling the SPI incorrectly?
This will really solve the issue that I am stuck with and maybe will also help others who what to rx multiple bytes.
I am sharing my codes here so that it helps to find the solution quickly. Also included is a .zip file for compiling. Check the Codes here
So far the above code did not work for me properly. Therefore, after a little bit of digging online and other forums I found the following way to read multiple bytes:
uint8_t SPI_ExchangeHandler(uint8_t byte){
static uint8_t i = 0;
for(i=0; i<3; i++){
SSP1BUF =0x00;
while(!SSP1STATbits.BF);
rx_buff[i]=SSP1BUF;
}
State = SEND;
return byte;
}
Although the above codes give me what expected (i.e, correct data packets in the ordered manner), however, it misses two SPI interrupts every time and then displays/captures the correct data. Hence, two sets of data are always lost and then the third one is received correctly.
Is something wrongly configured or missing?
Finally, I managed to receive all the 3 bytes correctly. Sharing the codes below:
My interrupt service routine that triggers the MCU when master SPI has data to send.
void interrupt INTERRUPT_InterruptManager (void){
if(PIE1bits.SSP1IE == 1 && PIR1bits.SSP1IF == 1)
{
SPI_ISR();
}
}
The SPI_ISR code was autogenerated by the MCC GUI.
void SPI_ISR(void)
{
SSP1BUF = SPI_xchgHandler(SSP1BUF);
}
void SPI_setExchangeHandler(uint8_t (* InterruptHandler)(uint8_t))
{
SPI_xchgHandler = InterruptHandler;
}
Then I handle the SPI via a custom function using SPI_setExchangeHandler() as follows:
#define FRAME_SIZE 10 // Frame fixed size
volatile static uint8_t rx_buff[FRAME_SIZE]; //RX buffer
uint8_t SPI_ExchangeHandler(uint8_t byte)
{
static uint8_t i = 0;
rx_buff[i]=SSP1BUF;
i++;
if(i <= 2){
rx_buff[i]=SSP1BUF;
SSP1BUF = 0x00;
while(!SSP1STATbits.BF){};
i++;
}
else{
i = 2;
}
PIR1bits.SSP1IF = 0; // Clear the SPI interrupt flag
State = SEND;
return byte;
}
And I print out the values as follows for debugging:
printf("CMD:%d \n", rx_buff[0]);
printf("BUF1: %d \n", rx_buff[1]);
printf("BUF2: %d \n\n", rx_buff[2]);
However, I am pretty sure this is not the best/optimized way to handle multiple bytes from SPI, therefore, if there is an alternative, share...

PIC18F25K80 sending string through USART not working

I'm programming a few libraries for a board with a PIC18F25K80 built-in. Right now I'm trying to program the UART library and I've tried everything but I cannot make it work when it comes to send a string of chars.
I'm using the XC8 compiler and I have the following code in the library: (I haven't programmed the interruptions yet, that's why you can't see anything related to that in the code.
void UARTsend(char data){
UARTbusy();
TXREG1 = data;
}
void UARTsendTEXT(unsigned char *text){
while(*text != '\0'){
UARTsend(*(text++));
}
}
char UARTbusy(){
return TXSTA1bits.TRMT;
}
And this code in the main file:
int main() {
UARTconfig(_BR_19200, _RxINT_OFF, _TxINT_OFF, _8BIT);
unsigned char data[20] = "ABCDEFGHIJ";
while(1){
if(UARTrxREAD() == 'a'){
UARTsendTEXT(data);
}
}
return 0;
}
So, when I hit 'a', the string should be sent but instead of seeing the string, I receive the first and last letter, and sometimes just the first letter.
Honestly, I believe it is a really basic problem with the code, but I tried everything I could think about and nothing worked, so maybe someone here can help me with that.
EDIT: just in case you need to check it out:
void UARTconfig(unsigned int BaudRate, unsigned int RxINT, unsigned int TxINT, unsigned int BIT){
int br_data;
//Clock configuration at 16MHz
OSCCONbits.IRCF = 0b111;
//9-bit transmit enable bit.
if(BIT == 1) {
RCSTA1bits.RX9 = 1; //Reception 9-bit.
TXSTA1bits.TX9 = 1; //Transmission 9-bit.
}
else {
RCSTA1bits.RX9 = 0; //Reception 8-bit.
TXSTA1bits.TX9 = 0; //Transmission 8-bit.
}
//Enable serial port.
RCSTA1bits.SPEN = 1;
//Enable continuous reception.
RCSTA1bits.CREN = 1;
//Setting asynchronous mode.
TXSTA1bits.SYNC = 0;
//Enable transmission
TXSTA1bits.TXEN = 1;
//Setting Rx/Tx pins as output.
TRISC7 = 0;
TRISC6 = 0;
//Baud rate configuration
BAUDCON1bits.BRG16 = 1; //16bit Baud Rate generator
TXSTA1bits.BRGH = 0; //Low speed BR.
switch(BaudRate){
case 0:
br_data=415;
break;
case 1:
br_data=103;
break;
case 2:
br_data=51;
break;
case 3:
br_data=16;
break;
case 4:
br_data=8;
}
SPBRGH1:SPBRG1 = br_data;
}
The function UARTbusy should be waiting for status, or its caller should be. But the transmit register status is read once and ignored.
There is typically a two-stage buffer for transmitted data. Values written to the interface register are held until the shift register is empty, and the device remains 'busy' until then.
When you write the first data, it is transferred immediately to the shift register, so writing the second data immediately is harmless. But you then keep on over-writing the contents of the output register until it holds the last character of your message. Then when the shift register becomes empty, the last character of your message is sent.
Remember that the shift register is shifting bits out relatively slowly - at the baud rate. That is why the status bit needs to be checked.

C8051F340 USB device data transfer silicon lab IDE

I am trying to write a device code for C8051F340 to get the data from the host(PC) via USB. I have some example from silicon lab and the code look like below:
void Receive_File(void)
{
ReadStageLength = ((BytesToRead - BytesRead) > MAX_BLOCK_SIZE_READ)? MAX_BLOCK_SIZE_READ:(BytesToRead - BytesRead);
BytesRead += Block_Read((U8*)(&TempStorage[BlockIndex]), ReadStageLength); // Read Block
BlockIndex++;
// If device has received as many bytes as fit on one FLASH page, disable interrupts,
// write page to flash, reset packet index, enable interrupts
// Send handshake packet 0xFF to host after FLASH write
if ((BlockIndex == (BLOCKS_PR_PAGE)) || (BytesRead == BytesToRead))
{
Page_Erase((U8*)(PageIndices[PageIndex]));
Page_Write((U8*)(PageIndices[PageIndex]));
PageIndex++;
Led1 = !Led1;
BlockIndex = 0;
Buffer[0] = 0xFF;
Block_Write(Buffer, 1); // Send handshake Acknowledge to host
}
// Go to Idle state if last packet has been received
if (BytesRead == BytesToRead) {M_State = ST_IDLE_DEV; Led1 = 0;}
}
// Startup code for SDCC to disablt WDT before initializing variables so that
// a reset does not occur
#if defined SDCC
void _sdcc_external_startup (void)
{
PCA0MD &= ~0x40; // Disable Watchdog timer
}
#endif
I have some questions want to ask:
1. Where the data goes? the Buffer [0]?
2. if I got a Hex value transfer from the host, can I just read the Buffer [0] to get it ?
sorry I am a newbie.
Thank you.
Your received data stored in array TempStorage
You used Buufer[0] (the value 0xFF) for to send data to host

Resources