Example: Queue of DMA Requests

DSP/BIOS vs. Portos

Given one DMA channel, successive DMA requests have to be queued when the channel is busy. A DMA transfer terminates with a DMA done interrupt, at which point the next DMA request in queue can be serviced. In this example, in DSP/BIOS case we queue them with tasks and semaphores. In Portos we queue them with queue of functions (the natural way). This is a simplistic example; some functions may do more stuff.

See also Highlights.

DSP/BIOS Tasks
Portos Priority Functions

#include <std.h>
#include <tsk.h>
#include <sem.h>
#include <mbx.h>

// Tasks, semaphores and mailboxes
static TSK_Handle taskDma;
static TSK_Handle taskMyfunc;
static SEM_Handle semDma;
static SEM_Handle semMyfunc;
static MBX_Handle mbxDma;

// Message sent to DMA task
typedef struct {

char *src;
char *dest;
int len;

} MessageDma;

#include <portos.h>

// Queue to synchronize DMA requests
static po_queue_Queue myQ = po_queue_INIT(&myQ, 1, 0);

// Task to handle DMA requests (priority 3)
void dma_handler(void)
{

// For ever loop
while ( 1 ) {

MessageDma msg;

// Wait for new transfer request
MBX_pend(mbxDma, &msg, SYS_FOREVER);

// Wait for signal "end of previous DMA transfer"
SEM_pend(semDma, SYS_FOREVER);

// Start DMA transfer
dma_start(msg.src, msg.dest, msg.len);

}

}

// DMA request handler (priority 3)
void dma_handler(po_priority(3), char *src, char *dest, int len)
{

// Start DMA transfer
dma_start(src, dest, len);

}

// DMA done interrupt
void dma_done_interrupt(void)
{

// Reset DMA and other registers
dma_reset();

// Post semaphore (signal) for next transfer
SEM_post(semDma);

}

// DMA done interrupt
void dma_done_interrupt(void)
{

// Reset DMA and other registers
dma_reset();

// Service next DMA transfer in queue
po_queue_next(&myQ);

}

// Task myfunc that launches DMA transfers (priority 5)
void myfunc(void)
{

// For ever loop
while ( 1 ) {

MessageDma msg;

// Wait for someone to request a new DMA
SEM_pend(semMyfunc, SYS_FOREVER);

// Send message to DMA handler using mailbox
msg.src = SourceBuffer;
msg.dest = DestinationBuffer;
msg.len = 1000;
MBX_post(mbxDma, &msg, SYS_FOREVER);

}

}

// Launches DMA transfers (priority 5)
void myfunc(po_priority(5))
{

// Send packet to dma_handler (via queue)
dma_handler(po_queue(&myQ),
.......................SourceBuffer, DestinationBuffer, 1000);

}

// Random interrupt that requests new DMA transfers
void random_interrupt(void)
{

// Activate task that schedules transfers
SEM_post(semMyFunc);

}

// Random interrupt that requests new DMA transfers
void random_interrupt(void)
{

// Call priority function that schedules transfers
myfunc(po_priority);

}

// Main function
int main()
{

TSK_Attrs attr1 = {0};
TSK_Attrs attr2 = {0};

// Create tasks
attr1.name = "taskDma";
attr1.priority = 3;
attr1.stacksize = 512;
attr1.stack = NULL;
attr1.initstackflag = 1;
taskDma = TSK_create((Fxn)dma_handler, &attr1);
if ( !taskDma ) SYS_abort("Can't create Task DMA");

attr2.name = "taskMyfunc";
attr2.priority = 5;
attr2.stacksize = 512;
attr2.stack = NULL;
attr2.initstackflag = 1;
taskMyfunc = TSK_create((Fxn)myfunc, &attr2);
if ( !taskMyfunc ) SYS_abort("Can't create Task Myfunc");

// Create semaphores
semDma = SEM_create(1, NULL);
semMyfunc = SEM_create(0, NULL);

// Create mailbox
mbxDma = MBX_create(sizeof(MessageDma), 5, NULL);
if ( !mbxDma ) SYS_abort("Can't create Mailbox DMA");

// Start hardware interrupts
start_hwi();

// Init DMA
dma_init();

// main() returns but hardware interrupts go on
return 0;

}

// Main function
int main()
{

// Init Portos
po_init();

// Start hardware interrupts
start_hwi();

// Init DMA
dma_init();

// main() returns but hardware interrupts go on
return 0;

}