TIM2 module not ticking at 1us in STM8S103F3 controller - debugging

I created a program on STM8S103F3 to generate a delay in rage of micro seconds using TIM2 module, but the timer is not ticking as expected and when I tried to call 5 sec delay using it, it is giving around 3 sec delay. I'm using 16MHz HSI oscillator and timer pre-scalar is set to 16. please see my code below. Please help me to figure out what is wrong with my code.
void clock_setup(void)
{
CLK_DeInit();
CLK_HSECmd(DISABLE);
CLK_LSICmd(DISABLE);
CLK_HSICmd(ENABLE);
while(CLK_GetFlagStatus(CLK_FLAG_HSIRDY) == FALSE);
CLK_ClockSwitchCmd(ENABLE);
CLK_HSIPrescalerConfig(CLK_PRESCALER_HSIDIV1);
CLK_SYSCLKConfig(CLK_PRESCALER_CPUDIV1);
CLK_ClockSwitchConfig(CLK_SWITCHMODE_AUTO, CLK_SOURCE_HSI,
DISABLE, CLK_CURRENTCLOCKSTATE_ENABLE);
CLK_PeripheralClockConfig(CLK_PERIPHERAL_SPI, DISABLE);
CLK_PeripheralClockConfig(CLK_PERIPHERAL_I2C, DISABLE);
CLK_PeripheralClockConfig(CLK_PERIPHERAL_ADC, DISABLE);
CLK_PeripheralClockConfig(CLK_PERIPHERAL_AWU, DISABLE);
CLK_PeripheralClockConfig(CLK_PERIPHERAL_UART1, DISABLE);
CLK_PeripheralClockConfig(CLK_PERIPHERAL_TIMER1, DISABLE);
CLK_PeripheralClockConfig(CLK_PERIPHERAL_TIMER2, DISABLE);
}
void delay_us(uint16_t us)
{
volatile uint16_t temp;
TIM2_DeInit();
TIM2_TimeBaseInit(TIM2_PRESCALER_16, 2000); //Prescalar value 8,Timer clock 2MHz
TIM2_Cmd(ENABLE);
do{
temp = TIM2_GetCounter();
}while(temp < us);
TIM2_ClearFlag(TIM2_FLAG_UPDATE);
TIM2_Cmd(DISABLE);
}
void delay_ms(uint16_t ms)
{
while(ms--)
{
//delay_us(1000);
delay_us(1000);
}
}

It is better to use a 10us time base to round the delays. Well in order to achive a 10us timebase, if you use 16MHz master clock and you prescale TIM2 by 16, then you get a 1 us increment time, right? But we want TIM2 to overflow to generate an event named 16us event. Since we know that the timer will increment every 1us, if we use a reload value 65536 - 10 = 65526, this will give us a 10us overflow hence, 10us time base. If we are ok until here in delay code we'll just check the TIM2 update flag to know whther it has overflowed or not. See the example code snippet below.
// Set up it once since our time base is a fixed 10us
void setupTIM2(){
TIM2_DeInit();
TIM2_TimeBaseInit(TIM2_PRESCALER_16, 65526); //Prescalar value 16,Timer clock 1MHz
}
void delay_us(uint16_t us)
{
volatile uint16_t temp;
TIM2_Cmd(ENABLE);
const uint16_t count = us / 10; //Get the required counts for 10us time base
// Loop until the temp reaches the required count value
do{
while(TIM2_GetFlagStatus(TIM2_FLAG_UPDATE) == RESET); //Wait for the TIM2 to overflow
TIM2_ClearFlag(TIM2_FLAG_UPDATE); // Clear the overflow flag
temp++;
} while(temp < count);
TIM2_Cmd(DISABLE);
}
void delay_ms(uint16_t ms)
{
while(ms--)
{
//delay_us(1000);
delay_us(1000);
}
}
void main(void){
...
setupTIM2();
...
delay_ms(5000);
}

Related

SPI implementation stuck on “while(!spi_is_tx_empty(WINC1500_SPI));”

I'm currently implementing a driver for the WINC1500 to be used with an ATMEGA32 MCU and it's getting stuck on this line of "while(!spi_is_tx_empty(WINC1500_SPI));". The code builds and runs but it won't clear what's inside in this function to proceed through my code and boot up the Wifi Module. I've been stuck on this problem for weeks now with no progress and don't know how to clear it.
static inline bool spi_is_tx_empty(volatile avr32_spi_t *spi)
{
// 1 = All Transmissions complete
// 0 = Transmissions not complete
return (spi->sr & AVR32_SPI_SR_TXEMPTY_MASK) != 0;
}
Here is my implementation of the SPI Tx/Rx function
void m2mStub_SpiTxRx(uint8_t *p_txBuf,
uint16_t txLen,
uint8_t *p_rxBuf,
uint16_t rxLen)
{
uint16_t byteCount;
uint16_t i;
uint16_t data;
// Calculate the number of clock cycles necessary, this implies a full-duplex SPI.
byteCount = (txLen >= rxLen) ? txLen : rxLen;
// Read / Transmit.
for (i = 0; i < byteCount; ++i)
{
// Wait for transmitter to be ready.
while(!spi_is_tx_ready(WINC1500_SPI));
// Transmit.
if (txLen > 0)
{
// Send data from the transmit buffer
spi_put(WINC1500_SPI, *p_txBuf++);
--txLen;
}
else
{
// No more Tx data to send, just send something to keep clock active.
// Here we clock out a don't care byte
spi_put(WINC1500_SPI, 0x00U);
// Not reading it back, not being cleared 16/1/2020
}
// Reference http://asf.atmel.com/docs/latest/avr32.components.memory.sdmmc.spi.example.evk1101/html/avr32_drivers_spi_quick_start.html
// Wait for transfer to finish, stuck on here
// Need to clear the buffer for it to be able to continue
while(!spi_is_tx_empty(WINC1500_SPI));
// Wait for transmitter to be ready again
while(!spi_is_tx_ready(WINC1500_SPI));
// Send dummy data to slave, so we can read something from it.
spi_put(WINC1500_SPI, 0x00U); // Change dummy data from 00U to 0xFF idea
// Wait for a complete transmission
while(!spi_is_tx_empty(WINC1500_SPI));
// Read or throw away data from the slave as required.
if (rxLen > 0)
{
*p_rxBuf++ = spi_get(WINC1500_SPI);
--rxLen;
}
else
{
spi_get(WINC1500_SPI);
}
}
Debug output log
Disable SPI
Init SPI module as master
Configure SPI and Clock settings
spi_enable(WINC1500_SPI)
InitStateMachine()
INIT_START_STATE
InitStateMachine()
INIT_WAIT_FOR_CHIP_RESET_STATE
m2mStub_PinSet_CE
m2mStub_PinSet_RESET
m2mStub_GetOneMsTimer();
SetChipHardwareResetState (CHIP_HARDWARE_RESET_FIRST_DELAY_1MS)
InitStateMachine()
INIT_WAIT_FOR_CHIP_RESET_STATE
if(m2m_get_elapsed_time(startTime) >= 2)
m2mStub_PinSet_CE(M2M_WIFI_PIN_HIGH)
startTime = m2mStub_GetOneMsTimer();
SetChipHardwareResetState(CHIP_HARDWARE_RESET_SECOND_DELAY_5_MS);
InitStateMachine()
INIT_WAIT_FOR_CHIP_RESET_STATE
m2m_get_elapsed_time(startTime) >= 6
m2mStub_PinSet_RESET(M2M_WIFI_PIN_HIGH)
startTime = m2mStub_GetOneMsTimer();
SetChipHardwareResetState(CHIP_HARDWARE_RESET_FINAL_DELAY);
InitStateMachine()
INIT_WAIT_FOR_CHIP_RESET_STATE
m2m_get_elapsed_time(startTime) >= 10
SetChipHardwareResetState(CHIP_HARDWARE_RESET_COMPLETE)
retVal = true // State machine has completed successfully
g_scanInProgress = false
nm_spi_init();
reg = spi_read_reg(NMI_SPI_PROTOCOL_CONFIG)
Wait for a complete transmission
Wait for transmitter to be ready
SPI_PUT(WINC1500_SPI, *p_txBuf++);
--txLen;
Wait for transfer to finish, stuck on here
Wait for transfer to finish, stuck on here
The ATmega32 is an 8-bit AVR but you seem to be using code for the AVR32, a family of 32-bit AVRs. You're probably just using the totally wrong code and you should consult the datasheet of the ATmega32, and search for SPI for the AVR ATmega family.

Trigger Countdown with 433 MHz transmission

I would like to use an arduino to read 433 MHz transmission from multiple Soil Moisture Sensors. Since I can never be sure all transmissions reach the receiver I'd like to set a countdown from the moment the first transmission is received. If another transmission is received, the countdown starts again.
After a defined amount of time (e.g. 10 Minutes) without any more signals or if all signals have been received (e.g 4 Sensors) the receiving unit should stop and come to decision based on the data it got to the point.
For transmitting and receiving I am using the <RCSwitch.h>library.
The loop of the receiving unit and one Sensor looks like this:
#include <RCSwitch.h>
RCSwitch mySwitch = RCSwitch();
void Setup(){
Serial.begin(9600);
mySwitch.enableReceive(4);
}
void loop() {
if (mySwitch.available()) {
int value = mySwitch.getReceivedValue();
if (value == 0) {
lcd.clear();
Serial.print("Unknown encoding");
}
else {
Serial.print(mySwitch.getReceivedValue());
Serial.print("%");
}
The full code includes some differentiation mechanism for all sensors but I figured that might not be relevant for my question.
Question:
What's the best way to do this without a real time clock module. As far as I know I can't wait by using delay(...)since then I won't receive any data while the processor waiting.
You can use millis() as a clock. It returns the number of milliseconds since the arduino started.
#define MINUTES(x) ((x) * 60000UL)
unsigned long countStart = 0;
void loop()
{
if (/*read from module ok*/)
{
countStart = millis();
// sanity check, since millis() eventually rolls over
if (countStart == 0)
countStart = 1;
}
if (countStart && ((millis() - countStart) > MINUTES(10)))
{
countStart = 0;
// trigger event
}
}
Arduino's internal timers can also be used in this situation. If a long time period is needed, it's better to use 16bit counter (usually timer1) at 1024 prescaler (largest available). If the largest time interval of timer is greater than time required, then a counter have to be added in order to keep track of 1 minute interval.
For example, for 1-minute interval, initialize registers as:
TCCR1A = 0; //Initially setting every register as 0x0000
TCCR1B = 0;
TCNT1 = 0;
OCR1A = 468750; // compare match register 16MHz/1024/2/frequency(hz)
TCCR1B |= (1 << WGM12); // Timer compare mode
TCCR1B |= (1 << CS10) | (1 << CS10); // 1024 prescaler
TIMSK1 |= (1 << OCIE1A); // enable timer compare interrupt
These configuration of timer will give interrupt time of 1 minute. And upon timer completion ISR TIMER1_COMPA_vect will be run. You can play around with value of OCR1A for different interrupt periods.
Main advantage of using interrupts is that they don't block any task and can will be executed instantaneously (if interrupts are not disabled explicitly).

AlarmRepeat function in Arduino

I am using the Time.h and TimeAlarms.h libraries in Arduino. I try to call a function on specific times of the day (every day). The function is called on the first day, but then on the next day it seems like the alarm ceases to work, although it should repeat every day. Any ideas what's wrong with my sketch?
#include <Time.h>
#include <TimeAlarms.h>
#define TIME_MSG_LEN 11 // time sync to PC is HEADER followed by Unix time_t as ten ASCII digits
#define TIME_HEADER 'T' // Header tag for serial time sync message
#define TIME_REQUEST 7 // ASCII bell character requests a time sync message
// The constant variables used in the code:
const unsigned long shock_delay = 10; // shock stimulus duration (s)
// Edit below only if you make changes to the hardware configuration:
const int tonePin = 13; // the number of the LED pin
const int shockPin = 12; // the number of the shocker pin
const int buzzerOut = 8; // the number of the tone producer
const int trialButton=2; // the number of the trial button
const int controlButton=3; // the number of the control button
// Define the variables that will change in the code
unsigned int Interval1; // the interval between the beginning of the hour and the first footshock
unsigned int Interval2; // the interval between the first and the second footshock
void setup()
{
Serial.begin(9600); // opens serial port, sets data rate to 9600 bps
setTime(23,59,50,10,4,15); // The current time (HH,MM,SS,DD,MM,YY)
// Define the position of the different digital pins
pinMode(tonePin, OUTPUT); // The tone LED (red)
pinMode(shockPin, OUTPUT); // The shock output, which will coincide with green LED
pinMode(trialButton, INPUT); // The trial input button
pinMode(controlButton, INPUT); // The control input button
Alarm.alarmRepeat(20,00,0,RandomShock); // Initiate the user defined RandomShock function
Alarm.alarmRepeat(21,00,0,RandomShock); // Initiate the user defined RandomShock function
Alarm.alarmRepeat(22,00,0,RandomShock); // Initiate the user defined RandomShock function
Alarm.alarmRepeat(23,00,0,RandomShock); // Initiate the user defined RandomShock function
Alarm.alarmRepeat(0,00,0,RandomShock); // Initiate the user defined RandomShock function
Alarm.alarmRepeat(1,00,0,RandomShock); // Initiate the user defined RandomShock function
Alarm.alarmRepeat(2,00,0,RandomShock); // Initiate the user defined RandomShock function
Alarm.alarmRepeat(3,00,0,RandomShock); // Initiate the user defined RandomShock function
Alarm.alarmRepeat(4,00,0,RandomShock); // Initiate the user defined RandomShock function
Alarm.alarmRepeat(5,00,0,RandomShock); // Initiate the user defined RandomShock function
Alarm.alarmRepeat(6,00,0,RandomShock); // Initiate the user defined RandomShock function
Alarm.alarmRepeat(7,00,0,RandomShock); // Initiate the user defined RandomShock function
}
void loop(){
// Create a message that gives the current time and date on the monitor
if(Serial.available() )
{
processSyncMessage();
}
if(timeStatus() == timeNotSet)
Serial.println("waiting for sync message");
else
digitalClockDisplay(); // The function that calls on the time display
Alarm.delay(1000); // Delay of 1 minute between time display
}
void digitalClockDisplay(){
// digital clock display of the time
Serial.print(hour());
printDigits(minute());
printDigits(second());
Serial.print(" ");
Serial.print(day());
Serial.print(" ");
Serial.print(month());
Serial.print(" ");
Serial.print(year());
Serial.println();
}
void printDigits(int digits){
// utility function for digital clock display: prints preceding colon and leading 0
Serial.print(":");
if(digits < 10)
Serial.print('0');
Serial.print(digits);
}
void processSyncMessage() {
// if time sync available from serial port, update time and return true
while(Serial.available() >= TIME_MSG_LEN ){ // time message consists of header & 10 ASCII digits
char c = Serial.read() ;
Serial.print(c);
if( c == TIME_HEADER ) {
time_t pctime = 0;
for(int i=0; i < TIME_MSG_LEN -1; i++){
c = Serial.read();
if( c >= '0' && c <= '9'){
pctime = (10 * pctime) + (c - '0') ; // convert digits to a number
}
}
setTime(pctime); // Sync Arduino clock to the time received on the serial port
}
}
}
void RandomShock () {
Interval1 = random(0,60); // Random value between 0 and 59 [min]
digitalWrite(tonePin,HIGH); // Indicate the shock program is ON by the red LED
Alarm.delay(Interval1*60000); // Wait for the duration of the first interval
digitalWrite(tonePin,LOW); // Turn the red LED OFF
digitalWrite(shockPin, HIGH); // Apply the first shock (green LED will turn ON)
Serial.println("Applying an electeric shock at:"); // Write a message indicating a shock is applied
digitalClockDisplay(); // Display the time during which the shock was applied
Alarm.delay(shock_delay*1000); // The duration of the shock [10 seconds]
digitalWrite(shockPin, LOW); // Terminate the first shock (green LED will turn OFF)
Interval2 = random(0,(61-Interval1)); // Randomly asign a value to the second interval [min]
digitalWrite(tonePin,HIGH); // Indicate the shock program is ON by the red LED
Alarm.delay(Interval2*60000-20000); // Wait for the duration of the second interval
digitalWrite(tonePin,LOW); // Turn the red LED OFF
digitalWrite(shockPin,HIGH); // Apply the second shock (green LED will turn ON)
Serial.println("Applying an electeric shock at:"); // Write a message indicating a shock is applied
digitalClockDisplay(); // Display the time during which the shock was applied
Alarm.delay(shock_delay*1000); // The duration of the shock [10 seconds]
digitalWrite(shockPin,LOW); // Terminate the second shock
digitalWrite(tonePin,HIGH); // Indicate the shock program is ON by the red LED
Alarm.delay((60-Interval1-Interval2)*60000); // Wait until the hour is completed
digitalWrite(tonePin,LOW); // Turn the red LED OFF
}
There are two problems with the sketch that I wrote:
Alarm.alarmRepeat function does not seem to be able to call my
function exactly at midnight (00:00:00), however, if I schedule it
to any other time (e.g., 00:00:01) it works just fine.
There is a limit to the number of alarms you can schedule: the
maximum number of alarms is 6. The solution is either to change this threshold, or to reduce the number of alarms.
After correcting for these two issues the sketch work smoothly.
Seems that TimeAlarm library is unable to set an alarm to midnight
https://github.com/PaulStoffregen/TimeAlarms/issues/3
Try this pull request https://github.com/PaulStoffregen/TimeAlarms/pull/4
If you need more than 6 alarms just look for that at TimeAlarms.h on the library:
#if defined(__AVR__)
#define dtNBR_ALARMS 6 // max is 255
#else
#define dtNBR_ALARMS 12 // assume non-AVR has more memory
#endif
and change it to your need (example:24)
#if defined(__AVR__)
#define dtNBR_ALARMS 24 // max is 255
#else
#define dtNBR_ALARMS 12 // assume non-AVR has more memory
#endif

Segmentation fault when changing value of attribute

I'm working in a C++11 class that will fetch via I2C the value of a temperature sensor in a Raspberry Pi. It will be polling the value until it's stopped. It does the polling in a separate thread, so that it does not stop the application flow. The problem is that in the line 64 of this file: https://github.com/OpenStratos/server/blob/feature/temperature/temperature/Temperature.cpp#L64
void Temperature::read_temperature()
{
while (this->reading)
{
#ifndef OS_TESTING
int value = wiringPiI2CRead(this->filehandle);
#else
int value = 16000;
#endif
float voltage = value * 5 / 32768; // 2^15
float temp = r_to_c(TEMP_R * (TEMP_VIN / voltage - 1));
this->temperature = temp; // Gives segmentation fault
this_thread::sleep_for(chrono::milliseconds(50));
}
}
it gives a segmentation fault. The curius thing is that it does not always happen. After compiling, running the binary many times about the 75% of the time will crash.
This is the file that invoques the code:https://github.com/OpenStratos/server/blob/feature/temperature/testing/temperature_test.cpp
Temperature temp(20);
temp.start_reading();
AssertThat(temp.is_reading(), Equals(true));
// this_thread::sleep_for(chrono::milliseconds(100)); if uncommented less segmentation faults
temp.stop_reading();
AssertThat(temp.is_reading(), Equals(false));
What could be happening? How can it be fixed?
You need to wait for Temperature::read_temperature() to quit, so you need:
bool reading;
volatile bool stopped; // volatile required to make the compiler re-read
// the value everytime we expect it to.
//
bool is_stopped(){ return stopped; }
and
void Temperature::start_reading()
{
if (!reading)
{
stopped = false;
reading = true;
// etc
and
void Temperature::read_temperature()
{
while (this->reading)
{
// etc
}
stopped=true;
}
and
temp.stop_reading();
while(!temp.is_stopped();
AssertThat(temp.is_reading(), Equals(false));

Making a timer in Arduino whilst checking for input

I need to wait for a period of time while checking whether a button is pressed (so whether an input is HIGH or LOW).
The delay function is annoying to use for this because it cannot check whether something is happening while being delayed, so it would have to wait for 1 ms, check, wait, check, wait, check etc...
Can you help me with the coding I would need to check and pause for a set amount of time, at the same time?
You can realize that with a second condition-controlled loop.
If you want to wait in each arduino main loop as an example for 20 seconds and execute in this time span further code you can do this as follows:
unsigned long startTime = millis(); // Number of milliseconds since the program started (unsigned long)
unsigned long intervalTime = 20000UL; // equals 20 seconds
int buttonPin = 3; // used button pin
void loop()
{
while(millis() - startTime < intervalTime){
if(digitalRead(buttonPin)==HIGH){
//...
}
else {
//...
}
}
//...
}

Resources