Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

cpu: Add bit manipulation macros for Cortex-M #6916

Merged
merged 2 commits into from
Jun 21, 2017

Conversation

jnohlgard
Copy link
Member

@jnohlgard jnohlgard commented Apr 17, 2017

This PR introduces a new header bitband.h which provides macros for using the bit banding memory region found in Cortex-M3 and above, as well as a fall back for Cortex-M0 and Cortex-M0+ without bit banding.
Some Cortex-M0+ devices have their own bit manipulation equivalents, such as the Bit Manipulation Engine in Kinetis M0+ devices. On such CPUs, define BITBAND_MACROS_PROVIDED to 1 and provide your own macros.

The new macros are named bit_set32, bit_set16, and bit_set8, for setting single bits (i.e. writing a 1), and bit_clear32, bit_clear16, and bit_clear8 for clearing single bits (i.e. writing a 0).
The suffix numbers are the memory access width, some in-cpu modules have 8 bit or 16 bit registers which may require memory accesses to be the correct width to avoid undefined behaviour (Kinetis UART module is one example where using 32 bit access can mess up internal states).

This PR is a prerequisite for an upcoming Kinetis FRDM-KW41z port.

@jnohlgard jnohlgard added Platform: ARM Platform: This PR/issue effects ARM-based platforms Type: enhancement The issue suggests enhanceable parts / The PR enhances parts of the codebase / documentation labels Apr 17, 2017
@kaspar030
Copy link
Contributor

Nice!

Some thoughts:

  • would static inlines instead of macros work for this?

  • would it make sense to factor out the type from the macro (e.g., BIT_SET(uint32_t, ptr, bit), and then use that for the other implementations?

  • does adding toggling functions make sense?

Looking forward to using this for gpio, so with LTO, a gpio_set() compiles down to a single store instruction...

@jnohlgard
Copy link
Member Author

Static inline might work, didn't test yet.
Regarding type as parameter: it makes sense to do that, it simply didn't occur to me while refactoring.
Regarding toggle: it makes sense for the Kinetis BME implementation, which provides hardware support, don't know what it would be useful for though, other than toggling GPIOs. I would prefer to add it in a follow up together with a change that makes use of it. There's also the possible bit_load macro/function which would extract a single bit from a word.
Also, regarding GPIOs, many MCUs have specific set, clear, and toggle registers for GPIOs that our gpio drivers always should use, if possible.

@jnohlgard
Copy link
Member Author

The static inline method seems like it would be best, I found a bunch of mistakes where I missed the address-of operator which was hidden by the cast in the macro version. I will update this PR soon-ish

@jnohlgard jnohlgard added the CI: ready for build If set, CI server will compile all applications for all available boards for the labeled PR label Apr 20, 2017
@jnohlgard
Copy link
Member Author

OK to squash?

@haukepetersen
Copy link
Contributor

Another thought: why the fallback for Cortex-M0(+)? IMHO the bitbanging is only used in CPU specific code anyway, and in that code path it should be clear which target is worked on, right?

@haukepetersen
Copy link
Contributor

Another thought: why the fallback for Cortex-M0(+)? IMHO the bitbanging is only used in CPU specific code anyway, and in that code path it should be clear which target is worked on, right?

@haukepetersen haukepetersen reopened this Apr 24, 2017
@haukepetersen
Copy link
Contributor

sorry, wrong button + browser lag...

@kaspar030
Copy link
Contributor

"Some Cortex-M0+ devices have their own bit manipulation equivalents, such as the Bit Manipulation Engine in Kinetis M0+ devices. On such CPUs, define BITBAND_MACROS_PROVIDED to 1 and provide your own macros."

@haukepetersen
Copy link
Contributor

I see, never mind then.

@jnohlgard
Copy link
Member Author

@haukepetersen this is an example of a specific implementation for a kinetis m0+
https://github.com/gebart/RIOT/blob/pr/frdm-kw41z/cpu/kinetis_common/include/bme.h

@jnohlgard
Copy link
Member Author

@haukepetersen Also, using these functions in the STM common drivers might make sense in some situations, it will use bit-banding on the M3 and up, but still compile cleanly on the low end devices.

In Kinetis we use these macros to avoid having to disable IRQs or using mutexes while messing with clock gate registers (since the registers are shared between many different peripheral drivers)

@jnohlgard
Copy link
Member Author

I accidentally squashed while rebasing, sorry for that. Anyway, this PR is ready for review and testing. Murdock is fine except for squashing the fixups.

@haukepetersen
Copy link
Contributor

Changes look good to me, but I don't have a board around today, so can test only tomorrow. But please feel free to squash and make Murdock happy with that!

@kaspar030
Copy link
Contributor

Would it make sense to have the interface globally (not only for cortexm)? @gebart what do you think?

Otherwise, functions within "bitband.h" should be prefixed with "bitband_*".

@jnohlgard
Copy link
Member Author

@kaspar030 It does make sense to rename the header. I guess it would be possible to move the fallback to a global header and keep the bitband.h part inside cortexm.

@haukepetersen
Copy link
Contributor

I don't quite see the reason to make this global (yet), this is something cpu-arch internal and some other CPU arch that supports this might bring its own style of handling this, so why force this header on every arch?!

@kaspar030
Copy link
Contributor

so why force this header on every arch?!

The underlying bitbanding is architecture dependend, but "set bit N of the int at addr A" is not. Currently, we probably use e.g., val |= (1<< bitnum). A static inline bit_set(&val, bitnum) probably compiles to the same code if bitbanding is unavailable, but would make use of bitbanding where available...


#if DOXYGEN
/** @brief Flag for telling if the CPU has hardware bit band support */
#define CPU_HAS_BITBAND 1 || 0 (1 for Cortex-M3 and up, 0 for Cortex-M0)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I am seeing this style of documenting the first time. Shouldn't this go into some sort of @brief statement?

Copy link
Member Author

@jnohlgard jnohlgard Jun 1, 2017

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think it looks quite nice in the generated docs:
image
Otherwise it would say that the definition is simply 1, even though it is CPU dependent.

I'm okay with changing it if you think it is weird to write the documentation as a code syntax error.

@jnohlgard
Copy link
Member Author

@kaspar030 The bitband accesses to RAM on CM3 is restricted to a part of the address space (0x20000000-0x2xxxxxxx), so it may hardfault on CPUs where some RAM is addressed below 0x20000000, e.g. Kinetis.
The generic approach will also become problematic on Kinetis L when used on normal variables because the bit manipulation engine on that CPU family only supports bit manipulation on memory locations within the peripheral registers memory area (0x40000000-0x41FFFFFF).

Also there's the issue of non-atomicity in the generic implementation, if the access is already protected by a lock or disabled IRQs then another call to irq_disable/irq_restore will bloat the code a lot. The CM3 bitband accesses are atomic for free, and the number of CPU cycles for a hardware read-modify-write cycle via bitbanding is the same as for a software read-modify-write.

@kaspar030
Copy link
Contributor

@gebart Ok so we can't make this (easily) generic. I guess then it is fine to merge as is. I'll take last look over the code now.

* @param[in] ptr pointer to target word
* @param[in] bit bit number within the word
*/
static inline void bit_set32(volatile uint32_t *ptr, uint8_t bit)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should we rename the functions to bitband_*()?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'd rather rename the header bit.h if it is necessary, since bit banding is only one of the implementations

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

fine with me!

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

renamed

@@ -36,6 +36,7 @@
#include "sched.h"
#include "thread.h"
#include "cpu_conf.h"
#include "bitband.h"
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is this include necessary? It does include both ways...

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Convenience or lazy, this makes the big macros immediately available in all files using cpu.h

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ok

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

but doesn't this contradict the 'import only what is neccessary' thing that has impacts to the build process/speed?!

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

addressed, moved include to the consumers

Copy link
Contributor

@kaspar030 kaspar030 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The bit.h header guard needs fixing. Other than that I'm fine with that header. Can't really test, as I don't have the hardeare...

* @author Joakim Nohlgård <[email protected]>
*/

#ifndef BITBAND_H
Copy link
Contributor

@kaspar030 kaspar030 Jun 5, 2017

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hm, somehow this file triggers an encoding bug in the headercheck script. I suspect the beautiful a with "a" circle on top in your name. ;)
Unfortunately I cannot reproduce the bug locally.

Anyhow, this define (and the closing endif comment) need to be adapted to the file rename.
dist/tools/headerguards/check.sh | patch -p0 should do that for you.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

updated, the headerguards script worked fine on my machine locally to fix it automatically like you wrote.

@kaspar030
Copy link
Contributor

@gebart please squash! Could anyone with a kinetis do a quick check?

@jnohlgard
Copy link
Member Author

squashed

@jnohlgard
Copy link
Member Author

reworded commit msg on kinetis commit

@aabadie
Copy link
Contributor

aabadie commented Jun 21, 2017

This one looks in good shape: just a test remains. Is there someone with this board who can test ? Otherwise @gebart, can you provide a copy of the output of the uart/timer test applications for the boards you have ?

@kaspar030
Copy link
Contributor

Otherwise @gebart, can you provide a copy of the output of the uart/timer test applications for the boards you have ?

IMO a little trust goes a long way here.

@aabadie
Copy link
Contributor

aabadie commented Jun 21, 2017

IMO a little trust goes a long way here.

+1. So an ACK would be enough then

@kaspar030
Copy link
Contributor

ACK. Let's see how long it takes until we want to use bit.h somewhere else. ;)

@kaspar030 kaspar030 merged commit 42830d2 into RIOT-OS:master Jun 21, 2017
@jnohlgard jnohlgard deleted the pr/cortexm3-bitband branch June 21, 2017 11:18
@aabadie aabadie modified the milestone: Release 2017.07 Jun 26, 2017
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
CI: ready for build If set, CI server will compile all applications for all available boards for the labeled PR Platform: ARM Platform: This PR/issue effects ARM-based platforms Type: enhancement The issue suggests enhanceable parts / The PR enhances parts of the codebase / documentation
Projects
None yet
Development

Successfully merging this pull request may close these issues.

5 participants