Hi,

we do indeed have a number of places in the driver code, where busy waiting is used. The reason for this is mostly missing man power to implement better versions of the same driver. The most important fact here is, that you can re-implement a driver in a more efficient way completely transparent to the drivers API. So you could just re-implement the STM32F4's SPI driver using DMA - and device drivers using the SPI interface would not even notice it...

This does indeed not make sense for every peripheral driver. As long as the time you wait on something is smaller than the time you need for 2 context switches, it does not make sense to use some kind of thread synchronization... The ADC measurements are for example very fast (some 10-50 CPU cycles on most CPUs), so you are never able to switch to the idle thread and back in that time...

The way to go with asynchronous pereipheral driver implementations is in my opinion to use mutexes: wait on one in thread context after you triggered some action and release the mutex from the interrupt. I think this might be a little safer then using `thread_sleep()`.

Maybe have a look at `cpu/stm32f4/startup.c` as example on how the uart is used in a completely asynchronous, interrupt driven way...

To conclude: I am against implementing something as a driver event system or the like - to my opinion does the peripheral driver interface already provide everything needed for efficient driver implementation. We just need to spend some effort in implementing the drivers we have to be more efficient when needed.

Cheers,
Hauke


On 09.02.2015 14:20, Joakim Gebart wrote:
I was actually writing on a post for this list along the same theme when I saw your message. The main reason I see for removing the busy waits is that you can lower the power consumption if you can let the CPU core sleep while the peripheral is working, either using interrupts or DMA for the transfer.

I was thinking I could use `thread_sleep()` inside the part of the driver called from the application thread and `thread_wakeup` from an ISR for the relevant status flag. Will this introduce any noticeable extra delays from the context switching or otherwise? (Except for the function calls to `thread_sleep()`, `thread_wakeup()` which obviously are an extra overhead)

Has anyone measured the cost of the thread context switching on the different platforms? I'm mainly interested in Cortex-M4 (Kinetis). This would be a good indication of how "slow" an I/O device has to be before it is worth it to manually yield a thread while waiting.

I think ADC and UART (depending on baudrate vs. core clock frequency) are good candidates for this, as well as I2C in normal or fast mode when running on a fast MCU. SPI may not be very useful for small transfers, but DMA of larger blocks will definitely save some power/decrease CPU usage with such a change.

Best regards,

Joakim Gebart
Eistec AB
www.eistec.se <http://www.eistec.se>

On Sun, Feb 8, 2015 at 11:47 AM, Frank Holtz <[email protected] <mailto:[email protected]>> wrote:

    Hello,

    i have looked into periph drivers and found a lot of single line
    "while"
    statements waiting for finishing things.

    stm32f4 -> 26 statements
    nrf51822 -> 4 statements
    atmega2560 -> 8 statements
    cc2538 -> 4 statements
    sam3x8e -> 13 statements
    ...

    Slow devices like ADC, Flash, UART or Random number generation are
    wasting a lot of CPU cycles while waiting to finish an action. This
    blocks task switching(right?) and preventing to go into sleep mode.

    What about an architecture for asynchronous drivers?

    An asynchronous driver can be initialized, but it brings hardware into
    sleep mode. The hardware is powered on when an process is added to
    queue
    and powered off when noting listens to queue. It should be possbile to
    add more than one process to an queue. This gives the availability to
    debug things, implement an work flow to decrypt or route radio
    packages
    or use ADC values to generate better random data when ADC is enabled.

    An queue can be centralized and handle an event-type, the priority and
    an pointer to an call back function.

    When an event is triggered any function with same event type is called
    with an identifier like pin number and an value or pointer to expected
    data structure. Every function can determine with return code if other
    functions with same event type are called. This is needed for random
    numbers to make sure that an random number is not used twice.

    When it's possible to change an event type and re queue an event
    an work
    flow can implemented.

    Regards,

    Frank
    _______________________________________________
    devel mailing list
    [email protected] <mailto:[email protected]>
    http://lists.riot-os.org/mailman/listinfo/devel




_______________________________________________
devel mailing list
[email protected]
http://lists.riot-os.org/mailman/listinfo/devel

_______________________________________________
devel mailing list
[email protected]
http://lists.riot-os.org/mailman/listinfo/devel

Reply via email to