in C, how do I perform equivalent of stm.mem32[x]= y ?

C programming, build, interpreter/VM.
Target audience: MicroPython Developers.
Post Reply
nmz787
Posts: 29
Joined: Sun Jul 10, 2016 7:57 am

in C, how do I perform equivalent of stm.mem32[x]= y ?

Post by nmz787 » Wed May 30, 2018 8:48 am

I am trying to write a very tight loop in C, based on the adc.c

Code: Select all

read_timed
method... it might end up turning into a PI or PID control loop to control the width or period of two timer PWM channels. In Python I was calling this sort of function to adjust the PWM/Timer period and width:

Code: Select all

def adjust_tim2(period, width):
  stm.mem32[stm.TIM2 + stm.TIM_ARR] = period
  stm.mem32[stm.TIM2 + stm.TIM_CCR1] = period - width
but after grepping the repo for

Code: Select all

mem16
I am at a loss as for how to do this in my hacked/custom C code/module, probably due to misunderstanding and being unfamiliar with the MicroPython C macros.

Thanks in advance!

stijn
Posts: 735
Joined: Thu Apr 24, 2014 9:13 am

Re: in C, how do I perform equivalent of stm.mem32[x]= y ?

Post by stijn » Wed May 30, 2018 9:53 am

If you grep for mem16 you'll see it is part of the stm module as defined in modstm.c where it says

Code: Select all

{ MP_ROM_QSTR(MP_QSTR_mem16), MP_ROM_PTR(&machine_mem16_obj) },
The MP_QSTR_ prefix is an implementation detail because strings are interned in MicroPython, important part is it tells you
stm.mem16 returns machine_mem16_obj.
Look for that in turn you'll see it's C definition in machine_mem.c, it's an object of type machine_mem_type. Which has a 'subscr' member pointing to the machine_mem_subscr method which is what gets executed when you run stm.mem16[someIndex] = someValue.

So in your C code you'll have something like machine_mem16_obj.base.type->subscr(machine_mem16_obj, mp_obj_new_int(myIndex), mp_obj_new_int(myValue)); (note: didn't test this, but that should be the principle).
Or if that's still too slow for you ou could copy parts of the machine_mem_subscr implementation to read/write addresses directly.

User avatar
dhylands
Posts: 3821
Joined: Mon Jan 06, 2014 6:08 pm
Location: Peachland, BC, Canada
Contact:

Re: in C, how do I perform equivalent of stm.mem32[x]= y ?

Post by dhylands » Wed May 30, 2018 6:08 pm

Unless I had a particular reason to do so, I wouldn't try to mimic exactly what stm.mem32 was doing. I would do it the "C" way.

For the python function:

Code: Select all

def adjust_tim2(period, width):
  stm.mem32[stm.TIM2 + stm.TIM_ARR] = period
  stm.mem32[stm.TIM2 + stm.TIM_CCR1] = period - width
I would code it in C as:

Code: Select all

#include "py/mphal.h"

void adjust_tim2(uint32_t period, uint32_t width) {
    TIM2->ARR = period;
    TIM2->CCR1 = period - width;
}
The python stm constants like TIM2 and TIM_ARR are generated by running python script over the C header files found in the CMSIS library, which you can find in lib/stm32lib/CMSIS/STM32F4xx/Include/stm32f405xx.h (which is #included indirectly thru mphal.h)

There are ways to generalize this even more, but without knowing more about what you're doing, I can't really recommend anything.

stijn
Posts: 735
Joined: Thu Apr 24, 2014 9:13 am

Re: in C, how do I perform equivalent of stm.mem32[x]= y ?

Post by stijn » Wed May 30, 2018 6:45 pm

dhylands wrote:
Wed May 30, 2018 6:08 pm
The python stm constants like TIM2 and TIM_ARR are generated by running python script over the C header files found in the CMSIS library, which you can find in lib/stm32lib/CMSIS/STM32F4xx/Include/stm32f405xx.h (which is #included indirectly thru mphal.h)
Nice, didn't know that. In that case and if the code doesn't have to be generic your 'C way' is way better than what I proposed.

nmz787
Posts: 29
Joined: Sun Jul 10, 2016 7:57 am

Re: in C, how do I perform equivalent of stm.mem32[x]= y ?

Post by nmz787 » Wed May 30, 2018 7:21 pm

stijn wrote:
Wed May 30, 2018 9:53 am
If you grep for mem16 you'll see it is part of the stm module as defined in modstm.c where it says

Code: Select all

{ MP_ROM_QSTR(MP_QSTR_mem16), MP_ROM_PTR(&machine_mem16_obj) },
The MP_QSTR_ prefix is an implementation detail because strings are interned in MicroPython, important part is it tells you
stm.mem16 returns machine_mem16_obj.
Look for that in turn you'll see it's C definition in machine_mem.c, it's an object of type machine_mem_type. Which has a 'subscr' member pointing to the machine_mem_subscr method which is what gets executed when you run stm.mem16[someIndex] = someValue.

So in your C code you'll have something like machine_mem16_obj.base.type->subscr(machine_mem16_obj, mp_obj_new_int(myIndex), mp_obj_new_int(myValue)); (note: didn't test this, but that should be the principle).
Or if that's still too slow for you ou could copy parts of the machine_mem_subscr implementation to read/write addresses directly.
Thanks, your explanation is exactly what I lacked and was hoping after I indeed saw that line in my searching. I haven't had much time to dig deep lately, and honestly didn't really having a feeling on what to do next besides moving up the directory tree (started in ports/stm32), then grepping the macros MP_ROM_QSTR and MP_ROM_PTR. The method/variable subscr is a bit confusing... I was initially reading it as 'subscriber' but now after a minute it's sticking that it means subscript... but now I am not so sure.

Regardless, when I get to the end of the line, the machine_mem_subscr method, I'm still at a loss for how to get the correct address to write to, so I'd still need to dig more into MICROPY_MACHINE_MEM_GET_WRITE_ADDR.

dhylands wrote:
Wed May 30, 2018 6:08 pm

Code: Select all

#include "py/mphal.h"

void adjust_tim2(uint32_t period, uint32_t width) {
    TIM2->ARR = period;
    TIM2->CCR1 = period - width;
}
Awesome, this is pretty much exactly what I want to do in my code. Thanks!
The python stm constants like TIM2 and TIM_ARR are generated by running python script over the C header files
I assumed that much, but indeed didn't know where they ended up being generated (I was grepping a micropython repo with a build in it).
found in the CMSIS library, which you can find in lib/stm32lib/CMSIS/STM32F4xx/Include/stm32f405xx.h (which is #included indirectly thru mphal.h)

There are ways to generalize this even more, but without knowing more about what you're doing, I can't really recommend anything.
Great, thanks, very valuable and should immediately help me move along.

If I wanted to generalize a bit, just for syntactic sugar, outside my "needs to be fast" code loop, could I pre-fetch the relevant addresses (TIM2->ARR) with a call to MICROPY_MACHINE_MEM_GET_WRITE_ADDR ?


Thanks both of you!!!

User avatar
dhylands
Posts: 3821
Joined: Mon Jan 06, 2014 6:08 pm
Location: Peachland, BC, Canada
Contact:

Re: in C, how do I perform equivalent of stm.mem32[x]= y ?

Post by dhylands » Wed May 30, 2018 7:57 pm

nmz787 wrote:
Wed May 30, 2018 7:21 pm
If I wanted to generalize a bit, just for syntactic sugar, outside my "needs to be fast" code loop, could I pre-fetch the relevant addresses (TIM2->ARR) with a call to MICROPY_MACHINE_MEM_GET_WRITE_ADDR ?
You can get the equivalent value by doing:

Code: Select all

uint32_t *tim2_arr = &TIM2->ARR;
and then later assign it using:

Code: Select all

*tim2_arr = val;
If you look in this file: https://raw.githubusercontent.com/micro ... 32f405xx.h and search for TIM2, you'll see that TIM2 is defined to be:

Code: Select all

#define TIM2                ((TIM_TypeDef *) TIM2_BASE)
In otherwords just a pointer to a structure mapped to a particular memory address. If you then search for TIM_TypeDef you'll see that ARR is a member of that structure.

You can see the QSTR constants in build-PYBV11/genhdr/modstm_const.h

Code: Select all

...
{ MP_ROM_QSTR(MP_QSTR_TIM2), MP_ROM_PTR(&mpz_40000000) },
...
{ MP_ROM_QSTR(MP_QSTR_TIM_ARR), MP_ROM_INT(0x2c) }, // 32-bits, TIM auto-reload register
...
The C macro offsetof could be used on the ARR member and you'd discover that offsetof(TIM_TypeDef, ARR) would yield the value 0x2c

Getting back to your original question, MICROPY_MACHINE_MEM_GET_WRITE_ADDR is defined here: https://github.com/micropython/micropyt ... _mem.c#L53 and machine_mem_get_addr is defined here: https://github.com/micropython/micropyt ... _mem.c#L42

Because the MICROPY_MACHINE_MEM_GET_WRITE_ADDR is #defined inside a C file and not a header file you can only use it from within machine_mem.c and because machine_mem_get_addr is defined as a static function you can't call it from outside machine_mem.c

In order to use the actual python constants, you'd need to look up the TIM2 object and the TIM_ARR object, convert them to ints, add them together and then convert back to a pointer:

Code: Select all

uint32_t TIM2_value = some-mp-function-to-lookup(stm.TIM2);
uint32_t TIM_ARR_value = some-mp-function-to-lookup(stm.TIM_ARR);
uint32_t *tim2_arr = (uint32_t *)(TIM2_value + TIM_ARR_value);
which is basically just a very expensive way of doing:

Code: Select all

uint32_t *tim2_arr = &TIM2->ARR;

Post Reply