heinbali01 wrote on Monday, November 23, 2015:
Hi Pugglewuggle
I need to dynamically allocate some memory 1) from in a task, and 2) from in an ISR.
Personally I would not recommend dynamically allocate memory from an ISR because:
- Most allocators are not written to be called from an ISR.
- ISR’s must be fast and most calls to [pvPort]malloc() have a variable processing time
Most people will use a queue and feed it with xQueueSendFromISR(). That will also wake-up a task which is waiting for data.
Volume data:
If the ISR produces bigger quantities of data, and if there is only one consumer-task of that data, then I would prefer to use a circular buffer, such as FreeRTOS-Plus-TCP\FreeRTOS_Stream_Buffer.c
. This can be accompanied with a call to vTaskNotifyGiveFromISR()
(or xSemaphoreGiveFromISR()
etc) which will wake-up the task.
Should I always use pvPortMalloc or is there any instance
where I should used regular malloc from stdlib?
I would not mix the use of both allocators. But if you want you can use the malloc()
and free()
from stdlib, and make those thread-aware with the wrap-arounds.
I tend to prefer using:
- heap_4.c In case I have 1 block of contiguous RAM data available
- heap_5.c In case there are several non-contiguous blocks of RAM
The algorithm used is safe and very fast.
Also, I need to dynamically allocate some memory in an ISR to create an item
for a queue. Is it okay/a good idea to call some form of malloc/pvPortMalloc
(depending on ths answer to my first question) inside an ISR? (is it
thread-safe, too slow, etc?). I’m using heap_4 right now.
Please have a look at:
FreeRTOS-Plus-TCP\include\FreeRTOS_Stream_Buffer.h
As a simple example:
#define UART_DMA_BUFFER_SIZE 2048
StreamBuffer_t *pxBuffer;
void create_buffer()
{
size_t uxLength = UART_DMA_BUFFER_SIZE;
size_t uxSize;
/* Add an extra 4 (or 8) bytes. */
uxLength += sizeof( size_t );
/* And make the length a multiple of sizeof( size_t ). */
uxLength &= ~( sizeof( size_t ) - 1u );
uxSize = sizeof( *pxBuffer ) - sizeof( pxBuffer->ucArray ) + uxLength;
pxBuffer = ( StreamBuffer_t * )pvPortMalloc( uxSize );
if( pxBuffer != NULL )
{
/* Clear the header data. */
memset( pxBuffer, '\0', sizeof( *pxBuffer ) - sizeof( pxBuffer->ucArray ) );
/* Treat the 'LENGTH' member (all capitals) as a 'const member' */
pxBuffer->LENGTH = uxLength;
}
}
void uart_isr()
{
BaseType_t xHigherPriorityTaskWoken = pdFALSE;
reset__flags();
uxStreamBufferAdd( pxBuffer, 0, &xDMA[ dma_index ], sizeof( xDMA[ dma_index ] ) );
vTaskNotifyGiveFromISR( xDMATask, &xHigherPriorityTaskWoken );
portYIELD_FROM_ISR( xHigherPriorityTaskWoken );
}
void uart_task()
{
create_buffer();
install_isr();
for( ;; )
{
size_t uxCount;
ulTaskNotifyTake( pdFALSE, ulMaxBlockTime );
for( ;; )
{
uxCount = uxStreamBufferGet( pxBuffer, 0, uart_buffer, sizeof( uart_buffer ), pdFALSE );
if( uxCount == 0 )
{
/* All data ave been read. */
break;
}
/* Process uxCount bytes. */
}
}
}
I hope that the example is clear and useful.
Regards.