Author Topic: STM32 Simple Blink CMSIS bit manip question?  (Read 8069 times)

0 Members and 1 Guest are viewing this topic.

Offline blewisjrTopic starter

  • Frequent Contributor
  • **
  • Posts: 301
STM32 Simple Blink CMSIS bit manip question?
« on: March 25, 2014, 09:16:00 pm »
Hello Everyone,

I am not quite sure if I did this correctly.  My first blink was with the STM32 lib and I decided to convert it over to CMSIS so I can build my own library slowly as I learn the chip.

Essentially I setup all the registers and then used a for loop as a delay.  The code does work but I am not sure if it is working because of register defaults or if I got the bit twiddling correct.  I never had to really manipulate 2 bits at the same time this way before.  So I may be going about it wrong.  I know MODER is suppose to be 2 bits for output it should be 01 but when I tried the double twiddle it ended up flipping the whole register 1 and had the appropriate bit set to 0 but it should have been whole register 0 with appropriate bit to 1.  To fix that I relied on the default and just flipped the one bit to 1.  Here is the code maybe someone can better explain how to manipulate 2 bits at once especially the case when you need a 01 or a 10 as 00 and 11 are easy?  I know elementary C and I am drawing  a blank on the manipulation of 2 bits.  |O

Code: [Select]
#include "stm32f30x.h"

void delay(int length);

int main(void)
{
/* Enable GPIOE Clock */
RCC->AHBENR |= (1<<21);

/* Setup PE11 as output */
GPIOE->MODER |= (1<<22);
GPIOE->OTYPER &= ~(1<<11);
GPIOE->OSPEEDR |= (1<<23)|(1<<22);
GPIOE->PUPDR &= ~(1<<23)|~(1<<22);

while (1)
{
GPIOE->BSRR = (1<<11);
delay(5000000);
GPIOE->BRR = (1<<11);
delay(5000000);
}
}

void delay(int length)
{
int i = 0;
for (i = 0; i < length; i++);
}

 

Offline dannyf

  • Super Contributor
  • ***
  • Posts: 8221
  • Country: 00
Re: STM32 Simple Blink CMSIS bit manip question?
« Reply #1 on: March 25, 2014, 11:12:09 pm »
The general structure is valid - I didn't check the bits for you.

I would, however, rearrange the code a little bit differently in order to maximize their reusability:

Code: [Select]

#define LED_PORT GPIOE //leds on GPIOE
#define LED_DDR   GPIOE
#define LED            (1<<11) //led on porte.11

#define PIN_SET(port, pins) port->ODR |= (pins) //set pins on port
#define PIN_CLR(port, pins) port->ODR &=~(pins) //clear pins on port
#define PIN_GET(port, pins) ((port->IDR) & (pins)) //read pins on port
#define FPIN_SET(port, pins) port->BSRR = (pins) //fast_st pins on port
#define FPIN_CLR(port, pins port->BRR = (pins) //fast_clear pins on port
#define FPIN_GET(port, pins) PIN_GET(port, pins) //no fast get routines

//initialize the mcu
void mcu_init(void) {
  SystemCoreClockUpdate(); //update systemcore clock in case you use non-default settings
  RCC->AHBENR |= RCC_AHBENR_GPIOEEN; //enable gpioe clock
  //set other rcc gates here too
}

in main
  mcu_init(); //reset the mcu
  PIN_OUT(LED_DDR, LED); //led as output
  while (1) {
    PIN_SET(LED_PORT, LED); //set led
    delay(5000000);
    PIN_CLR(LED_PORT, LED); //clear led
    delay(5000000);
  }
}


You can put mcu_init() and the associated macros in a .c/.h file to be called on in the future. With this approach you don't have to worry about remembering all those details next time.

Code: [Select]
GPIOE->OSPEEDR |= (1<<23)|(1<<22);
Alternatively:
Code: [Select]
GPIOE->OSPEEDR |= (0x03<<22);
« Last Edit: March 25, 2014, 11:15:27 pm by dannyf »
================================
https://dannyelectronics.wordpress.com/
 

Offline dannyf

  • Super Contributor
  • ***
  • Posts: 8221
  • Country: 00
Re: STM32 Simple Blink CMSIS bit manip question?
« Reply #2 on: March 25, 2014, 11:15:01 pm »
If you were to use the oem library, setting up the pins as output would be as simple as this:

Code: [Select]
void PIN_OUT(GPIO_TypeDef* port, uint16_t pins) {
GPIO_InitTypeDef        GPIO_InitStruct;

/* Configure PC8 and PC9 in output pushpull mode */
GPIO_InitStruct.GPIO_Pin = pins; //GPIO_Pin_0..15 + GPIO_Pin_All
GPIO_InitStruct.GPIO_Mode = GPIO_Mode_OUT; //GPIO_Mode_Out_PP -> push-pull; GPIO_Mode_Out_OD -> open drain
GPIO_InitStruct.GPIO_OType = GPIO_OType_PP;
GPIO_InitStruct.GPIO_Speed = GPIO_Speed_50MHz; //GPIO_Speed_50Mhz -> 50Mhz; GPIO_Speed_2Mhz -> 2Mhz; GPIO_Speed_10Mhz -> 10Mhz
GPIO_InitStruct.GPIO_PuPd = GPIO_PuPd_NOPULL;
GPIO_Init(port, &GPIO_InitStruct);

}
================================
https://dannyelectronics.wordpress.com/
 

Offline dannyf

  • Super Contributor
  • ***
  • Posts: 8221
  • Country: 00
Re: STM32 Simple Blink CMSIS bit manip question?
« Reply #3 on: March 25, 2014, 11:18:20 pm »
Code: [Select]
#define LED            (1<<11) //led on porte.11
This approach allows you to set/clear multiple pins, by defining LED differently.

Code: [Select]
#define LED0            (1<<11) //led on porte.11
#define LED1            (1<<2) //led on porte.2
#define LED2           (1<<5) //led on porte.5
#define LEDs            (LED0 | LED1 | LED2) //leds = led0+led1+led2

  PIN_SET(LED_PORT, LEDs); //set led0/1/2
  PIN_CLR(LED_PORT, LED2); //clear led2

================================
https://dannyelectronics.wordpress.com/
 

Offline dannyf

  • Super Contributor
  • ***
  • Posts: 8221
  • Country: 00
Re: STM32 Simple Blink CMSIS bit manip question?
« Reply #4 on: March 25, 2014, 11:20:50 pm »
The FPIN_xxx() vs. PIN_xxx() come from my LPC days. They allow faster port actions.

Those macros or routines can be easily ported to ARM chips that allow bit banding (LM4F120 from TI or luminary chips for example). Pin actions on those chips are single cycle. Very handy.
================================
https://dannyelectronics.wordpress.com/
 

Offline blewisjrTopic starter

  • Frequent Contributor
  • **
  • Posts: 301
Re: STM32 Simple Blink CMSIS bit manip question?
« Reply #5 on: March 26, 2014, 12:00:16 am »
Wow thanks for all the replies danny.  Yes I do know it is simple to do with the OEM library.  Thanks for some of the bit set tricks as well.  Macros would be useful but I just wanted to make sure I could get the thing working with CMSIS before I started adding in macros.  Like I said my big issue is figuring out the bit routine to get a 10 or 01 on the double registers.  I will have to tinker around with the bit math a bit to figure it out might be as simple as using a hex value instead of 1 on the shift.
 

Offline westfw

  • Super Contributor
  • ***
  • Posts: 4199
  • Country: us
Re: STM32 Simple Blink CMSIS bit manip question?
« Reply #6 on: March 26, 2014, 06:37:55 am »
Quote
If you were to use the oem library, setting up the pins as output would be as simple as
Is that sarcasm?  It doesn't look that much simpler than modifying the raw register bits to me.  Slightly more abstracted, but not a lot, and it seems to me that you pay substantially for that abstraction (setting up a bunch of memory as an abstracted GPIO_InitStruct, and then the library code presumably un-abstracting it back...)   And for all it's abstraction, that GPIO_InitStruct is still ST specific, right?

Setting a multi-bit field to a particular value requires that you make sure that the one and zero bits get set.
Something like:
Code: [Select]
GPIOE->MODER = (GPIO_MODER & ~(3<<22))  // old contents with our bitfield zero'ed
               | (0b01<<22); // or in our desired value.

(although in this case, you're only setting one bit anyway...)
« Last Edit: March 28, 2014, 04:42:22 pm by westfw »
 

Offline poorchava

  • Super Contributor
  • ***
  • Posts: 1672
  • Country: pl
  • Troll Cave Electronics!
Re: STM32 Simple Blink CMSIS bit manip question?
« Reply #7 on: March 26, 2014, 10:59:16 am »
Cortex M3 has a feature called bit-banding, this is an ideal solution which allows for atomic operations on single bits. It means that every register has its own address, but also every bit in that register is mapped to a location in address space. If that location is written then you get a single operation atomic access to that bit. No |=1<<x needed. You can find handy macros for that one the net (you want this to be a macro, so it's evaluated at compile time, not at runtime.
I love the smell of FR4 in the morning!
 

Offline dannyf

  • Super Contributor
  • ***
  • Posts: 8221
  • Country: 00
Re: STM32 Simple Blink CMSIS bit manip question?
« Reply #8 on: March 26, 2014, 11:06:11 am »
Quote
using a hex value

You should thinking about writing code as investment: write it once and use it as many times as possible.

For that to work, you should avoid hardcoding as much as you can. Instead of using hex values, you has the defined names in the header file as much as you can, and shield your code from the details as much as you can.

For example, use the PIN_xxx() macros for pin / port operations. When you move the code to a different chip, all you need is to include the appropriate PIN_xxx() macros for the new target and you are in business.
================================
https://dannyelectronics.wordpress.com/
 

Offline blewisjrTopic starter

  • Frequent Contributor
  • **
  • Posts: 301
Re: STM32 Simple Blink CMSIS bit manip question?
« Reply #9 on: March 26, 2014, 11:41:12 am »
[quote[If you were to use the oem library, setting up the pins as output would be as simple as
Is that sarcasm?  It doesn't look that much simpler than modifying the raw register bits to me.  Slightly more abstracted, but not a lot, and it seems to me that you pay substantially for that abstraction (setting up a bunch of memory as an abstracted GPIO_InitStruct, and then the library code presumably un-abstracting it back...)   And for all it's abstraction, that GPIO_InitStruct is still ST specific, right?

Setting a multi-bit field to a particular value requires that you make sure that the one and zero bits get set.
Something like:
Code: [Select]
GPIOE->MODER = (GPIO_MODER & ~(3<<22))  // old contents with our bitfield zero'ed
               | (0b01<<22); // or in our desired value.

(although in this case, you're only setting one bit anyway...)
[/quote]

Ah yes thanks a bunch westfw that joggled my memory makes perfect sense now I will try it out and see if the registers get set the way I expect.
 

Offline dannyf

  • Super Contributor
  • ***
  • Posts: 8221
  • Country: 00
Re: STM32 Simple Blink CMSIS bit manip question?
« Reply #10 on: March 26, 2014, 12:32:40 pm »
Take a look at the _gpio.h and _gpio.c files and you can see how ST implemented that. For example, the '3' in '3<<22' are defined in the device header file and should be used instead of a hardcoded '3'.
================================
https://dannyelectronics.wordpress.com/
 

Offline westfw

  • Super Contributor
  • ***
  • Posts: 4199
  • Country: us
Re: STM32 Simple Blink CMSIS bit manip question?
« Reply #11 on: March 26, 2014, 05:39:19 pm »
Are there "standard" C macros for dealing with bitfields?
Something like
BITFIELD(MODER11, 22, 23);  Or BITFIELD(MODER11, 0x00C00000);
SET_BITFIELD(MODER11, 3);
i = GET_BITFIELD(MODER11);

The CMSIS peripheral definitions don't seem to break things down any smaller than words or bytes (no bitfields), making them relatively useless :-(
(Is there a description somewhere on how these are supposed to work?  I keep getting redirected to the CMSIS functions that work on the core, where much more of the info is "standardized.")
 

Offline dannyf

  • Super Contributor
  • ***
  • Posts: 8221
  • Country: 00
Re: STM32 Simple Blink CMSIS bit manip question?
« Reply #12 on: March 27, 2014, 12:32:07 pm »
Quote
Cortex M3 has a feature called bit-banding

Three approaches reduce the usefulness of bit banding:

1) the mask - as used by NXP on their LPC chips; Very handy.
2) the BSRR and BRR registers - as used by ST;
3) BME - by Freescale.
================================
https://dannyelectronics.wordpress.com/
 

Offline westfw

  • Super Contributor
  • ***
  • Posts: 4199
  • Country: us
Re: STM32 Simple Blink CMSIS bit manip question?
« Reply #13 on: March 27, 2014, 04:56:53 pm »
I don't see how bitbanding helps very much on muti-bit fields.
(most of the microcontroller class chips have additional mechanisms for dealing with GPIO pins, but that's not what we're talking about here...)

ARM CM3 and up do have bitfield instructions.  "BFI" looks to do just the right thing, if your values are in register; I'm not sure it would be quicker or shorter than the and/or combinations if the goal is to set a constant in a memory location (ie peripheral register.)
 


Share me

Digg  Facebook  SlashDot  Delicious  Technorati  Twitter  Google  Yahoo
Smf