Saving RAM used for PIN_MAP

Information on the latest releases
User avatar
RogerClark
Posts: 7436
Joined: Mon Apr 27, 2015 10:36 am
Location: Melbourne, Australia
Contact:

Saving RAM used for PIN_MAP

Post by RogerClark » Thu May 07, 2015 10:24 am

Guys,

I've added a branch to the repo which contains the work done by VictorPB, RIck and mrburnette, to move the PIN_MAP array from RAM into Flash

This free's up 276 bytes of RAM, but more importantly, it should fix issue we currently have where libraries use pinMode, digitalRead or digitalWrite in their constructors (more details later)

The results fro an empty sketch are

With PIN_MAP in RAM

Sketch uses 11,464 bytes (8%) of program storage space. Maximum is 128,000 bytes.
Global variables use 3,888 bytes of dynamic memory.

With PIN_MAP in Flash

Sketch uses 11,188 bytes (8%) of program storage space. Maximum is 128,000 bytes.
Global variables use 3,312 bytes of dynamic memory.

Note, if the sketch is smaller than you see on your compile, its because of a separate change I made which free's up over 1k of Flash when I turned off some unused printing facilities.

Some technical background.
The PIN_MAP array. is used by the core to lookup the hardware register and bit data from pin names (or numbers).
The parts of the core which use the array are functions like pinMode and digitalRead, but it also gets used by the analogRead and also to control PWM etc.

I think the initial intention was for this to be in flash, as its all static / const data, but the compiler chose to stick it in RAM.

However with the changes made by Rick and Victor the compile is now happy to put it in Flash (program memory)

We have profiled whether there is a speed impact of this change, and there is a very small speed decrease in GPIO speed, but we can probably bring this back to the current speed by removing one out of bounds check in those functions.


Although 276 extra bytes of RAM doesn't seem a lot, the major advantage of this change is that the PIN_MAP data will be available to all functions from the moment the code starts running, which means that libraries which use pinMode etc in their constructors (which are run before even setup() is run), will be able to access those functions, where as before, it was fairly random whether they would work at all.
The reason it was random, is that the C language doesn't define the order in which global variables and global constructors are run, hence sometimes PIN_MAP may be initialised as the first thing, sometimes it could be the last.


Anyway, if you are interested in trying the new version, download a new zip from this link

https://github.com/rogerclarkmelbourne/ ... P-in-FLASH

Or for anyone using git, just do a pull and then checkout the PIN_MAP-in-FLASH branch
e.g. git checkout PIN_MAP-in-FLASH

Edit.

I have only updated the Maple mini and Generic STM32F103C series boards with this change, but I think thats what 90% of people are using.
(sorry Matthias, I will try to do nucleo in a minute)

User avatar
Rick Kimball
Posts: 1056
Joined: Tue Apr 28, 2015 1:26 am
Location: Eastern NC, US
Contact:

Re: Saving RAM used for PIN_MAP

Post by Rick Kimball » Thu May 07, 2015 1:08 pm

You might want to crank up the warning level to -Wall with this new branch during testing.

Here is a sample of some of the errors:

Code: Select all

arm-none-eabi-gcc -mcpu=cortex-m3 ... many gcc args removed for post ... "../cores/maple/libmaple/gpio_f1.c"
../cores/maple/libmaple/gpio_f1.c:39:17: warning: 'gpioa' initialized and declared 'extern' [enabled by default]
 extern gpio_dev gpioa = {
gpoia is already declare as an extern in the header. You don't need to do that for the .c file you might change to something like this:

Code: Select all

diff --git a/STM32F1/cores/maple/libmaple/gpio_f1.c b/STM32F1/cores/maple/libmaple/gpio_f1.c
index 37592c4..2e13d0d 100644
--- a/STM32F1/cores/maple/libmaple/gpio_f1.c
+++ b/STM32F1/cores/maple/libmaple/gpio_f1.c
@@ -36,7 +36,7 @@
  * GPIO devices
  */
 
-extern gpio_dev gpioa = {
+gpio_dev gpioa = {
     .regs      = GPIOA_BASE,
     .clk_id    = RCC_GPIOA,
     .exti_port = EXTI_PA,
@@ -44,7 +44,7 @@ extern gpio_dev gpioa = {
 /** GPIO port A device. */
 gpio_dev* const GPIOA = &gpioa;
 
-extern gpio_dev gpiob = {
+gpio_dev gpiob = {
-rick

victor_pv
Posts: 1738
Joined: Mon Apr 27, 2015 12:12 pm

Re: Saving RAM used for PIN_MAP

Post by victor_pv » Thu May 07, 2015 1:52 pm

Rick,

Is that the only file you get warnings on? I am very new to C and C++ and didn't know you only need to declare extern in the header, one more thing I learnt today :) I may have done the same thing with extern in some of the other files I had to modify for PIN_MAP.

User avatar
Rick Kimball
Posts: 1056
Joined: Tue Apr 28, 2015 1:26 am
Location: Eastern NC, US
Contact:

Re: Saving RAM used for PIN_MAP

Post by Rick Kimball » Thu May 07, 2015 1:55 pm

No there are few files with errors like that. That was just a single sample.
-rick

User avatar
Rick Kimball
Posts: 1056
Joined: Tue Apr 28, 2015 1:26 am
Location: Eastern NC, US
Contact:

Re: Saving RAM used for PIN_MAP

Post by Rick Kimball » Thu May 07, 2015 2:09 pm

@RogerClark do you want follow up here or in the issues on github?

I was wondering about the pinMode field of the struct stm32_pin_info. It didn't seemed to be used anywhere so I commented it out and recompiled and everything seemed to still work.

Code: Select all

diff --git a/STM32F1/cores/maple/wirish_types.h b/STM32F1/cores/maple/wirish_types.h
index f1ae4a0..b41f51a 100644
--- a/STM32F1/cores/maple/wirish_types.h
+++ b/STM32F1/cores/maple/wirish_types.h
@@ -55,7 +55,7 @@ typedef struct stm32_pin_info {
     uint8 gpio_bit;             /**< Pin's GPIO port bit. */
     uint8 timer_channel;        /**< Timer channel, or 0 if none. */
     uint8 adc_channel;          /**< Pin ADC channel, or ADCx if none. */
-       uint8 pinMode;                          /**< mode specific by pinMode call (Roger Clark added to optimize compatibility
+       //uint8 pinMode;                                /**< mode specific by pinMode call (Roger Clark added to optimize compa
Is that still needed?

-rick
-rick

User avatar
ahull
Posts: 1650
Joined: Mon Apr 27, 2015 11:04 pm
Location: Sunny Scotland
Contact:

Re: Saving RAM used for PIN_MAP

Post by ahull » Thu May 07, 2015 7:57 pm

@Roger...

git checkout PIN_MAP-in-FLASH

.. that works for me, sketches compile, USB serial works, analogRead speed is pretty much as before, so far so good.
- Andy Hull -

User avatar
RogerClark
Posts: 7436
Joined: Mon Apr 27, 2015 10:36 am
Location: Melbourne, Australia
Contact:

Re: Saving RAM used for PIN_MAP

Post by RogerClark » Fri May 08, 2015 5:36 am

Rick has found some problems

Its not being initialized for him :-(

I'm not sure if its that I didnt copy all the files correctly.

I've attached Ricks test files

PC13 is the LED on the generic board, if you are using a Maple mini I think this is PB1 or 33

I've not had time to test victors original repo but I will do that later to see if its something I failed to copy over (of which was not in Victors list of changed files)
Attachments
pim_map_test.ino
(315 Bytes) Downloaded 52 times
ActiveLowLED.h
(692 Bytes) Downloaded 25 times

victor_pv
Posts: 1738
Joined: Mon Apr 27, 2015 12:12 pm

Re: Saving RAM used for PIN_MAP

Post by victor_pv » Fri May 08, 2015 1:48 pm

Just tried that, and doesn't work for me either.
So we have PIN_MAP which is a table with pointers to some structs. Now we have the table in flash, but I bet all the gpio variables are still in RAM, and some not initialized in time.
I will have a look later if I have some time.

EDIT: Looks like the gpio structures have the correct values before they are copied from flash to RAM on the initialization code. Now, I remember in ARM before a pin can be used it's clock need to be setup, and not sure what else needs to be set up for the pin.
Do we know when does that happen?
We have this function in the gpio_f1.c file:
/**
* Initialize and reset all available GPIO devices.
*/
void gpio_init_all(void) {

If that gets called after the constructor sets the pinmode, I bet it will reset it back to default.

User avatar
RogerClark
Posts: 7436
Joined: Mon Apr 27, 2015 10:36 am
Location: Melbourne, Australia
Contact:

Re: Saving RAM used for PIN_MAP

Post by RogerClark » Fri May 08, 2015 9:54 pm

Victor

Re RCC not being set before pin mode

This crossed my mind as well.

I had a quick chat with Rick on IRC yesterday about it.

But Rick said that for him all the pointers in pin map were null.
He is using GDB via stlink, so he can look at the code in real time and set break points etc.


Anyway, I agree it could also be an RCC issue. But we could easily test this, by putting code into the test constructor or begin() that is hard coded to that register address e.g. Port C HighByte control register

Then if that works we will know that the pin mode can be set before RCC is set.

We'd also need to check the init code is not going through the whole pin map array setting all pins as inputs etc.

victor_pv
Posts: 1738
Joined: Mon Apr 27, 2015 12:12 pm

Re: Saving RAM used for PIN_MAP

Post by victor_pv » Fri May 08, 2015 11:30 pm

Roger, I have confirmed the issue is that init() is not called soon enough, and so when init() is called the pin settings get reset, and the pin mode is lost.

I tested calling init() from the constructor, and I can manipulate the pin within the constructor. When the constructor code finishes, and the code eventually calls init() again before calling main, the pin is reset to input and I can not control the led anymore, unless I set pinMode again.
I modified his constructor like this:

Code: Select all

  ActiveLowLED(const int pin) : _pin(pin), _initialized(0) {
    init();
    begin();
    for (int n=20; n>0; n--){
    on();
    delay (500);
    off ();
    delay (500);
    };
  }
and I get the 20 cycles of on/off at 1hz, then nothing else after that, unless I set the pinMode again.
Now, I know my pinmap is in flash, but perhaps I forgot some other file I changed, I will try to compare the folder with my fork of your repo and see what else is different.

EDIT:
Just checked the files modification dates and don't see anything else modified in the last few days, but I will compare that folder with the fork it came from and see if I modified anything related days ago.

Post Reply