Skip to content

[Observation] Need to manually re-enable the Serial TX and RX pins after SLEEP_DEEP with v2.1 #411

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

Open
PaulZC opened this issue Jul 5, 2021 · 4 comments

Comments

@PaulZC
Copy link
Contributor

PaulZC commented Jul 5, 2021

Another observation...

With v2.1 of the core, we need to manually re-enable the Serial TX and RX pins after disabling them to reduce power consumption during SLEEP_DEEP.

With v1.2 of the core, we didn't need to do this.

Steps to reproduce:
RedBoard Artemis ATP
v2.1 of the core
Run the following example:

extern "C" void am_stimer_cmpr6_isr(void)
{
  uint32_t ui32Status = am_hal_stimer_int_status_get(false);
  if (ui32Status & AM_HAL_STIMER_INT_COMPAREG)
  {
    am_hal_stimer_int_clear(AM_HAL_STIMER_INT_COMPAREG);
  }
}

void setup() {
  Serial.begin(115200);
  Serial.println(F("Apollo3: Serial and micros after deep sleep test"));
  Serial.flush();
}

void loop() {

  Serial.end();

  //Force UART0 off
  am_hal_pwrctrl_periph_disable(AM_HAL_PWRCTRL_PERIPH_UART0);

  //Disable the TX and RX pins
  am_hal_gpio_pinconfig(48 , g_AM_HAL_GPIO_DISABLE); //TX0
  am_hal_gpio_pinconfig(49 , g_AM_HAL_GPIO_DISABLE); //RX0

  //We use counter/timer 6 to cause us to wake up from sleep but 0 to 7 are available
  //CT 7 is used for Software Serial. All CTs are used for Servo.
  am_hal_stimer_int_clear(AM_HAL_STIMER_INT_COMPAREG);  //Clear CT6
  am_hal_stimer_int_enable(AM_HAL_STIMER_INT_COMPAREG); //Enable C/T G=6

  //Use the lower power 32kHz clock. Use it to run CT6 as well.
  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_STIMER_CFG_COMPARE_G_ENABLE);

  //Setup interrupt to trigger when the number of ms have elapsed
  am_hal_stimer_compare_delta_set(6, 32768); // Sleep for 32768 clock ticks = 1 second at 32768Hz

  //Power down cache, flash, SRAM
  am_hal_pwrctrl_memory_deepsleep_powerdown(AM_HAL_PWRCTRL_MEM_ALL); // Power down all flash and cache
  am_hal_pwrctrl_memory_deepsleep_retain(AM_HAL_PWRCTRL_MEM_SRAM_384K); // Retain all SRAM

  //Enable the timer interrupt in the NVIC.
  NVIC_EnableIRQ(STIMER_CMPR6_IRQn);

  //Deep Sleep
  am_hal_sysctrl_sleep(AM_HAL_SYSCTRL_SLEEP_DEEP);

  //Turn off interrupt
  NVIC_DisableIRQ(STIMER_CMPR6_IRQn);
  am_hal_stimer_int_disable(AM_HAL_STIMER_INT_COMPAREG); //Disable C/T G=6

  // Power up SRAM, turn on entire Flash
  am_hal_pwrctrl_memory_deepsleep_powerdown(AM_HAL_PWRCTRL_MEM_MAX);

  //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);

  //We need to re-enable the TX and RX pins manually. Serial.begin does not do it for us...
  
// If you comment the next four lines, the code stops working on v2.1 of the core:
  am_hal_gpio_pincfg_t txPinCfg = g_AM_BSP_GPIO_COM_UART_TX;
  pin_config(PinName(48), txPinCfg);    
  am_hal_gpio_pincfg_t rxPinCfg = g_AM_BSP_GPIO_COM_UART_RX;
  pin_config(PinName(49), rxPinCfg);    

  //Restart Serial
  Serial.begin(115200);
  Serial.println();
  Serial.print(F("Micros: "));
  Serial.println(micros());
  Serial.flush();
}

Here is the Serial output:

image

Note that micros does not behave well after waking from SLEEP_DEEP.
The reverse question marks probably are expected - caused by turning the pin off and on again, generating a spurious start bit.

If you comment the four lines which re-enable the TX and RX pins, the code stops working on v2.1:

// If you comment the next four lines, the code stops working on v2.1 of the core:
//  am_hal_gpio_pincfg_t txPinCfg = g_AM_BSP_GPIO_COM_UART_TX;
//  pin_config(PinName(48), txPinCfg);    
//  am_hal_gpio_pincfg_t rxPinCfg = g_AM_BSP_GPIO_COM_UART_RX;
//  pin_config(PinName(49), rxPinCfg);    

But if you switch to v1.2.1 of the core, the code does work with those same four lines commented. I guess Serial.begin must be re-initializing the pins for us? Note micros is better behaved too...

image

Cheers,
Paul

@paulvha
Copy link
Contributor

paulvha commented Jul 6, 2021

Hi

Check the post on Fri Feb 26, 2021 1:27 pm in https://forum.sparkfun.com/viewtopic.php?f=169&t=55163.

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.

example was included.

regards,
Paul

@PaulZC
Copy link
Contributor Author

PaulZC commented Jul 6, 2021

Nice one Paul - thank you - I'd missed that discussion.
Very best wishes,
Paul (ZC)

@PaulZC
Copy link
Contributor Author

PaulZC commented Jul 6, 2021

Hi Paul (@paulvha ),
I suspect this could also be the root cause of #412 (disabling the Wire IOM) too?
Do you know if there is a way to manually delete the handle to Serial or Wire - or some other way of marking the handle as 'stale' and so forcing MBED to re-initialize the hardware completely with the next .begin?
Thank you,
Paul

@paulvha
Copy link
Contributor

paulvha commented Jul 6, 2021

with respect to serial.

Calling Serial.end(); will lead to Hardwareserial.cpp. However, this function is currently empty and does nothing.
One could/should add in this function : mbed::UnbufferedSerial::_deinit().
This will lead to drivers/SerialBase.cpp, where it will call serial_free().
Serial_free() in serial_api.c (part of the device folder in the apollo3 target) is currently empty. This should be changed to reset the serial in Apollo3-chip, close power and release the handle. The next Serial.begin() will now re-init the Serial completely and correctly.

I wrote the feedback based on V 2.0 , now looking at the code (V2.10), it seems the RX and TX pins are set, whether there is a handle or not, but it will not restore the power, reset buffer pointers etc etc.

Need to look to Wire/IOM..

regards,
Paul

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants