Triggering Interrupt for any byte received - stm32

I'm trying to get a code to work that triggers an interrupt for a variable data size coming to a RX input of a STM32 board (not discovery) in DMA Circular mode. ex.:CONNECTED\r\nDATAREQUEST\r\n
So far so good, I'm being able to receive data and all, while also triggering the DMA interrupt.
I will then create a sub RX message processing buffer breaking down each \r\n to a different char array pointer.
msgProcessingBuffer[0] = "COM_OK"
msgProcessingBuffer[1] = "DATAREQUEST"
msgProcessingBuffer[n] = "BlahBlahBlah"
My problem comes actually from the trigger of the interrupt. I would like to trigger the interrupt from any amount of data and processing any data received.
If I use the interrupt request bellow:
HAL_UART_Receive_DMA(&huart1,uart1RxMsgBuffer, 30);
The input buffer will take 30 bytes to trigger the interrupt, but that's too much time to wait because I would like to process the RX data as soon as a \r\n is found in the string. So I cannot wait for the full buffer to fill to begin processing it.
If I use the interrupt request bellow:
HAL_UART_Receive_DMA(&huart1,uart1RxMsgBuffer, 1;
It will trigger as I want, but there is no point on using DMA in this case because it will trigger the interrupt for every byte and will create a buffer of just 1 byte (duh) just like in "polling mode".
So my question is, how do I trigger the DMA for the first byte received but still receive/process all data that might come after it in a single interrupt? I believe I might be missing some basic concept here.
Best regards,
Blukrr

In short: HAL/SPL libraries don't provide such feachures.
Generally some MCUs, for example STM32F091VCT6 have hardware supporting of Modbus and byte flow analysis (interrupt by recieve some control byte) - so if you will use such MCU in you project, you can configure receive by circular DMA with interrupts by receive '\r' or '\n' byte.
And I repeat: HAL or SPL don't support this features, you can use it only throught work with registers (see reference manuals).

I was taking a look at some other forums and I've found there a work around for this problem.
I'm using a DMA in circular mode and then I monitor the NDTR which updates its value every time a byte is received through the UART interface. Then I cyclically call a function (in while 1 loop or in a cyclic interrupt handler) that break down each message part always looking for /n /r chars. This function also saves the current NDTR value for comparison if it has changed since the last "while 1" cycle. If the NDTR has changed since last cycle I wait a couple milliseconds to receive the remaining message (UART it's too slow to transmit) and then save those received messages in a char buffer array for post processing.
If you create a circular DMA buffer of about 50 bytes (HAL_UART_Receive_DMA(&huart1,uart1RxMsgBuffer, 50)) I think it's enough to compensate any fluctuations in the program cycle.

In the mean time I opened a ticket to ST and they confirmed what you just said they also added:
SOLUTION PROPOSED BY SUPPORTER - 14/4/2016 16:45:22 :
Hi Gilberto,
The DMA interrupt requests available are listed on Table 50 of the Reference Manual, RM0090, http://www.st.com/web/en/resource/technical/document/reference_manual/DM00031020.pdf. Therefore, basically, the DMA interrupt can only trigger at the end of one of these events.
• Half-transfer reached
• Transfer complete
• Transfer error
• Fifo error (overrun, underrun or FIFO level error)
• Direct mode error
Getting a DMA interrupt to trigger upon reception of a specific character in your receive data stream is not possible. You may want to trigger the interrupt when you receive packets of say 30 bytes each and then process the datastring to check if your \r\n chars have arrived so you can process the data block.
Regards,
MCU Tech Support

Related

Is there a way to do uart_recieve without using "while" on stm32?

I want to receive data using UART_Receive.
However, if UART_Receive is not included in the while statement, the data will not be received properly.
I don't want to impose restrictions on executing certain events and other code when uart occurs.
Is there any way to get the data when uart occurs at any time?
I am currently using UART_RECEIVE_DMA.
I can suggest you to use UART idle interrupt
void My_UART_IRQHandler(UART_HandleTypeDef *huart)
{
if (__HAL_UART_GET_FLAG(huart, UART_FLAG_IDLE))
{
__HAL_UART_CLEAR_IDLEFLAG(huart);
// data is stored in uartData
}
}
void InitUART(void)
{
__HAL_UART_ENABLE_IT(&huart, UART_IT_IDLE);
HAL_UART_Receive_DMA(&huart, uartData, size);
}
Go to USARTx_IRQHandler in stm32xxxx_it.c and add call My_UART_IRQHandler:
void USART1_IRQHandler(void)
{
/* USER CODE BEGIN USART1_IRQn 0 */
/* USER CODE END USART1_IRQn 0 */
HAL_UART_IRQHandler(&huart1);
/* USER CODE BEGIN USART1_IRQn 1 */
My_UART_IRQHandler(&huart1);
/* USER CODE END USART1_IRQn 1 */
}
Don't forget to enable UART interrupts and use DMA for UART TX
In three ways UARTdata can be received.
polling
Interrupt
DMA
DMA or interrupt UART receive methods can be triggered anytime when the UART signal occurs. So using UART_RECEIVE_DMA and "imposing restrictions on executing certain events and other code when uart occurs" is kind of strange to me.
In the DMA method, you do not need to call the UART to receive on the while() loop. For learning and receiving fixed-length data can try this resource.
If the data length is unknown can use IDLE line detection. Use this resource from controllers tech for more details.
One way is an interrupt-based circular FIFO queue.
Issue a recieve-call for a byte (or more), when the interrupt service routine is called, stuff the byte/s in the FIFO and then process the data in-between.
This allows for data reception to be done quickly, so you can do the other things that seem to be a worry.
If you're worried about servicing the other peipherals, you may want to go with a pre-emptive approach with either a Real-time Operating System, or priority-based interrupts. This will give you control over when exactly things are serviced.

STM32 UART in DMA mode stops receiving after receiving from a host with wrong baud rate

The scenario: I have a STM32 MCU, which uses an UART in DMA Mode with Idle Interrupt for RS485 data transfer. The baud rate of the UART is set in CubeMX, in this case to 115200. My Code works fine, when the Host uses the correct baud rate, it is also "long time" stable, no issues or worries.
BUT: when I set the wrong baud rate at the host, e.g. 56700 instead of 115200, the UART stops receiving data, even if I later set the baud rate at the host to the same baud rate the Microcontroller uses, it won't work. The only way to solve this issue so far is: reset the MCU and connect again with the correct baud rate.
To give you some (Pseudo-)Code:
uint8_t UART_Buf[128];
HAL_UART_Receive_DMA(&huart2, UART_Buf, 128);
__HAL_UART_ENABLE_IT(&huart2, UART_IT_IDLE);
Or in Plain Words: there is a UART Buffer for DMA (UART_Buf[128]) and the UART is started with HAL_UART_Receive_DMA(...), DMA Rx is set to circular mode in CubeMX, also the Idle-Interrupt is activated, using the HAL Macro: __HAL_UART_ENABLE_IT(...); This code works fine so far.
Works fine means:
when I transmit data from my PC to the Micro, the (one) Idle Interrupt is triggered (correctly) by the MCU. In the ISR I set a flag, to start the data parsing afterwards. I receive exactly the number of bytes I have sent, and all is fine.
BUT: when I make the wrong setting in my Terminal Program and instead of the (correct) baud rate of 115200, the baud rate select menu is set to e.g. 57600, the trouble begins:
The idle interrupt will still trigger after each transmission.
But it triggers 2-4 times in a quick "burst" (depending on the baud rate) and the number of bytes received is 0. I'd expect at least some bs data, but there is exactly 0 data in the buffer - which I can check with the debugger. There is obviously received nothing. When I change the baud rate in my terminal program and restart it, there is still nothing received on the MCU.
I could live with 0 received bytes, if the baud rate of the host is incorrect, but it's pretty uncool that one incoming transmission of a host with the wrong baud rate disables the UART until a hardware reset is done.
My attempts to resolve this were so far:
count the "Idle Interrupt Bursts" in combination with 0 received bytes to trigger a "self reset" routine, that stops the UART and restarts it, using the MX_USART2_UART_Init(); Routine. With zero effect. I can see the Idle Interrupt is still triggered correctly, but the buffer remains empty and no data is transferred into the buffer. The UART remains in a non-receiving state.
The Question
Has anyone out there experienced similar issues, and if yes: how did you solve that?
Additional Info: this happens on a STM32F030 as well as on a STM32G03x
When you send to the UART at the wrong baud rate it will appear to the receiver as framing errors and/or noise errors. It could also appear as random characters being received correctly, but this is less likely so don't be surprised to have nothing in your buffer.
When you are receiving with DMA, it is normal to turn the error interrupt on or else poll the error bits. When an error is detected you would then re-initialize everything and restart the DMA. This sounds like what you are trying to do by counting the idle interrupts, but you are just not checking the right bits.
If you don't want to do that, it is not impossible to imagine that you have nothing to do at the driver level and want to try to do the resynchronisation at a higher level (eg: start reading again and discard everything until a newline character) but you will have to bear in mind at least two things:
First, make sure you clear the DDRE bit in the USART_CR3 register. The name "DMA Disable on Reception Error" speaks for itself.
Second, the UART peripheral is able to self resynchronize, as long as you have an idle gap between bytes. If you switch the transmitter to the correct baud rate but keep blasting out data then the receiver may never correctly identify which bit is a start bit.
After investigating this issue a little bit further, i found a solution.
Abstract:
When a host connects to the MCU to an UART with an other baud rate than the UART is set to, it will go into an error state and stop DMA transmission to the RX Buffer. You can check if there is an error with the HAL_UART_GetError(...) function. If there is an error, stop the UART/DMA and restart it.
The Details:
First of all, it was not the DDRE bit in the USART_CR2 register. This was set to 0 by CubeMX. But the hint of Tom V led me into the right direction.
I tried to recover the UART by playing around with the register bits. I read through the UART section of the reference manual multiple times and tried to figure out, which bits to set in which order, to resolve the error condition manually.
What I found out:
When a transmission with the wrong baud rate is received by the UART the following changes in the UART Registers occur (on an STM32F030):
Control register 1 (USART_CR1) - Bit 8 (PEIE) goes from 1 to 0. PEIE is the Parity Interrupt Enable Bit.
Control register 2 (USART_CR2) - remains unchanged
Control register 3 (USART_CR3) - changes from 0d16449 to 0d16384, which means
Bit 0 (EIE - Error Interrupt enable) goes from 1 to 0
Bit 6 (DMAR - DMA enable receiver) goes from 1 to 0
Bit 14 (DEM - Driver enable mode) remains unchanged at 1
USART_CR3.DEM makes sense. I am using the RS485-Functionality of the F030, so the UART handles the Driver-Enable GPIO by itself.
the transition from 1 to 0 at USART_CR3.EIE and USART_CR3.DMAR are most probably the reason why no more data are transfered to the DMA buffer.
Besides that, the error Flags in the Interrupt and status register (USART_ISR) for ORE and FE are set. ORE stands for Overrun Error and FE for Frame Error. Although these bit can be cleared by writing a 1 to the corresponding bit of the Interrupt flag clear register (USART_ICR), the ErrorCode in the hUART Struct remains at the intial error value.
At the end of my try&error process, I managed to have all registers at the same values they had during valid transmissions, but there were still no bytes received. Whatever i tried, id had no effect. The UART remained in a non receiving state. So i decided to use the "brute force" approach and use the HAL functions, which I know they work.
Finally the solution is pretty simple:
if an Idle Interrupt is detected, but the number of received bytes is 0
=> check the Error-Status of the UART with HAL_UART_GetError(...)
If there is an error, stop the UART with HAL_UART_DMAStop(...) and restart it with HAL_UART_Receive_DMA(...)
The code:
if(RxLen) {
// normal execution, number of received bytes > 0
if(UA_RXCallback[i]) (*UA_RXCallback[i])(hUA); // exec RX callback function
} else {
if(HAL_UART_GetError(&huart2)) {
HAL_UART_DMAStop(&huart2); // STOP Uart
MX_USART2_UART_Init(); // INIT Uart
HAL_UART_Receive_DMA(&huart2, UA2_Buf, UA2_BufSz); // START Uart DMA
__HAL_UART_CLEAR_IDLEFLAG(&huart2); // Clear Idle IT-Flag
__HAL_UART_ENABLE_IT(&huart2, UART_IT_IDLE); // Enable Idle Interrupt
}
}
I had a similar issue. I'm using a DMA to receive data, and then periodically checking how many bytes were received. After a bit error, it would not recover. The solution for me was to first subscribe to ErrorCallback on the UART_HandleTypeDef.
In the error handler, I then call UART_Start_Receive_DMA(...) again. This seems to restart the UART and DMA without issue.

what's the application of sequential transmission of I2C in HAL library in STM32f746ng

I can understand that you can use first frame option for first frame and next frame options for others, but since you can use them as FIRS_FRAME_LAST_FRAME, what is the advantage of other? and when we must use them?
Findings:
A code use wile to continuously transmit two number and get a callback to see if module has accepted that, if this happen correctly the led must blink.
In this simple code I've tested every xferoption of sequential transmission, every options worked except: I2C_LAST_FRAME_NO_STOP and I2C_FIRST_FRAME.
Code:
while (1)
{
value=300;
*(uint16_t*) buffer=(value<<8)|(value>>8);//Data prepared for DAC module
HAL_I2C_Master_Seq_Transmit_IT (&hi2c1, (MCP4725A0_ADDR_A00<<1), buffer, 2,I2C_LAST_FRAME_NO_STOP);
HAL_Delay(1);
HAL_I2C_Master_Receive(&hi2c1, (MCP4725A0_ADDR_A00<<1), rxbuffer, 3, 1000);
if( (uint16_t)(((uint16_t)rxbuffer[1])<<8|((uint16_t)rxbuffer[2]))>>4 == value ){
HAL_GPIO_WritePin(LED_GPIO_Port,LED_Pin,GPIO_PIN_SET);}
HAL_Delay(50);
value=4000;
*(uint16_t*) buffer=(value<<8)|(value>>8);
HAL_I2C_Master_Seq_Transmit_IT (&hi2c1, (MCP4725A0_ADDR_A00<<1), buffer, 2,I2C_LAST_FRAME_NO_STOP);
HAL_Delay(1);
HAL_I2C_Master_Receive(&hi2c1, (MCP4725A0_ADDR_A00<<1), rxbuffer, 3, 1000);
if( (uint16_t)(((uint16_t)rxbuffer[1])<<8|((uint16_t)rxbuffer[2]))>>4 == value ){
HAL_GPIO_WritePin(LED_GPIO_Port,LED_Pin,GPIO_PIN_RESET);}
HAL_Delay(50);
}
The HAL sometimes poorly documents these variables functions, and you will need to dive into the reference manual !
Looking at what the #defines are
https://github.com/STMicroelectronics/STM32CubeF7/blob/f8bda023e34ce9935cb4efb9d1c299860137b6f3/Drivers/STM32F7xx_HAL_Driver/Inc/stm32f7xx_hal_i2c.h#L302-L307
/** #defgroup I2C_XFEROPTIONS I2C Sequential Transfer Options
* #{
*/
#define I2C_FIRST_FRAME ((uint32_t)I2C_SOFTEND_MODE)
#define I2C_FIRST_AND_NEXT_FRAME ((uint32_t)(I2C_RELOAD_MODE | I2C_SOFTEND_MODE))
#define I2C_NEXT_FRAME ((uint32_t)(I2C_RELOAD_MODE | I2C_SOFTEND_MODE))
#define I2C_FIRST_AND_LAST_FRAME ((uint32_t)I2C_AUTOEND_MODE)
#define I2C_LAST_FRAME ((uint32_t)I2C_AUTOEND_MODE)
#define I2C_LAST_FRAME_NO_STOP ((uint32_t)I2C_SOFTEND_MODE)
We can see references to RELOAD and AUTOEND and SOFTEND.
Digging into the reference manual
https://www.st.com/resource/en/reference_manual/rm0385-stm32f75xxx-and-stm32f74xxx-advanced-armbased-32bit-mcus-stmicroelectronics.pdf#page=969
So we can see here the reference to
AUTOEND - as a way to automatically implement a STOP condition after the set bytes end
SOFTEND as a way to prevent the automatic STOP condition and require the software to decide.
Relationship to your observed behaviour
The define's using the SOFTEND mode is where you saw things not working, and this is to be expected, the I2C protocol was not being fulfilled as there was nothing in the code to indicate the STOP condition.
So what does this mean you can do - an example of a variable byte i2c slave receiver
I haven't found a shining example from ST for this, but let me illustrate an example I have implemented in a project for an I2C Slave.
Let us look at the callbacks that are called:
https://github.com/STMicroelectronics/STM32CubeF7/blob/master/Drivers/STM32F7xx_HAL_Driver/Src/stm32f7xx_hal_i2c.c#L76-L97
*** Interrupt mode IO operation ***
===================================
[..]
(+) Transmit in master mode an amount of data in non-blocking mode using HAL_I2C_Master_Transmit_IT()
(+) At transmission end of transfer, HAL_I2C_MasterTxCpltCallback() is executed and users can
add their own code by customization of function pointer HAL_I2C_MasterTxCpltCallback()
(+) Receive in master mode an amount of data in non-blocking mode using HAL_I2C_Master_Receive_IT()
(+) At reception end of transfer, HAL_I2C_MasterRxCpltCallback() is executed and users can
add their own code by customization of function pointer HAL_I2C_MasterRxCpltCallback()
(+) Transmit in slave mode an amount of data in non-blocking mode using HAL_I2C_Slave_Transmit_IT()
(+) At transmission end of transfer, HAL_I2C_SlaveTxCpltCallback() is executed and users can
add their own code by customization of function pointer HAL_I2C_SlaveTxCpltCallback()
(+) Receive in slave mode an amount of data in non-blocking mode using HAL_I2C_Slave_Receive_IT()
(+) At reception end of transfer, HAL_I2C_SlaveRxCpltCallback() is executed and users can
add their own code by customization of function pointer HAL_I2C_SlaveRxCpltCallback()
(+) In case of transfer Error, HAL_I2C_ErrorCallback() function is executed and users can
add their own code by customization of function pointer HAL_I2C_ErrorCallback()
(+) Abort a master I2C process communication with Interrupt using HAL_I2C_Master_Abort_IT()
(+) End of abort process, HAL_I2C_AbortCpltCallback() is executed and users can
add their own code by customization of function pointer HAL_I2C_AbortCpltCallback()
(+) Discard a slave I2C process communication using __HAL_I2C_GENERATE_NACK() macro.
This action will inform Master to generate a Stop condition to discard the communication.
Therefore, you could implement a I2C slave that could read a variable/dynamic amount of data:
Receive 1 byte - using the SOFTEND based options
This prevents the stop condition being raised, but once this first byte is received will trigger the HAL_I2C_SlaveRxCpltCallback().
In the HAL_I2C_SlaveRxCpltCallback() check the value of the first byte and then request more data of any further length, but this time using an AUTOEND based option.

NRF24L01+ RX Mode and Flush

I have been trying to write my own code for NRF24L01+. I have a problem and I can not solve it
As a receiver, I use STM32F103C8T6 and as a transmitter I use Arduino Uno.
The problem is related to RX Operation.
As I've mentioned above,
As a receiver, I use STM32F103C8T6 and as a transmitter I use Arduino Uno.
Both sides;
Are communicationg through the same address.
Have the same CRC Length
Do not use Enhanced Mode
Have the same address width
Have the same payload width
have the same communication data rate. (1Mbps)
Here is the algorith I use to get coming data from the transmitter. By the way, I do not use IRQ Pin.
Set CE high
Check RX_DR bit in STATUS register. If a value arrives RX FIFO this bit is set. If so, bring CE low to stop RX operation. (Datasheet says RX_DR bit is Data Ready RX FIFO interrupt. Asserted when new data arrives RX FIFO)
Use R_RX_Payload command described in the datasheet and assign the data to a variable.
Clear RX FIFO
Clear RX_DR bit in STATUS register,( write 1)
But it does not work.
void RX_Mode()
{
ChipEnable_high(); // CE=1
//Check RX_DR bit. Wait until a value appears.
while(check)
{
ReadRegister(REG_STATUS,1);
if( (reg_data & 0x40) == 0x40 ){check = false;}
}
ChipEnable_low(); // CE=0
csn_low(); //CSN=0
HAL_SPI_TransmitReceive(&hspi1, (uint8_t*)COMD_R_RX_PAYLOAD, &received_data, 1, 150); // Read the data
csn_high(); // CSN=1
Flush_RX(); //Clear RX FIFO
// Clear RX_DR bit. (Write 1)
ReadRegister(REG_STATUS,1);
data2write = ( reg_data | 0x40);
WriteRegister(REG_STATUS,data2write,1);
CDC_Transmit_FS(&received_data,1); // Print the received data out.
}
When I disable while loop in the code, I continuously read 0x0E.
Edit: My new problem is related to Flush command.
I want to flush RX FIFO when a data arrives. I keep reading registers while transmitter is sending data and I can observe that a new data arrives RX FIFO which means RX_DR bit is set and RX_FIFO status is changed. Then I turn the tx off and execute FLUSH_RX command on the rx side, can not flush fifo. The registers still say that there is data in RX FIFO.
void Flush_RX()
{
csn_low();
HAL_SPI_Transmit(&hspi1, (uint8_t *)COMD_FLUSH_RX, 1, 150);
while(HAL_SPI_GetState(&hspi1) != HAL_SPI_STATE_READY);
csn_high();
}
Any suggestion, help, guidance will be appreciated.
Thanks in advance.
For the RX Mode problem I may help, but I have no idea about Flush operation.
On page 59 in datasheet of NRF24L01+, it says
The RX_DR IRQ is asserted by a new packet arrival event. The procedure for handling this interrups should be
1)Read payload
2)Clear RX_dR
3)Read FIFO_STATUS
4)If there are more available payloads in FIFO repeat step 1.
Could you please use IRQ pin and check whether an interrupt occurs or not. If so, go through these steps above.
I have made some changes on my code. I am trying to make a unidirectional communication for now. So, one side is only RX and the other one is only TX. I am applying the steps described on p.59 in the datasheet.
void RX_Mode(){
ChipEnable_high(); // receiver monitors for a data
while( !(IRQ_Pin_Is_Low() && RXDR_Bit_Is_Set()) ); // Wait until IRQ occurs and RX_DR bit is set.
ChipEnable_low(); // when the data arrives, bring CE low to read payload
ReadPayload(); // read the payload
ClearInterrupts(); // clear all interrupt bits
// This while loop is to check FIFO_STATUS register, if there are more data in FIFO read them.
while(check)
{
ReadRegister(REG_FIFO_STATUS,1);
if((reg_data & 0x01)==0x00)
{
ReadPayload();
ClearInterrupts(); // clear all interrupt bits
}
else
check = false;
}
Flush_RX(); //Flush RX FIFO
check = true; }
The code to read payload is :
void ReadPayload()
{
csn_low(); //CSN=0
HAL_SPI_TransmitReceive(&hspi1, (uint8_t *)COMD_R_RX_PAYLOAD, &received_data ,1, 1500); // READ RX FIFO
while(HAL_SPI_GetState(&hspi1) != HAL_SPI_STATE_READY);
CDC_Transmit_FS(&received_data,1); // print the received data out
csn_high(); // CSN=1
}
BUT; when I turn the tx device on, I read the value of STATUS register which is 0x42 (means that RX_DR bit is set) then I continuously read 0x02 (means RX_DR bit is cleaned a). The data I sent is 0x36.
There are two communication mode as mentioned in PDF nRF24L01Pluss_Preliminary_Product_Specification_v1_0_1 page no. 72,73,74.
please just go through it. I worked with stm32 micro-controller with external interrupt. The sequence of commands passed to NRF chip will be dependent on two modes as mentioned below:
one way communication( tx will transmit and rx will receive only)
both side communication((tx+rx) <----> (rx+tx))
In 1st mode, you have to enable auto-acknowledgement,
In 2nd, disable the auto-acknowledgement.
Hereby writing some steps for 2nd mode,
1> For transmitter side while transmitting:
a)flush transmitter
b)clear the tx_ds flag
c)pass the command for writing the payload
d)fill the payload
e)prepare for transmission
f)check the status
g)clear the all flags(maxtx,rx_dr,tx_ds)
2>for Receiver side while receiving:
Note: Receiver should be in reception mode always. If interrupt is used then no need to check the status bit.
when interrupt arrives;
a) read the payload
b)check the status
c)clear RX_DR flag
d)flush RX_FIFO
e)again configure as a receiver.
Try this one
Thank you, all the best.
*hi,
for one way communication you have to enable the auto-acknowledgment,
and better to flush the receiver fifo after reading one packet. whatever data Tx is transmitting just check it on serial port or in other method because if payload length doesn't match with predefined one in rx, then RX_DR interrupt on NRF chip will not occur, so you will not get data on rx side.
for the testing just enable one pipe, check whether data is received by rx.
chip enable and SPI chip select plays vital role in reading from payload or writing a payload.
*

Weird Winsock recv() slowdown

I'm writing a little VOIP app like Skype, which works quite good right now, but I've run into a very strange problem.
In one thread, I'm calling within a while(true) loop the winsock recv() function twice per run to get data from a socket.
The first call gets 2 bytes which will be casted into a (short) while the second call gets the rest of the message which looks like:
Complete Message: [2 Byte Header | Message, length determined by the 2Byte Header]
These packets are round about 49/sec which will be round about 3000bytes/sec.
The content of these packets is audio-data that gets converted into wave.
With ioctlsocket() I determine wether there is some data on the socket or not at each "message" I receive (2byte+data). If there's something on the socket right after I received a message within the while(true) loop of the thread, the message will be received, but thrown away to work against upstacking latency.
This concept works very well, but here's the problem:
While my VOIP program is running and when I parallely download (e.g. via browser) a file, there always gets too much data stacked on the socket, because while downloading, the recv() loop seems actually to slow down. This happens in every download/upload situation besides the actual voip up/download.
I don't know where this behaviour comes from, but when I actually cancel every up/download besides the voip traffic of my application, my apps works again perfectly.
If the program runs perfectly, the ioctlsocket() function writes 0 into the bytesLeft var, defined within the class where the receive function comes from.
Does somebody know where this comes from? I'll attach my receive function down below:
std::string D_SOCKETS::receive_message(){
recv(ClientSocket,(char*)&val,sizeof(val),MSG_WAITALL);
receivedBytes = recv(ClientSocket,buffer,val,MSG_WAITALL);
if (receivedBytes != val){
printf("SHORT: %d PAKET: %d ERROR: %d",val,receivedBytes,WSAGetLastError());
exit(128);
}
ioctlsocket(ClientSocket,FIONREAD,&bytesLeft);
cout<<"Bytes left on the Socket:"<<bytesLeft<<endl;
if(bytesLeft>20)
{
// message gets received, but ignored/thrown away to throw away
return std::string();
}
else
return std::string(buffer,receivedBytes);}
There is no need to use ioctlsocket() to discard data. That would indicate a bug in your protocol design. Assuming you are using TCP (you did not say), there should not be any left over data if your 2byte header is always accurate. After reading the 2byte header and then reading the specified number of bytes, the next bytes you receive after that constitute your next message and should not be discarded simply because it exists.
The fact that ioctlsocket() reports more bytes available means that you are receiving messages faster than you are reading them from the socket. Make your reading code run faster, don't throw away good data due to your slowness.
Your reading model is not efficient. Instead of reading 2 bytes, then X bytes, then 2 bytes, and so on, you should instead use a larger buffer to read more raw data from the socket at one time (use ioctlsocket() to know how many bytes are available, and then read at least that many bytes at one time and append them to the end of your buffer), and then parse as many complete messages are in the buffer before then reading more raw data from the socket again. The more data you can read at a time, the faster you can receive data.
To help speed up the code even more, don't process the messages inside the loop directly, either. Do the processing in another thread instead. Have the reading loop put complete messages in a queue and go back to reading, and then have a processing thread pull from the queue whenever messages are available for processing.