No subject


Mon Sep 27 22:03:44 CEST 2010


fixed size "packet". AFAIK it's not implemented in any of our archs.
Even on PCs it's fairly uncommon to use it.
Even ppl who write bad code to read from barcode scanners, don't
usually use that feature. It's usually much better to find the STX or
ETX yourself, or otherwise parse the protocol properly.

>
> For all those functions I miss something too: If you use transfers async,=
 you will not get an reply on the read/write that is valid as the transfer =
is not finished at that time. So _ioctl needs another option too. Besides g=
etting the information about the errors from the last transfer one needs to=
 get the status of the current transfer, i.e. the number of bytes trasnferr=
ed and the status if the transfer is ongoing or whatever reason aborted.
>

I wrote a while ago a serial port class for my desktop apps and spent
some time digging the Unix and Windows APIs. On Linux, if you use a
non-blocking transfer, read() returns EWOULDBLOCK which is a define to
some negative number. Much like the sockets API. Otherwise it returns
the number of read bytes. Is that what you mean?

> So what we have is a usart that relies on ringbuffer even the ringbuffer =
struct supplies blockptr / blockcntr.
> If you use packet oriented data, you cannot handle timeouts on packets ca=
use the timeouts are based on the ringbuffer and, if the ringbuffer is to s=
mall two locks block your thread no, better, something blocks you that you =
cannot determine.

True. Even if we implement the packet based API, we would have to make
the serial buffer size configurable and make the call fail with some
error code if it requests a packet larger than the buffer.

>
> If you have a function that allocated memory to form a block you don't ne=
ed to copy it to the ringbuffer for transfer but the actual implemenation d=
oes.
> On smaller systems that need packet oriented communication ( block transf=
er) the ringbuffer memory could bee freed completely.

This would be a nice trick. But I'm not sure how it would fit in our
current driver structure. Somehow we would have to get the buffer
pointer down to the driver level.
Then again, I wonder if there is real use for the packet oriented reads.

>
> On bigger systems with DMA/PDC support, you save a lot of CPU time for al=
l those TXE Interrupts that do not appear.
>
>
> Unfortunately I cannot implement DMA in the actual structure as DMA shoul=
d lock the calling thread until transfer is over or set a signal after fini=
shing the transfer.
> I tried to do that by using the normal StartTx(void) function that will r=
ise an TXE Interrupt and this first TxReadyIrq( RINGBUF *rbf) will setup th=
e DMA process.
> Unfortunately this function is out of thread as it is an interrupt and th=
erefore cannot set a NutEventWait that blocks the calling thread.
>

I'm confused. Why wouldn't the calling thread keep it's blocked state
from read()?
Anyway, I thought about using DMA first with the EMAC driver, which
should benefit the most from it, as it transfers at least an ethernet
frame each time.
I see that u-boot, linux and other kernels usually define a API for
DMA, with dma_alloc (similar to malloc). The question is, should we
try to do something like that, and have each arch provide the
implementation, or should we confine the DMA engine within the arch
folder as a private API, so each port does it as it pleases.

> So here's what I am thinking about:
> Assume that all functions for the USARTs get the USARTDCB as an argument:
> - You can implement block-control with DMA in StartTx on CPUs that suppor=
t that feature.
> - You can implement block transfer by saving the ringbuffer (Data is take=
n from the calling functions buffer pointer)
> - You can write totally different usart drivers for totally different arc=
hitectures by keeping the Nut/OS usual function calls.
>
>
> In my STM32 implementation I fear that if I can call one set of functions=
 from all usart interrupts the code in flash will be much lower even I impl=
ement and enable all features.
> All features mean: HW/SW-Handshake, DTR/DSR support, XON/XOFF, STX//ETX, =
Full-/Half-Duplex, IRDA, ...
>

It makes a lot more sense to have all functions for the USART to
receive the DCB structure or the DEVUSART structure. That's how
drivers in Linux and Windows Driver Model works (sort of).

> The backdraw of this change would be that all architectures have to be mo=
dified to pass DEVUSART *dev or at least USARTDCB *dcb to all functions.
> That would lead to one small problem, any function accessing the ringbuff=
er needs to derive it from the dcb.
> For a 72MHz STM32 it's not a problem to do RINGBUF *rbf =3D dcb->dcb_rbf;=
 at every function start. But how is that on an AVR?

That could easily be offset by any deduplication we achieve in the
code. It should not be too much per function really.


> Ah, by the way. I am thinking about making the things a bit comfortable. =
So one could set "Use Interrupts" and "Use DMA" independantly for every USA=
RT in a system.
> If it stays like it is, so usart1.c includes usart.c this saves some flas=
h if the user unchecks the one or the other option.
> If there is only one usart.c calld by the interrupts of usartx.c it could=
 be an idea to include portions of the code only if at least one of the usa=
rts has enabled that option.
> So DMA handling in the general driver is only enabled and compiled if at =
least one usart has the option set in nutconf.
>

Wouldn't it actually make the code bigger? Some routines would be
duplicated in the binary blob, one with DMA and another without. I'm
not sure if there is a use-case were one would like to enable DMA for
one USART but not for the others.

> So now I have three options:
> 1 Modify usart.c / usart.h / uart.h to the new structure and hope that so=
meone is helping me to bull AVR and ARM architecture to that level.

I can help with AVR and AVR32.

> 2 Just split usart.h / uart.h into stm32_usart.h and other_usart.h while =
usart.h includes the one or the other depending on the architecture selecte=
d.

It can easily became a nightmare regarding to maintenance and portability.

> 3 Leave it as it is and forget about that all :)

Tempting *smile*
Actually I think Nut/OS already has the most compreensive USART driver
from the RTOS I know of, and for the applications we work with, that's
a huge benefit :)
But it's also quite hard to maintain the way it is... If a bug is
found in the flow control code for instance, one has to remember to
fix it in all other archs, and it only get's worst with new platforms
being added.

>
> By the way, Option 2 is what I did for TWI cause STM32 has two interfaces=
 and 4 interrupt providers ( two per interface) that call the same code exi=
sting only once.
> Old Tw*() functions are #defined to the stm32 specific functions. Works f=
ine here :)
>

Yesterday I was thinking about a platform independent TWI. So we could
have platform independent drivers to access EEPROMs and Atmel QTouch
chips.

But I'm actually quite worried about the GPIO. I'm going to start
working on a board with UC3B164 connected with sensors/relays. I would
like to see and use an interface to set pin functions, level,
configure interrupts, etc in a way that's standard and portable
between current and future platforms.
How are you handling this with STM32?
Btw, which STM32 are you using? I would like to take a look at the datashee=
ts :)

Kind Regards,
    Thiago A. Correa


More information about the En-Nut-Discussion mailing list