This thread has been locked.

If you have a related question, please click the "Ask a related question" button in the top right corner. The newly created question will be automatically linked to this question.

RM42 GIO Are GIODSET and GIODCLR atomic/thread-safe?

The RM42x 16/32-Bit RISC Flash Microcontroller Technical Reference Manual (http://www.ti.com/lit/ug/spnu516a/spnu516a.pdf), Section 19.3.1, says this about the GIODSET register:

Data set ( GIODSET)
Allows logic HIGH to be output on GIO terminal(s) configured as outputs by writing 1's to the required
bits in the GIODSETx registers. ... The GIODSETx registers eliminate
the need for the application to perform a read-modify-write operation when it needs to set one or more
GIO pin(s).

This sort of implies, but the manual doesn't seem to explicitly say, that subsequent writes to GIODSET/GIODCLR are guaranteed to be atomic. I'm wondering if it's possible for subsequent writes to either register to interfere with each other.


For example, if I write 0000 0001 to GIODSET and immediately write 0000 0002, is it guaranteed that the first write will already be processed by the time the second write happens?

I thought this information would be in the tech reference, but I haven't been able to locate it yet.

  • Hi Joshua,

    Two separate issues here:
    1) correct end result
    2) order in which pins change state

    DSET, DCLR give you a correct end state when you have more than one task operating on the same GPIO port.

    As an example - here is the hazard you avoid:
    Assume task 1 wants to clear bit 0 and task 2 wants to set bit 1 of GIO port A.
    1) task 1 reads DOUT - and gets the value 0x0000 0001 back in register R0.
    2) task 2 interrupts task 1
    3) task 2 reads DOUT, and also gets 0x0000 0001 in register R0
    4) task 2 then sets bit 1 in R0, R0 -> 0x0000 0003
    5) task 2 writes register R0 back to DOUT
    6) task 2 returns, task 1 continues to execute
    7) task 1 has the old value of DOUT in register R0, but doesn't know any better
    and just clears bit 0, R0 goes from 0x0000 0001 -> 0x0000 0000.
    8) task 1 writes R0 back to DOUT - now DOUT has 0x0000 00000.

    as a result, the end state of DOUT is 0x0000 00000 not 0x00000002 as desired.

    By using DSET and DCLR instead, the sequence would look like this:

    1) task 1 writes 0x0000 00001 to DCLR
    2) task 2 writes 0x0000 00010 to DSET

    or

    1) task 2 writes 0x0000 00010 to DSET
    2) task 1 writes 0x0000 00001 to DCLR

    And either way after both operations complete, pin GIOA[0] will be '0' and pin GIOA[1] will be '1'.

    But this really doen't tell us if GIOA[1] got set before GIOA[0] was cleared, or vice versa. That's a different problem.

    For the most part that problem is controlled by the order in which the instructions execute, and this could be simply the order in which you code the instructions if they are in the same task, or under control of the OS if you are multitasking. Neither really are specific issues to TMS570.

    But, the CPU on the TMS570 does support write buffering and merging, and this can change the order / timing in which the writes appear on the pins.

    These features are mainly something intended to reduce bandwidth and improve performance when operating on RAM that is not shared. If the CPU is the only processor using a value in memory, then it doesn't really always need to write the value back to memory (physically) immediately. It can delay this operation as long as possible, as long as it keeps track of the write - doesn't drop it, and returns the correct values on read. Almost like a small 'cache'...

    The CPU does this so that it can make the best use of it's 64-bit bus interface and minimize the amount of time that the CPU is stalled waiting for an access that goes out to the switch fabric to complete. For example, if you write 4 times to 4 consequitive bytes, the CPU might wait to combine these into a single 32-bit write operation which takes up less bandwidth on the switch fabric than 4 separate writes would take.

    With GIO ports, you need to control this type of optimization. The simplest way is by setting up the address range of the GIO port as type 'strongly ordered' in the MPU. There are some 'barrier' instructions that you can insert in your code to force the buffer to flush.

    Anyway, you need to be aware of this and you probably want to set the peripheral registers up so they are strongly ordered to begin with.