I am having problem with RTC alarm interrupt of STM32L151. I want my program to go to RTC alarm interrupt every second but it does not work.
My main funtion:
int main(void)
{
HAL_Init();
SystemClock_Config();
MX_GPIO_Init();
MX_IWDG_Init();
MX_RTC_Init();
MX_SPI1_Init();
MX_USART1_UART_Init();
__HAL_RTC_ALARM_ENABLE_IT(&hrtc, RTC_IT_ALRA);
while (1)
{
}
}
Function configures RTC: MX_RTC_Init():
void MX_RTC_Init(void)
{
RTC_TimeTypeDef sTime;
RTC_DateTypeDef sDate;
RTC_AlarmTypeDef sAlarm;
hrtc.Instance = RTC;
hrtc.Init.HourFormat = RTC_HOURFORMAT_24;
hrtc.Init.AsynchPrediv = 127;
hrtc.Init.SynchPrediv = 255;
hrtc.Init.OutPut = RTC_OUTPUT_DISABLE;
hrtc.Init.OutPutPolarity = RTC_OUTPUT_POLARITY_HIGH;
hrtc.Init.OutPutType = RTC_OUTPUT_TYPE_OPENDRAIN;
HAL_RTC_Init(&hrtc);
sTime.Hours = 0x14;
sTime.Minutes = 0;
sTime.Seconds = 0;
sTime.TimeFormat = RTC_HOURFORMAT12_AM;
sTime.DayLightSaving = RTC_DAYLIGHTSAVING_NONE;
sTime.StoreOperation = RTC_STOREOPERATION_RESET;
HAL_RTC_SetTime(&hrtc, &sTime, FORMAT_BCD);
sDate.WeekDay = RTC_WEEKDAY_WEDNESDAY;
sDate.Month = RTC_MONTH_AUGUST;
sDate.Date = 0x24;
sDate.Year = 0x16;
HAL_RTC_SetDate(&hrtc, &sDate, FORMAT_BCD);
/**Enable the Alarm A
*/
sAlarm.AlarmTime.Hours = 0;
sAlarm.AlarmTime.Minutes = 0;
sAlarm.AlarmTime.Seconds = 0;
sAlarm.AlarmTime.TimeFormat = RTC_HOURFORMAT12_AM;
sAlarm.AlarmTime.DayLightSaving = RTC_DAYLIGHTSAVING_NONE;
sAlarm.AlarmTime.StoreOperation = RTC_STOREOPERATION_RESET;
sAlarm.AlarmMask = RTC_ALARMMASK_SECONDS;
sAlarm.AlarmDateWeekDaySel = RTC_ALARMDATEWEEKDAYSEL_DATE;
sAlarm.AlarmDateWeekDay = 1;
sAlarm.Alarm = RTC_ALARM_A;
HAL_RTC_SetAlarm_IT(&hrtc, &sAlarm, FORMAT_BCD);
}
I created project using CubeMX. Do you have any idea or advice for me? Thank you
If a field is masked, then that won't be compared when checking alarm date. So when you mask SECONDS, then only the DAY, HOUR and MINUTE fields will be compared.
The proper way of achieving 1 second interrupts with RTC is to use all alarm mask because this way none of the fields are compared and when the RTC increments the SECOND field an alarm interrupt will be generated.
sAlarm.AlarmMask = RTC_ALARMMASK_ALL;
Also all of this are described by ST in their Using the hardware real-time clock (RTC) in STM32 F0, F2, F3, F4 and L1 series of MCUs application note.
This is a very convenient solution as you do not have to reset the alarm after all interrupts.
As you have set sAlarm.AlarmMask = RTC_ALARMMASK_SECONDS, the RTC will generate an interrupt when the seconds value of the time will match sAlarm.AlarmTime.Seconds which is 0 in your case. So you will have an interrupt every minute here if you leave the code as it is.
If you want an interrupt every second, you will have to set the alarm again with the next second in your interrupt handler. The code in your interrupt handler would look like:
void HAL_RTC_AlarmAEventCallback(RTC_HandleTypeDef *hrtc)
{
RTC_TimeTypeDef sTime;
HAL_RTC_GetTime(&hrtc, &sTime, RTC_FORMAT_BIN);
uint8_t next_second = sTime.Seconds++;
if (next_second > 59) next_second = 0;
RTC_AlarmTypeDef sAlarm;
sAlarm.AlarmTime.Hours = 0;
sAlarm.AlarmTime.Minutes = 0;
sAlarm.AlarmTime.Seconds = RTC_ByteToBcd2(next_second);
sAlarm.AlarmTime.TimeFormat = RTC_HOURFORMAT12_AM;
sAlarm.AlarmTime.DayLightSaving = RTC_DAYLIGHTSAVING_NONE;
sAlarm.AlarmTime.StoreOperation = RTC_STOREOPERATION_RESET;
sAlarm.AlarmMask = RTC_ALARMMASK_SECONDS;
sAlarm.AlarmDateWeekDaySel = RTC_ALARMDATEWEEKDAYSEL_DATE;
sAlarm.AlarmDateWeekDay = 1;
sAlarm.Alarm = RTC_ALARM_A;
HAL_RTC_SetAlarm_IT(&hrtc, &sAlarm, FORMAT_BCD);
}
For this to work, you have to make sure that you have set up properly the RTC clock (internal or external 32K).
Alternatively you could use the wake up function of the RTC, it would be more appropriate I think.
Or in your main loop, you could use the HAL_GetTick to check that 1 second has elapsed since your last processing, like this:
static uint32_t last_second = 0;
void main(void)
{
uint32_t current_second = HAL_GetTick();
if (current_second - last_second > 1000)
{
last_second = current_second;
//1 second has elapsed, do something
}
}
Don't call __HAL_RTC_ALARM_ENABLE_IT() directly. It's called by HAL_RTC_SetAlarm_IT().
Enable Alarm B. Why? Because sometimes, as I've experienced, one alarm won't work. You "sometimes" have to enable both alarms.
For masking, you have to mask all bits:
sAlarm.AlarmMask = RTC_ALARMMASK_DATEWEEKDAY|RTC_ALARMMASK_HOURS|RTC_ALARMMASK_MINUTES|RTC_ALARMMASK_SECONDS;
This way, you ask ST to just use seconds. You can also use RTC_ALARMMASK_ALL.
Related
I am writing some Arduino code that is meant to control my 3D printed robot at a basic level. Everything works fine until the value that I analogWrite() to ledPin (pin 11 on the Nano) is no longer 0. The purpose of this bit of code is to fade some leds ON/OFF based on ambient lighting without using delay() function that pauses the program.
The code here determines whether the ambient light is below threshold, wheter 4 milliseconds have passed and whether the LEDs are at their target brightness yet, then increments/decrements the value to analogWrite() accordingly. It's when this value (lightVal) increases that the whole program freezes and remains in the state it was just before freezing. (The robot becomes unresponsive and serial data stops getting sent.) The moment I comment out the analogWrite(), the freeze does not occur.
timer = millis();
aLightVal = analogRead(LDR);
aLightVal = map(aLightVal, 0, 600, 0, 100);
//Check to see if the ambient light is below threshold
//If LED is not yet at target brightness, fade every 4 milliseconds
if (aLightVal < 40){
if (timer - currentTime > 4){
if (lightVal < 255){
lightVal++;
currentTime = timer;
}
}
}
if (aLightVal >= 40){
if (timer - currentTime > 4){
if (lightVal > 0){
lightVal--;
currentTime = timer;
}
}
}
analogWrite(ledPin, lightVal);
Serial.println(aLightVal);
I am using the Servo.h as well as the Ultrasonic.h libraries in the program if that helps?
I initialised the variables as follows:
const int LDR = A1;
const int ledPin = 11;
unsigned long timer = 0;
unsigned long currentTime = 0;
int aLightVal;
int lightVal = 0;
Any advice? Please let me know, I would really appreciate it!
I am currently developing a program where Raspberry Pi 3 will read contents sent by 4 Arduino (USB) devices through serial communication every 100ms. The UI gets stuck on the fourth call (serialDeviceIndex = 3) of Concurrency::create_task but if there are only 3 Arduino devices, the problem is not happening and the thread execution continues to the .then lambda body. Can you help me pin point what is the problem? Here's the function called when the connect button from the xaml devices is pressed.
void MainPage::comPortInput_Click(Object^ sender, RoutedEventArgs^ e)
{
m_timer->Start();
auto selectionIndex = ConnectDevices->SelectedIndex;
if (selectionIndex < 0)
{
status->Text = "Select a device and connect";
return;
}
auto selectedItems = ConnectDevices->SelectedItems;
for (unsigned serialDeviceIndex = 0; serialDeviceIndex < selectedItems->Size; serialDeviceIndex++)
{
Device ^device = static_cast<Device ^>(selectedItems->GetAt(serialDeviceIndex));
textBox->Text = textBox->Text + "\n<START>:" + device->Id->ToString() + "<END>";
Windows::Devices::SerialCommunication::SerialDevice ^serial_device;
Windows::Devices::Enumeration::DeviceInformation ^entry = device->DeviceInfo;
auto childTokenSource = Concurrency::cancellation_token_source::create_linked_source(cancellationTokenSource->get_token());
auto childToken = childTokenSource.get_token();
Concurrency::create_task(
Windows::Devices::SerialCommunication::SerialDevice::FromIdAsync(entry->Id), childToken)
.then([this, serialDeviceIndex](Windows::Devices::SerialCommunication::SerialDevice ^serial_device)
{
_serialPort = serial_device;
Platform::String ^deviceString1 = _serialPort->ToString();
// Disable the 'Connect' button
//comPortInput->IsEnabled = false;
Windows::Foundation::TimeSpan _timeOut;
_timeOut.Duration = 100000L; //100000 works with delay(200)
// Configure serial settings
_serialPort->WriteTimeout = _timeOut;
_serialPort->ReadTimeout = _timeOut;
_serialPort->BaudRate = 9600;
_serialPort->Parity = Windows::Devices::SerialCommunication::SerialParity::None;
_serialPort->StopBits = Windows::Devices::SerialCommunication::SerialStopBitCount::One;
_serialPort->DataBits = 8;
_serialPort->Handshake = Windows::Devices::SerialCommunication::SerialHandshake::None;
_dataReaderObject = ref new Windows::Storage::Streams::DataReader(_serialPort->InputStream);
_dataReaderObject->InputStreamOptions = Windows::Storage::Streams::InputStreamOptions::Partial;
_dataReaderObjects.Append(_dataReaderObject);
_serialPorts.Append(_serialPort);
int serialPortsSize = _serialPorts.Size;
Listen(_serialPorts.GetAt(serialDeviceIndex), _dataReaderObject, serialDeviceIndex);
});
Sleep(5);
}
}
EDIT:
Okay, I simplified now the code to JUST this one
for (unsigned serialDeviceIndex = 0; serialDeviceIndex < selectedItems->Size; serialDeviceIndex++){
Device ^device = static_cast<Device ^>(selectedItems->GetAt(serialDeviceIndex));
textBox->Text = textBox->Text + "\n<START>:" + device->Id->ToString() + "<END>";
Windows::Devices::Enumeration::DeviceInformation ^entry = device->DeviceInfo;
auto it = Concurrency::create_task(Windows::Devices::SerialCommunication::SerialDevice::FromIdAsync(entry->Id));
while (!it.is_done())
textBoxStatus->Text = "processing" + deviceIndex.ToString();
it.get();
}
FYI, this code runs normally fine in my pc. no errors. When I try to run this in my RaspberryPi3 under Windows IoT the program hungs up at the fourth time I try to get the device using it.get()
OK, so i have accomplished creating a software and hardware UART on PIC18f8680 in MikroC compiler. The Soft_Uart uses timer0 for interrupt and breaks the Soft_UART_read() line by a function called Soft_uart_Break().
everything is working fine, when i read a single character from both uart. but when i send a string on hardware uart, the string doesn't gets reads properly by these lines;
UART1_Read_Text(buffer, "OK", 100);
UART1_Write_Text(buffer);
I've found out whats causing this problem. that is, my main while loop gets stuck in Soft_UART_read() until it gets break by an interrupt. while its stuck over there, the hardware uart doesn't gets proper time to read the whole string, so as a result it displays some of the characters of that string.
how can i overcome this ? do i need to use a separate interrupt for hardware uart aswel ? or what ? any help would be highly appreciated.
here is a snip of my code;
void main() {
INTCON.GIE=1; //globle interrupt enable
INTCON.PEIE=1; //peripharel interrupt enable
INTCON.TMR0IF = 0x0; //Clear timer0 overflow interrupt flag
INTCON.TMR0IE = 1; //enable the timer0 by setting TRM0IE flag
T0CON.TMR0ON = 1; // Timer0 On/Off Control bit: 1=Enables Timer0 / 0=Stops Timer0
T0CON.T08BIT = 0; // Timer0 8-bit/16-bit Control bit: 1=8-bit timer/counter / 0=16-bit timer/counter
T0CON.T0CS = 0; // TMR0 Clock Source Select bit: 0=Internal Clock (CLKO) / 1=Transition on T0CKI pin
T0CON.T0SE = 0; // TMR0 Source Edge Select bit: 0=low/high / 1=high/low
T0CON.PSA = 1; // Prescaler Assignment bit: 0=Prescaler is assigned; 1=NOT assigned/bypassed
T0CON.T0PS2 = 0; // bits 2-0 PS2:PS0: Prescaler Select bits
T0CON.T0PS1 = 1;
T0CON.T0PS0 = 1;
TMR0H = 0xBD; // preset for Timer0 MSB register
TMR0L = 0xCD; // preset for Timer0 LSB register
while(1) {
data1 = Soft_UART_Read(&error);
Soft_UART_Write(data1);
if (data1 == 'b') {
for(x = 0; x <= strlen(alive); x++) {
Soft_UART_Write(alive[x]);
}
}
if (UART1_Data_Ready()) { // If data is received,
UART1_Read_Text(buffer, "OK", 100); // reads text until 'OK' is found
UART1_Write_Text(buffer); // sends back text
/*if (uart_rd == 'a') {
UART1_Write_Text("\rSensor 1 data\r");
}*/
//else
//UART1_Write(uart_rd); // and send data via UART
}
}
}
I had the same issue. Some of the example code and documentation in the MikroC manual seems to contradict itself.
The prototype is:
void UARTx_Read_Text(char *Output, char *Delimiter, char Attempts);
Your delimiter should be:
char delimit[] = "OK";
UART1_Read_Text(&dataIn,&delimit,attempts);
If you know the size of the data being received attempts should correspond to this.
Using RTC_B
XIN is connected to a 32.768 kHz clock source (not oscillator)
XIN Bypass is used since no oscillator
Init code is as follows:
//Calendar mode, BCD coded, stop rtc, hourly interrupt
RTCCTL01 = RTCTEV_0 + RTCHOLD;
//no calibration
RTCCTL23 = 0;
//prescale setup
RTCPS0CTL = 0; // disable PS0 interrupts
//clear calendar
RTCHOUR = 0;
RTCMIN = 0;
RTCSEC = 0;
RTCDAY = 0;
RTCMON = 0;
RTCYEAR = 0;
//enable RTC
RTCCTL01 &= ~RTCHOLD;
After this I wait for the RTCRDY bit to get set but it never does
while( !(RTCCTL01 & RTCRDY) );
Note that the clock is being configured as follows:
// Enable XT1(32.768kHz) and XT2(4MHz) clock ports
XT1_XT2_PORT_SEL |= (XT1_ENABLE + XT2_ENABLE);
XT1_Bypass();
ret = SetVCore(3); // Set Vcore to accommodate for max. allowed
LFXT_Start(XT1DRIVE_3); // Enable XT1 and maximize drive strength
//! \note The system clock is derived from the internal reference clock,
//! which is set to 32768.
Init_FLL_Settle(MCLK_TICKPERSEC/1000, MCLK_TICKPERSEC/32768);
LFXT_Start() disables bypass mode and enables the oscillator.
I am new to Arduino programming and trying to use the arduino uno as a high resolution timer. I would like to be able to count clock cycles at the full 16MHz rate between two rising edge interrupts. I have some code that is functional using the micros() function which has 4 microsecond resolution, and I need better than that. Here is an example code where I am trying to use micros() for the timing:
volatile int k = 0;
volatile float t1 = 0;
volatile float t2 = 0;
void setup() {
// put your setup code here, to run once:
Serial.begin(9600);
attachInterrupt(digitalPinToInterrupt(2), ISR1, RISING);
attachInterrupt(digitalPinToInterrupt(3), ISR2, RISING);
}
void ISR2()
{
k = 1;
t1 = micros();
Serial.println(1);
}
void ISR1()
{
k = 2;
t2 = micros();
Serial.println(2);
}
void loop()
{
if (t1 != 0 && t2 != 0) {
if (t2 - t1 < 0) {
t1 = 0;
t2 = 0;
}
else {
Serial.print("tdelta ");
Serial.print(t2 - t1);
t1 = 0;
t2 = 0;
Serial.println(0);
}
}
}
I realize that my micros timing is probably getting a bit offset by the interrupts, which may be an issue.
Can anyone point me in the right direction?
I think I want to use timer1 since it is 16 bit and my events should be fast enough to be completed before any overflow occurs. I am hoping to find a simple way to set up tcnt1 to be 0 with the first interrupt and then count tcnt1 clock cycles until the second interrupt. I don't really even know how to read the values from tcnt1 though, so I have a ways to go.
I have searched for examples, but haven't really found one that seems appropriate. Everything seems to be geared towards timer interrupts which I don't think is quite what I'm after.
I am probably lacking a lot of needed understanding to use this tcnt1 counter, but any help to point me in the right direction would be greatly appreciated!
Thanks
You can try to work with timer registers directly. Look at manual for CPU which is used on your particular board. For mega it is ATmega2560-16AU. Timer register's name is TCNT1. You can store its value:
int t1;// declare global variable somewhere
t1 = TCNT1; //save timer value in ISRx interrupts
Be sure to setup prescaler value TCCR1B.CSn and handle timer overflow interrupt, else you will lose time data: ISR(TIMER1_OVF_vect)
As you can read here here precision of <1 uS can be reached.
More info of how to work directly with CPU timers registers.