SparkFun Forums 

Where electronics enthusiasts find answers.

Topics pertaining to the Arduino Core & software used with the Artemis module and Artemis development boards.
By EarlyRiser
#223440
Hello -
I am using...
Win10
Arduino 1.8.12
Sparkfun Apollo3 Core 2.0.5

I am starting a project that will use Deep Sleep (or as low as it will go) and so am running thru the Apollo/RTC examples.

I started with the Artemis ATP and received an error, then tried the Artemis Dev Kit and finally the Artemis RedBoard Nano - each with the same error.

Is this an issue with 2.0.5 that can be fixed?

The error below is from the Nano --

c:/users/frede/appdata/local/arduino15/packages/sparkfun/tools/arm-none-eabi-gcc/8-2018-q4-major/bin/../lib/gcc/arm-none-eabi/8.2.1/../../../../arm-none-eabi/bin/ld.exe: core\core.a(main.cpp.o): in function `main':

C:\Users\frede\AppData\Local\Arduino15\packages\SparkFun\hardware\apollo3\2.0.5\cores\arduino\mbed-bridge/main.cpp:12: undefined reference to `setup'

c:/users/frede/appdata/local/arduino15/packages/sparkfun/tools/arm-none-eabi-gcc/8-2018-q4-major/bin/../lib/gcc/arm-none-eabi/8.2.1/../../../../arm-none-eabi/bin/ld.exe: C:\Users\frede\AppData\Local\Arduino15\packages\SparkFun\hardware\apollo3\2.0.5\cores\arduino\mbed-bridge/main.cpp:15: undefined reference to `loop'

collect2.exe: error: ld returned 1 exit status
exit status 1
Error compiling for board RedBoard Artemis Nano.

Thanks
#223458
Just checked. No problem on 1.2.1, but in 2.0.5 it gives the same error message.
The issue is related to a check #ifdef I_WANT_TO_BRICK_MY_BOARD. Not sure why that check is there, but it is expecting somewhere a
Code: Select all
#define I_WANT_TO_BRICK_MY_BOARD 1
You can try to add that in your sketch before the #ifdef line, but I don't know whether this sketch will brick-your-board. Never worked with this sketch before.

At least you know the issue of failing linking
#223465
paulvha wrote: Thu Feb 25, 2021 8:00 am Just checked. No problem on 1.2.1, but in 2.0.5 it gives the same error message.
The issue is related to a check #ifdef I_WANT_TO_BRICK_MY_BOARD. Not sure why that check is there, but it is expecting somewhere a
Code: Select all
#define I_WANT_TO_BRICK_MY_BOARD 1
You can try to add that in your sketch before the #ifdef line, but I don't know whether this sketch will brick-your-board. Never worked with this sketch before.

At least you know the issue of failing linking
Hi folks,

I wrote the RTC deep sleep example, which was based on Nathan's low power examples in v1.x of the Apollo3 Core. When Owen rewrote the RTC library for v2.x, he added that #ifdef statement. I've been waiting to learn why: https://github.com/sparkfun/Arduino_Apollo3/issues/337

These examples, and library, were based on the Ambiq HAL, and I suspect that v2.x of the core has broken some functionality. I just tried testing the code on v2.0.5 with an Artemis Redboard but it doesn't appear that the system ever wakes from sleep.

Cheers,
Adam
#223474
There are a couple of issues:
1. In the Sketch, line 99 :
Code: Select all
am_hal_pwrctrl_memory_deepsleep_powerdown(AM_HAL_PWRCTRL_MEM_SRAM_64K_DTCM); // Turn off everything but lower 64k
the program is 121K so we need to comment this out:
Code: Select all
//am_hal_pwrctrl_memory_deepsleep_powerdown(AM_HAL_PWRCTRL_MEM_SRAM_64K_DTCM); // Turn off everything but lower 64k
2. The whole handling of the UART has changed. Much more complex given that Mbed is in between, but the real problem is the fact that NO "deinitialize" is happening. Serial.end() does nothing in 2.0.5, opposite to 1.2.1.
In the Sketch we turn off the power as well as disable the UART0 pins. In wakeup() it will call Serial.begin(), which will lead to an MBED call in unbufferdserial.cpp, which in turn call MBED Serialbase.cpp and from there Serial_api.c. In serial.init() function in Serial_api.c it will ONLY turn on power and set the pins if this was NOT done previous ( e.g. there is no valid handle yet.). BUT as the handle is still valid because as was never de-initialized, power and pins will not be set correctly again.
To overcome, we will have to change the sketch to NOT disable the TX and RX pins and to re-enable the UART power.

I have applied all the necessary changes in the attached sketch and tested that it works on an ATP.
You do not have the required permissions to view the files attached to this post.
#223479
Hi Paul,

Thanks very much! My biggest challenge with Mbed OS has been not knowing what I don't know. The handling of UART is a perfect example of this.

Regarding the changes to the code:
the program is 121K so we need to comment this out:
It makes complete sense to need to keep the lower 512K powered up. I didn't realize how significant the sketch size difference is between v1.x and v2.x. Example 6 on v1.x is approximately 14,000 bytes but 121,000 bytes on v2.x. I assume this is due to it needing to include the Mbed core?

The whole handling of the UART has changed.
Thanks for the heads up. I was unaware of this change. In your code, you modified the range of GPIO pins that are disabled to 0 - 47. I assume this is because GPIO 48/49 are the UART0 TX/RX pins. I've tested your code on a SparkFun Redboard Artemis and an Edge 2 and a side effect I've noticed of this is that the TX LED is now constantly ON when the Artemis is in deep sleep.
Code: Select all
// Disable all pads (do NOT reassign UART TX and RX)
for (int x = 0 ; x < 48 ; x++)
  am_hal_gpio_pinconfig(x, g_AM_HAL_GPIO_DISABLE);
Could we not explicitly re-enable the TX/RX pins in wakeUp() before powering back up UART0 and reinitializing Serial?

Happy to get your thoughts on the best way to approach this. I use the Ambiq HAL because it's what I know. If there's a better way to do it using Mbed OS, I'm all ears.

Cheers,
Adam
#223484
I took the simple approach to not disable the pins. Of course, one can disable all and enable TX/RX pins when waking up. Mbed UnbufferedSerial.cpp does not have an end /de-init function. So that would require a change in Mbed. Best in Serial_Api.cpp, to rework the init function. There is nothing against trying re-applying power and re-setting the pins correctly if you already have a handle. You just have to skip am_hal_uart_initialize() and skip setting the default serial_format() if you have a handle. All the rest (FIFO etc) can be done in my mind with a handle available
#224216
Hi Paul,

Reading up on the Mbed OS memory model (https://os.mbed.com/handbook/Memory-Model), and it looks like program code is stored in flash and static variables, the heap, and the stack are stored in RAM. The Ambiq HAL low power code maintains 512 KB of flash memory and 64 KB of SRAM. Should this not be sufficient for this example, which requires 118 KB program storage space and 28 KB of dynamic memory?
Code: Select all
  am_hal_pwrctrl_memory_deepsleep_powerdown(AM_HAL_PWRCTRL_MEM_FLASH_512K); // Turn off everything but lower 512k
  am_hal_pwrctrl_memory_deepsleep_powerdown(AM_HAL_PWRCTRL_MEM_SRAM_64K_DTCM); // Turn off everything but lower 64k

Thinking in terms of low-power operation, it looks like the HAL provides numerous options for the amount of RAM/flash that remains enabled.
Code: Select all
typedef enum
{
    AM_HAL_PWRCTRL_MEM_NONE,
    AM_HAL_PWRCTRL_MEM_SRAM_8K_DTCM,
    AM_HAL_PWRCTRL_MEM_SRAM_32K_DTCM,
    AM_HAL_PWRCTRL_MEM_SRAM_64K_DTCM,
    AM_HAL_PWRCTRL_MEM_SRAM_96K,
    AM_HAL_PWRCTRL_MEM_SRAM_128K,
    AM_HAL_PWRCTRL_MEM_SRAM_160K,
    AM_HAL_PWRCTRL_MEM_SRAM_192K,
    AM_HAL_PWRCTRL_MEM_SRAM_224K,
    AM_HAL_PWRCTRL_MEM_SRAM_256K,
    AM_HAL_PWRCTRL_MEM_SRAM_288K,
    AM_HAL_PWRCTRL_MEM_SRAM_320K,
    AM_HAL_PWRCTRL_MEM_SRAM_352K,
    AM_HAL_PWRCTRL_MEM_SRAM_384K,
    AM_HAL_PWRCTRL_MEM_FLASH_512K,
    AM_HAL_PWRCTRL_MEM_FLASH_1M,
    AM_HAL_PWRCTRL_MEM_CACHE,
    AM_HAL_PWRCTRL_MEM_ALL,
    AM_HAL_PWRCTRL_MEM_MAX
} am_hal_pwrctrl_mem_e;

Cheers,
Adam
#224296
hi Adam,

This time I did a deep dive and the more I learned the more I realized how incorrect this example is. I have studied the Sparkfun source code, the datasheet and SDK code
1. Calling am_hal_pwrctrl_memory_deepsleep_powerdown()
This will ENABLE powerdown in deepsleep for the memory that is provided. So calling
Code: Select all
am_hal_pwrctrl_memory_deepsleep_powerdown(AM_HAL_PWRCTRL_MEM_FLASH_512K); // Turn off everything but lower 512k
will do exactly the opposite of what the comment states. It will enable power down for the first 512K flash memory during deep sleep. Nothing will be lost as this is flash memory that will retain the content without power.

same for calling
Code: Select all
am_hal_pwrctrl_memory_deepsleep_powerdown(AM_HAL_PWRCTRL_MEM_SRAM_64K_DTCM); // Turn off everything but lower 64k
this will enable the lower 64k to power down during deep sleep.

In wakeUp() routine in the sketch the call :
Code: Select all
am_hal_pwrctrl_memory_deepsleep_powerdown(AM_HAL_PWRCTRL_MEM_MAX);
This would enable ALL memory to power down at deep sleep HOWEVER the wrong argument is used. The source code will check and if the provided argument is higher or equal to AM_HAL_PWRCTRL_MEM_MAX it will fail.

Actually, this call is not needed at all. Whether the memory area will be powered up again after deep sleep is done with the enable call. The Artemis will use the MEMPWREN register which is set during boot.

Now what ??


There is a call am_hal_pwrctrl_memory_deepsleep_retain(). This call will DISABLE the indicated memory area for going power down in deep sleep

So before enabling deep sleep, first enable power down for ALL memory. Then exclude the first 32K by calling am_hal_pwrctrl_memory_deepsleep_retain() for the selected area. No need to maintain the power for the flash..
Code: Select all
  //Power down Flash, SRAM, cache
  am_hal_pwrctrl_memory_deepsleep_powerdown(AM_HAL_PWRCTRL_MEM_ALL);    // enable powerdown of all memory during deepsleep
  am_hal_pwrctrl_memory_deepsleep_retain(AM_HAL_PWRCTRL_MEM_SRAM_32K_DTCM); // disable powerdown of the first 32K memory during deepsleep
Next we remove the am_hal_pwrctrl_memory_deepsleep_powerdown() from wakeUp(). We still need to enable UART0 after wakeUp as that was disabled before AND because of how this driver is integrated with Mbed, it will not re-enable itself.

Attached the adjusted sketch (tested on ATP)
You do not have the required permissions to view the files attached to this post.
#224299
Hi Paul,

Thanks for looking into this. I assume you must have found the Ambiq SDK deepsleep_wake.c example? I'll try to do some current measurements with a SparkFun Edge 2 board to see if I can achieve the same 2.5 uA draw with v2.x of the Apollo3 Core.

The v1.2.1 low power examples were originally written by Nathan and I believe stemmed from Robin Hodgson's efforts: viewtopic.php?f=169&t=50904

I'd be keen to get Robin's thoughts on how to correctly achieve optimal deep sleep currents with the new Mbed OS/Ambiq HAL Apollo3 Core v2.x .

Cheers,
Adam
#224306
Hi Paul,

You are completely right. The previous low-power examples are incorrect. I believe everyone (myself included) just assumed the code was working correctly because we achieved the desirable current consumption.

I was able to confirm a sleep current of 2.27 uA on a SparkFun Edge 2 using on v2.0.6 of the Apollo3 Core and using the following sleep and wake functions. I disable the UART pins and explicitly reenable them. If you omit them from the GPIO disable function, the sleep current jumps to 521 uA.

Are the calls then to Serial.begin() and Serial.end() even necesssary?

Edit: Deep sleep current of 2.08 uA when only 32K of SRAM is retained.

Cheers,
Adam
Code: Select all
void goToSleep()
{
  // Disable UART0
  Serial.end();

  // Disable ADC
  powerControlADC(false);

  // Force the peripherals off
  am_hal_pwrctrl_periph_disable(AM_HAL_PWRCTRL_PERIPH_IOM0);
  am_hal_pwrctrl_periph_disable(AM_HAL_PWRCTRL_PERIPH_IOM1);
  am_hal_pwrctrl_periph_disable(AM_HAL_PWRCTRL_PERIPH_IOM2);
  am_hal_pwrctrl_periph_disable(AM_HAL_PWRCTRL_PERIPH_IOM3);
  am_hal_pwrctrl_periph_disable(AM_HAL_PWRCTRL_PERIPH_IOM4);
  am_hal_pwrctrl_periph_disable(AM_HAL_PWRCTRL_PERIPH_IOM5);
  am_hal_pwrctrl_periph_disable(AM_HAL_PWRCTRL_PERIPH_ADC);
  am_hal_pwrctrl_periph_disable(AM_HAL_PWRCTRL_PERIPH_UART0);
  am_hal_pwrctrl_periph_disable(AM_HAL_PWRCTRL_PERIPH_UART1);

  // Disable all pads
  for (int x = 0 ; x < 50 ; x++)
    am_hal_gpio_pinconfig(x, g_AM_HAL_GPIO_DISABLE);

  // Power down Flash, SRAM, cache
  am_hal_pwrctrl_memory_deepsleep_powerdown(AM_HAL_PWRCTRL_MEM_ALL);    // Powerdown all memory during deepsleep
  am_hal_pwrctrl_memory_deepsleep_retain(AM_HAL_PWRCTRL_MEM_SRAM_64K_DTCM); // Powerup first 64K of SRAM during deepsleep

  // Keep the 32kHz clock running for RTC
  am_hal_stimer_config(AM_HAL_STIMER_CFG_CLEAR | AM_HAL_STIMER_CFG_FREEZE);
  am_hal_stimer_config(AM_HAL_STIMER_XTAL_32KHZ);

  am_hal_sysctrl_sleep(AM_HAL_SYSCTRL_SLEEP_DEEP); // Sleep forever

  // And we're back!
  wakeUp();
}

// Power up gracefully
void wakeUp()
{
  // Go back to using the main clock
  am_hal_stimer_config(AM_HAL_STIMER_CFG_CLEAR | AM_HAL_STIMER_CFG_FREEZE);
  am_hal_stimer_config(AM_HAL_STIMER_HFRC_3MHZ);

  // Reconfigure UART0 pins and reenable power to interface
  am_hal_gpio_pinconfig(48, g_AM_BSP_GPIO_COM_UART_TX);
  am_hal_gpio_pinconfig(49, g_AM_BSP_GPIO_COM_UART_RX);
  am_hal_pwrctrl_periph_enable(AM_HAL_PWRCTRL_PERIPH_UART0);

  // Enable ADC
  initializeADC();

  // Enable Serial
  Serial.begin(115200);
}
#224309
thanks Adam. I have read the link to Robin's entry and I found we are in sync. Unfortunately, the Serial.end() does not do anything in the current version (up to 2.0.6). It is an empty routine and that is part of the problem that we need to re-enable UART after waking-up. The Serial.begin() will set for the right speed, bits and parity, just in case it is different than default values.
#224336
Hi Paul,

A quick note that the following code does not work on Apollo3 Core v1.2.1. The watchdog timer is rendered inoperable and the system enters into a reset loop.
Code: Select all
  // Power down flash, SRAM, cache
  am_hal_pwrctrl_memory_deepsleep_powerdown(AM_HAL_PWRCTRL_MEM_ALL); // Power down all memory during deepsleep
  am_hal_pwrctrl_memory_deepsleep_retain(AM_HAL_PWRCTRL_MEM_FLASH_512K); // Retain lower 512K of CACHE
  am_hal_pwrctrl_memory_deepsleep_retain(AM_HAL_PWRCTRL_MEM_SRAM_64K_DTCM); // Retain lower 64K of SRAM
However, if I switch to AM_HAL_PWRCTRL_MEM_MAX instead of AM_HAL_PWRCTRL_MEM_ALL, the system works as intended.
Code: Select all
  am_hal_pwrctrl_memory_deepsleep_powerdown(AM_HAL_PWRCTRL_MEM_MAX); // Power down all memory during deepsleep

Could it be that we're inadvertently powering down memory that is critical to the overall operation?

Cheers,
Adam
 Topic permissions

You can post new topics in this forum
You can reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum
You cannot post attachments in this forum