Hi to restart the device without resetting RTC clock. For example, when I run:
import machine
print(str(time.localtime()))
# Set the datetime
machine.RTC().datetime((...))
print(str(time.localtime()))
machine.reset()
print(str(time.localtime()))
Outputs like this
(2000, 1, 1, 0, 2, 4, 5, 1)
(2052, 11, 10, 10, 26, 45, 6, 315)
# Resets
(2000, 1, 1, 0, 2, 4, 5, 1)
I would like reset everything but the RTC time
ESP32 internal RTC do not preserved the settings with hard reset, ESP32 RTC time however is preserved during deep sleep.
If you want to "preserved" the RTC time:
use an external RTC module;
use an external GPS module (requires to be outdoor);
call an NTP service to set the time after reset;
don't unplug it or don't reset it, put it in deep sleep mode.
You can't. The RTC is a hardware device, and it's not reset when you reset the microcontroller. You can only reset the RTC by removing the battery or by using the reset pin on the RTC chip.
But if you still want to preserve the RTC, you can use the RTC memory to store the current time, and then restore it after the reset. For example:
import machine
import time
# Save the current time in RTC memory
rtc = machine.RTC()
rtc.memory(str(time.localtime()))
# Set the datetime
rtc.datetime((...))
# Reset the device
machine.reset()
# Restore the time from RTC memory
rtc = machine.RTC()
time.localtime(eval(rtc.memory()))
print(str(time.localtime()))
The eval() function is used to evaluate a string as a Python expression. It's not safe to use eval() with untrusted input, but in this case it's safe because the string is generated by the program itself.
Note that the RTC memory is volatile, so it will be lost if the battery is removed or if the device is powered off. You can use the RTC memory to store other data, but you should use a non-volatile storage like a file or a database to store data that you want to preserve.
Related
I need to read temperature data with using MAX31865 SPI communication. First of all, I tried to read 4 byte data:
import machine
import ubinascii
spi = machine.SPI(1, baudrate=5000000, polarity=0, phase=0)
#baudrate controls the speed of the clock line in hertz.
#polarity controls the polarity of the clock line, i.e. if it's idle at a low or high level.
#phase controls the phase of the clock line, i.e. when data is read and written during a clock cycle
cs = machine.Pin(15, machine.Pin.OUT)
cs.off()
cs.on()
data = spi.read(4)
cs.off()
print(ubinascii.hexlify(data))
I tried many times with different codes but result is always similar b'00000000'.
I am using ESP32 WROOM.
I used this pins:
ESP32 : D12 - D14 - 3V3 - GND - D15
Max31865: SDO - CLK - VIN - GND - CS
I am new on micropython and esp32.
I don't know what should I do. Is there any suggestions , recommended tutorials or idea?
Short answer: see if you can use CircuitPython and its drivers for MAX31865.
Long answer: a bunch of stuff. I suspect you've been following the Adafruit tutorial for MAX31855, but its SPI interface is very different from the MAX31865.
Your SPI connection is missing the SDI pin. You have to connect it, as communication is bidirectional. Also, I suggest using the default SPI pinout on ESP32 side as described in the micropython documetation for ESP32.
The SPI startup looks to be missing stuff. Looking at the SPI documentation a call to machine.SPI() requires that you assign values to arguments sck, mosi, miso. Those would probably be the pins on ESP32 side where you've connected SCLK, SDI, SDO on MAX31865 (note mosi means "master out, slave in" and miso is "master in, slave out").
The chip select signal on the MAX is inverted (that's what the line above CS input in the datasheet means). You have to set it low to activate the chip and high to disable it.
You can't just read data out of the chip, it has a protocol you must follow. First you have to request a temperature-to-resistance conversion from the chip. The datasheet for your chip explains how to do that, the relevant info starts on page 13 (it's a bit difficult to read for a beginner, but try anyway as it's the authoritative source of information for this chip). On a high level, it works like this:
Write to Configuration register a value which initiates the conversion.
Wait for the conversion to complete.
Read from the RTD (Resistance-To-Digital) registers to get the conversion result.
Calculate the temperature value from the conversion result.
The code might be closer to this (not tested, and very likely to not work off the bat - but it should convey the idea):
import ubinascii, time
from machine import Pin, SPI
cs = Pin(15, Pin.OUT)
# Assuming you've rewired according to default SPI pinout
spi = machine.SPI(1, baudrate=100000, polarity=0, phase=0, sck=Pin(14), mosi=Pin(13), miso=Pin(12))
# Enable chip
cs.off()
# Prime a 1-shot read by writing 0x40 to Configration register 0x00
spi.write(b'\x00\x40')
# Wait for conversion to complete (up to 66 ms)
time.sleep_ms(100)
# Select the RTD MSBs register (0x01) and read 1 byte from it
spi.write(b'\x01')
msb = spi.read(1)
# Select the RTD LSBs register (0x02) and read 1 byte from it
spi.write(b'\x02')
lsb = spi.read(1)
# Disable chip
cs.on()
# Join the 2 bytes
result = msb * 256 + lsb
print(ubinascii.hexlify(result))
Convert result to temperature according to section "Converting RTD Data Register
Values to Temperature" in datasheet.
Side note 1: here spi = machine.SPI(1, baudrate=5000000, polarity=0, phase=0) you've configured a baud rate of 5MHz which is the maximum for this chip. Depending on how you've connected your devices, it may not work. The SPI protocol is synchronous and driven by master device, so you can set any baud rate you want. Start with a much, much lower value, maybe 100KHz or so. Increase this after you've figured out how to talk to the chip.
Side note 2: if you want your conversion result faster than the 100ms sleep in my code, connect the DRDY line from MAX to ESP32 and wait for it to go low. This means the conversion is finished and you can read out the result immediately.
I am writing a bare-metal kernel, but an interrupt doesn't seem to be triggered when the EMMC INTERRUPT register becomes non-zero.
I have two cores idling, and one at EL3 with no data caches enabled continually displaying a page of memory, in order to see what the code I'm testing is up to. (The test code regularly flushes its cache, on the working QA7 millisecond interrupt.)
The code being tested is running at Secure EL0 on core 0, with interrupts enabled. Interrupts are routed to core 0:
QA7.GPU_interrupts_routing = 0; // IRQ and FIQ to Core 0
The EMMC interface is initialised, and a reset command sent to the card, at which point the INTERRUPT register becomes 1 (bit 0 set: command has finished), but no GPU interrupt seems to be signalled to the QA7 hardware (bit 8 in the Core 0 interrupt source register stays zero).
The EMMC registers IRPT_MASK and IRPT_EN are both set to 0x017f7137, which I think should enable all known interrupts from that peripheral, and certainly bit 0.
The BCM8235 interrupt registers have been written as so:
Enable_IRQs_1 = 0x20000000; // (1 << 29);
Enable_IRQs_2 = 0x02ff6800; // 0b00000010111111110110100000000000;
Enable_Basic_IRQs = 0x303;
But they read back as:
Enable_IRQs_1: 0x20000200 // (1 << 9) also set
Enable_IRQs_2: 0x02ff6800 // unchanged
Enable_Basic_IRQs: 0x3 // No interrupts from IRQs 1 or 2.
What have I missed?
(Tagged raspberry-pi2, since it also has the QA7 component.)
The simple answer is nothing more. The Arasan SD interface interrupt is number 62, bit 20 in the IRQ basic pending register. Enable bit 30 in IRQ pending 2, and the interrupt comes through.
Enable_IRQs_2 = 0x42ff6800;
I just had to ignore the advice: "The table above has many empty entries. These should not be enabled as they will interfere with the GPU operation." in the documentation.
I'm in a strange situation with an ATMega2560.
I want to save power by going into PowerDown mode. In this mode there are only a few events only which can wake it up.
On USART1 I have an external controller which sends messages to the AVR.
But when USART1 is used I can not use the INT2 and INT3 for external interrupt (=the CPU will not wake up).
So I had an idea to disable the USART1 just right before going into PowerDown mode, and have the INT2 enabled as external interrupt.
Pseudo code for this:
UCSR1B &= ~(1<<RXEN1); //Disable RXEN1: let AVR releasing it
DDRD &= ~(1<<PD2); //Make sure PortD2 is an input - we need it for waking up
EIMSK &= ~(1<<INT2); //Disable INT2 - this needs to be done before changing ISC20 and ISC221
EICRA |= (1<<ISC20)|(1<<ISC21); //Rising edge on PortD2 will generate an interrupt and wake up the AVR from PowerDown
EIMSK |= (1<<INT2); //Now enable INT2
//Sleep routine
cli();
sleep_enable();
sei();
sleep_cpu();
sleep_disable();
In the ISR of INT2, I change everything back to USART1.
Pseudo:
ISR(INT2_vect) {
EIMSK &= ~(1<<INT2); //Disable INT2 to be able to use it as USART1 again
UCSR1B=(1<<RXEN1)|(1<<TXEN1)|(1<<RXCIE1);
}
However it seems to take long time until the USART1 is working correctly again.
There are too many faulty bits in the beginning (after waking up from PowerDown).
How hackish is this?
Is there any reasonable way to make the change faster?
The main idea was to set the 'RX' port to an interrupt which can wake the CPU up then immediately change it back to USART and process it asap.
PS: I really have to use the same pin for this purpose, there is no other available option. So guiding toward using some other pins won't be accepted as an answer.
The Power-down mode disables the oscillator, so you have to wait for a stable oscillator after wakeup.
Please take a look at the datasheet on page 51:
When waking up from Power-down mode, there is a delay from the wake-up condition occurs until the wake-upbecomes effective. This allows the clock to restart and become stable after having been stopped. The wake-upperiod is defined by the same CKSEL Fuses that define the Reset Time-out period, as described in “ClockSources” on page 40.
You have to wait up to 258 clock cykles assuming you use a high speed ceramic oscillator (see table 10-4 on page 42).
You can use the Standby Mode. If you use an external oscillator the CPU enter the Standby Mode, which is identical to Power-down Mode, but the Oscillator isn´t stopped. Furthermore you can set the Power Reduction Register for additional power save options.
Another option is to use the Extended Standby Mode, which is identical to the Power-save Mode. This mode disables the oscillator, but the oscillator wakes up in six clock cycles.
I am using a PCA9544 GPIO expander in embedded Linux. The driver is installed and controlling GPIO as expected. However, I would like to read the values of the INTn lines through the control register using sysfs. Is there a file associated with the control register?
If you export single GPIOs, you can wait for its interrupt on per GPIO basis. Take a look at libsoc project. It handles sysfs calls for you. Look at libsoc_gpio_wait_interrupt and libsoc_gpio_callback_interrupt routines. All you have to do it to activate required GPIOs, configure them as input and specify trigger edge (see options below), after this you can use interrupt routines. I've also an i2c based GPIO expander and it works.
typedef enum {
EDGE_ERROR = -1,
RISING = 0,
FALLING = 1,
NONE = 2,
BOTH = 3,
} gpio_edge;
I'm currently working with a USB-enabled low power device that I'm having a bit of trouble with. During normal operation, the system clock is set to a significantly slower speed (since this is a data logger only active once every few minutes, this isn't a problem). However, when the device is then plugged into a USB port on a computer, it needs to recognize this, initialize the USB stack (which I can do), and reset the system clock to full speed (I can do this, as well).
My problem, as you might have noticed, is the "USB Connected" event. I'm looking through the STM32 evaluation materials and they have in the IRQn table a "USB_FS_WKUP_IRQn", and the STM32 eval board also has USB-5V power routed to pin PE6, which can also act as WKUP3.
Do I need to enable an external interrupt for that pin, or is there a better way to detect such an event and set/reset the clocks as needed?
Thanks in advance.
Basing on the interrupt name you mentioned I found this implementation:
// Enable the USB Wake-up interrupt
NVICInit.NVIC_IRQChannel = USB_FS_WKUP_IRQn;
NVICInit.NVIC_IRQChannelPreemptionPriority = 1;
NVIC_Init(&NVICInit);
It seems you don't need much more. The implementation can differ from the STM32 family you use.
I use the stm32l4
I set up an interrupt on the Vbus pin.
While not in USB mode, configure the pin as a pull-down (so it isn't floating).
Your pin and interrupt line would be different, but
//Configure the pin
GPIO_InitTypeDef GPIO_InitStruct = {0};
__HAL_RCC_GPIOA_CLK_ENABLE();
/*Configure GPIO pin : PA9 */
GPIO_InitStruct.Pin = VBUS_Pin;
GPIO_InitStruct.Mode = GPIO_MODE_IT_RISING;
GPIO_InitStruct.Pull = GPIO_PULLDOWN;
HAL_GPIO_Init(VBUS_GPIO_Port, &GPIO_InitStruct);
/* EXTI interrupt init*/
HAL_NVIC_SetPriority(EXTI9_5_IRQn, 0, 0);
HAL_NVIC_EnableIRQ(EXTI9_5_IRQn);
//Configure the interrupt
EXTI_ConfigTypeDef exti_conf;
exti_conf.Line = EXTI_LINE_9;
exti_conf.GPIOSel = EXTI_GPIOA;
exti_conf.Mode = EXTI_MODE_INTERRUPT;
exti_conf.Trigger = EXTI_TRIGGER_RISING;
HAL_EXTI_SetConfigLine(&hexti_vbus, &exti_conf);
And make sure you have an interrupt handler taken care of. Set a flag for going to USB in the interrupt handler. And you should be set.