Hi All,
I could port the code for LoRa Mac Node onto EFM32PG custom board with SX1276/RFM95 changeable module. The LoRa radio module goes on socket, SX1276 is 915Mhz and RFM95 is 868Mhz versions.
I am using RFM95 868Mhz with ABP for now and it does transmit and I can see the uplink message under my Laird geateway on TTN, but that happens only one time when the powered up. I have a few questions:
- In the board.c file, under BoardInitMCU() there is a function call CalibrateSystemWakeupTime( ).How important is this? I tried to single step through this in dubug mode, it does start a timer, but it does not generate OnCalibrateSystemWakeupTimeTimerEvent, and after 5 tries it sends RTC into low power mode and does not wakeup. But when I comment out the CalibrateSystemWakeupTime(), the code goes further and works good and transmits the message.
2.Further I need to transmit the message every 15sec, where can I set up this?
Thank you in advance!
Silas
your board does not need to calibrate with CalibrateSystemWakeupTime(), this function is for STM32 only.
can you show your implementation code for EFM32PG?
1 Like
Hi Nestorayuso
Thanks for clarification on CalibrateSystemWakeupTime()
here is my code in Board.c
void BoardInit(void)
{
BoardInitEMU();
BoardInitCMU();
BoardInitHFXO();
BoardInitLFXO();
BoardInitHWPins();
}
void BoardInitMcu( void )
{
BoardInit();
BoardInitPeriph();
if( McuInitialized == false )
{
RtcInit();
}
SpiInitRadio( &SX1276.Spi );
SX1276IoInit();
if( McuInitialized == false )
{
McuInitialized = true;
if( GetBoardPowerSource( ) == BATTERY_POWER )
{
CalibrateSystemWakeupTime( );
}
}
}
The BoardInit() initializes EMU, CMU, HFXO, LFXO and HWPins and then initializes the Peripherals. Then RTC is initilzed. The following is the RTCInit code
void RtcInit( void )
{
if( RtcInitalized == false )
{
// Reset overflow counter
rtcOverflowCounter = 0;
// Calculate overflow interval based on RTC counter width and frequency
rtcOverflowInterval = ((0x00FFFFFF+1) / RTC_TICKS_PER_MS);
rtcOverflowIntervalR = ((0x00FFFFFF+1) - (rtcOverflowInterval * RTC_TICKS_PER_MS)); // remainder
RtcInitalized = true;
rtcFreq = CMU_ClockFreqGet(cmuClock_RTCC);
RTCC_Init_TypeDef rtccInit = RTCC_INIT_DEFAULT;
RTCC_CCChConf_TypeDef rtccInitCompareChannel = RTCC_CH_INIT_COMPARE_DEFAULT;
rtccInit.cntWrapOnCCV1 = true; /* Clear counter on compare match */
rtccInit.presc = rtccCntPresc_1;
/* Setting the compare value of the RTCC */
//RTCC_ChannelInit(1, &rtccInitCompareChannel);
//RTCC_ChannelCCVSet(1, RTC_COUNT_BETWEEN_WAKEUP);
// Disable all rtc interrupts
RTCC_IntDisable(RTCC_IEN_OF | RTCC_IEN_CC1);
RTCC_IntClear(RTCC_IFC_OF | RTCC_IFC_CC1);
//RTCC_CounterReset();
// Enable interrupt on overflow
RTCC_IntEnable(RTCC_IF_OF);
// Enable interrupts
NVIC_SetPriority(RTCC_IRQn, 4);
NVIC_ClearPendingIRQ(RTCC_IRQn);
NVIC_EnableIRQ(RTCC_IRQn);
// Enable RTC
RTCC_Enable(true);
}
}
Thanks
Silas
1 Like
Ok, I fouind the following defines:
#define APP_TX_DUTYCYCLE 15000 // Milliseconds between two transmissions
#define APP_TX_DUTYCYCLE_RND 1000 // Random delay for application data transmission duty cycle [ms]
#define APP_DEFAULT_DATARATE DR_5 // SF7 - BW125
#define APP_PORT 2 // Application port
#define APP_DATA_SIZE 16 // Size of packets to transmit in this example
#define APP_DATA_MAX_SIZE 64 // Size of user data buffer
#define APP_ADR_ON 1 // Whether we use Adaptive Data Rate or not
#define APP_CONFIRMED_MSG_ON 0 // Whether this example will transmit confirmed or unconfirmed packets
So I guess my second question is answered
I also found this post - very useful read
TTN Fair Access Policy
Thanks
Silas
Hi Nestorayuso
Following is the RtcInit() code, actually it is RTCC for EFM32PG. It seems the code on the Main() after sending the first message in “case DEVICE_STATE_SEND:” sets the DeviceState=DEVICE_STATE_SLEEP and then send to TimerLowPowerHandler() (EM2), although the statement TimerStart(&TxNextPacketTimer) should have started the timer which would wake the device up when the time = APP_TX_DUTYCYCLE + RandomDelay expires, but this never happens, seems the RTCC is not running or the interrupt is not firing…
Further, just the outline: in case of my product, the EM sleep mode is handled by the main product code, and it is also responsible for writing the new data frame and when the data is different from the previous data sent, it will set the flag for DataReady and approximately every 4 or 5 min the LoRa packet will be sent out.
Would you please help.
void RtcInit( void )
{
if( RtcInitalized == false )
{
// Reset overflow counter
rtcOverflowCounter = 0;
// Calculate overflow interval based on RTC counter width and frequency
rtcOverflowInterval = ((0x00FFFFFF+1) / RTC_TICKS_PER_MS);
rtcOverflowIntervalR = ((0x00FFFFFF+1) - (rtcOverflowInterval * RTC_TICKS_PER_MS)); // remainder
RtcInitalized = true;
rtcFreq = CMU_ClockFreqGet(cmuClock_RTCC);
RTCC_Init_TypeDef rtccInit = RTCC_INIT_DEFAULT;
RTCC_CCChConf_TypeDef rtccInitCompareChannel = RTCC_CH_INIT_COMPARE_DEFAULT;
rtccInit.cntWrapOnCCV1 = true; /* Clear counter on compare match */
rtccInit.presc = rtccCntPresc_1;
/* Setting the compare value of the RTCC */
RTCC_ChannelInit(1, &rtccInitCompareChannel);
RTCC_ChannelCCVSet(1, 64000);
/* Enabling Interrupt from RTCC */
RTCC_IntEnable(RTCC_IEN_CC1);
NVIC_ClearPendingIRQ(RTCC_IRQn);
NVIC_EnableIRQ(RTCC_IRQn);
/* Initialize the RTCC */
RTCC_Init(&rtccInit);
}
}
be sure to use a 32.768KHz crystal LFXO, not an internal LFRC:
CMU_ClockEnable(cmuClock_CORELE, true);
CMU_ClockSelectSet(cmuClock_LFA, cmuSelect_LFXO);
CMU_ClockDivSet(cmuClock_RTCC, cmuClkDiv_1);
CMU_ClockEnable(cmuClock_RTCC, true);
in your code, the variable rtcFreq is useless.
also set the compare value to 32768-1
RTCC_ChannelCCVSet(1, 32768-1);
show me your RTCC_IRQHandler() function
Hi Nestorayuso
Thanks for your reply. Here is the RTCC_IRQHandler(). With a break point on the RTCCC_IntClear, the program execution does stop there with compare value set to 32767. That means the RTCC and IRQ working fine. Further I set the function GetBoardPowerSource() to return USB_POWER so that the code does not put the device into sleep mode through function TimerLowPowerHandler() and keeps looping through the main -> DEVICE_STATE_SLEEP. But the event OnTxNextPacketTimerEvent() never comes up!! Seems the following code lines does not start the timer for next transmission, what am I missing?? Can you please help… Thank you so much help…
Silas
// Schedule next packet transmission
TxDutyCycleTime = APP_TX_DUTYCYCLE + randr(-APP_TX_DUTYCYCLE_RND, APP_TX_DUTYCYCLE_RND);
TimerSetValue(&TxNextPacketTimer, TxDutyCycleTime);
TimerStart(&TxNextPacketTimer);
void RTCC_IRQHandler(void)
{
uint32_t flags = RTCC_IntGetEnabled(); //get flags for only the enabled interrupts
RTCC_IntClear(RTCC_IFC_OF | RTCC_IFC_CC1);
// Check for overflow
if (flags & RTCC_IF_OF)
rtcOverflowCounter++;
// Check if timer expired
if (flags & RTCC_IF_CC1)
{
RTCC_IntDisable(RTCC_IEN_CC1);
TimerIrqHandler();
}
}
Please send me the complete rtc-board.c
To set a new timer, a call to RtcSetTimeout() is done ant this function sets a new compare value with RTCC_ChannelCCVSet(1, xxx).
The new compare value must be lower than the overflow size of the RCTT counter. If it is higher, you must save it somewhere to set the compare value later whenever doesn’t overflow.
Hi Nestorayuso,
Thanks for your reply. I have attached two files here, rtc-board.c and timer.c. In the original version of the rtc-board.c, in the code for RtcGetTimerValue() was partly commented ?!? I tried with uncommenting the lines but it did not help … rtc-board.txt (7.4 KB) timer.txt (9.8 KB)
For the first power-up cycle, the TimerIrqHandler() in timer.c does fire up and the message sent out without any issue, But after that it just goes into the loop on Main->TimerLowPowerHandler() in timer.c, I have set GetBoardPowerSource() to return as USBpower, so that does not go into low power mode. But there is no timer event and not next message…
TimerTime_t RtcGetTimerValue( void )
{
TimerTime_t t = 0;
// Add time based on number of counter overflows
// t += rtcOverflowCounter * rtcOverflowInterval;
// Add remainder if the overflow interval is not an integer
// if ( rtcOverflowIntervalR != 0 )
// {
// t += (rtcOverflowCounter * rtcOverflowIntervalR) / RTC_TICKS_PER_MS;
// }
// Add the number of milliseconds for RTC
t += ( RTC->CNT / RTC_TICKS_PER_MS );
// Add compensation for crystal temperature drift
t += tempCompAccumulator;
return t;
}
This is resolved with Nestor’s help
Thank you so much @nestorayuso
1 Like