chipKIT® Development Platform

Inspired by Arduino™

Howto increase serial write buffer on Max32?

Created Mon, 13 Jul 2015 22:38:33 +0000 by Magnum


Magnum

Mon, 13 Jul 2015 22:38:33 +0000

Hello, I have a project where I have to send data via the hardware serial ports. It seems that the Chipkit has a hardware write buffer of around 10 bytes. As long as I sends less than 10 bytes the write command completes quite fast, but if I send more characters the speed decreases rapidly to the selected baud rate (unfortunately 9600 baud). I have to make data bursts with enough time in between so that the buffer can be cleared meanwhile. But during the burst I need maximum speed of the program code. If I could increase the buffer to around 20 bytes everything would be fine. Does someone have a solution for it, I haven't found anything in HardwareSerial.cpp.

Many thanks in advance.

Magnus


majenko

Tue, 14 Jul 2015 09:10:34 +0000

The buffer is fixed in hardware. Some smaller chips have 4 bytes, and the larger ones (like on the MAX32) have 8 bytes. That can't be changed,

If you want background sending of data at low latency with no CPU overhead you could consider investigating using DMA to transmit the data.

Basically you build up a buffer of the data you want to send, then point a DMA channel at both that buffer and the UART's send buffer. Configure the DMA channel correctly and it should just send all that data in one go in the background.

You can read up on the DMA channels here: http://www.microchip.com/mymicrochip/filehandler.aspx?ddocname=en532840 The UART documentation is here: http://www.microchip.com/mymicrochip/filehandler.aspx?ddocname=en532828


Magnum

Tue, 14 Jul 2015 10:11:46 +0000

Hello Majenko,

many thanks for your fast reply. I am already thinking about a send buffer, the DMA solution sounds really good.

Many thanks,

Magnus


majenko

Tue, 14 Jul 2015 10:34:57 +0000

DMA can be a bit tricky to get your head around. I'm actually working on an abstraction layer at the moment to make it easier, but it's been delayed by other work. Here's one bit of code that may help you out:

/*! DMA transfer to or from a peripheral
 *
 *  Read a block of data from a peripheral using an interrupt to trigger each
 *  transfer.  Good for things like ADC sampling where a timer sets the sampling rate.
 *
 *  Pass it the channel, destination buffer and source location, destination and source sizes,
 *  transfer cell size and IRQ to trigger the transfers.
 */
int dma_transfer(int chan, void *dest, const void *src, int dsize, int ssize, int csize, int irq) {
#if (_NUM_DMA > 0)
    if ((chan < 0) || (chan >= _NUM_DMA)) {
        return 0;
    }
    p32_dch *dch = (p32_dch *)&DCH0CON;
    while ((dch[chan].dchcon.reg & DCH_CON_CHBUSY) != 0) {
        asm volatile("nop");
    }

    dch[chan].dchcon.reg = 0;
    dch[chan].dchecon.reg = 0x00FF0000;
    dch[chan].dchecon.set = DCH_ECON_CHSIRQ(irq);
    dch[chan].dchecon.set = DCH_ECON_SIRQEN;
    dch[chan].dchint.reg = 0;
    dch[chan].dchssa.reg = KVA_2_PA(src);
    dch[chan].dchdsa.reg = KVA_2_PA(dest);
    dch[chan].dchssiz.reg = ssize;
    dch[chan].dchdsiz.reg = dsize;
    dch[chan].dchcsiz.reg = csize;
    dch[chan].dchcon.set = DCH_CON_CHEN;
#else
    return -1;
#endif
    return 1;
}

The "dch[chan].dchcon" corresponds to a "DCHxCON" register. Similarly the "dch[chan].dchecon" corresponds to "DCHxECON" etc.

KVA_2_PA is defined as:

#define KVA_2_PA(v)             (((uint32_t) (v)) & 0x1fffffff)