Timer interrupt using ESP32 IDF - timer

I'm a beginner learning ESP32 using IDF and having a task to use interrupt timer. The task is to generate a signal using GPIO pin. The signal should be on for 20ms and off for 6ms. Here is the code that I've tried. I don't know where I'm going wrong and please guide me if my understanding is wrong.
#include <stdio.h>
#include "esp_timer.h"
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "esp_log.h"
#include "driver/gpio.h"
void timer_callback(void *param)
{
static bool on;
on = !on;
gpio_set_level(GPIO_NUM_2, on);
}
void app_main(void)
{
gpio_pad_select_gpio(GPIO_NUM_2);
gpio_set_direction(GPIO_NUM_2, GPIO_MODE_OUTPUT);
const esp_timer_create_args_t my_timer_args = {
.callback = &timer_callback,
.name = "a timer"};
esp_timer_handle_t timer_handler;
ESP_ERROR_CHECK(esp_timer_create(&my_timer_args, &timer_handler));
ESP_ERROR_CHECK(esp_timer_start_periodic(timer_handler, 20000));
ESP_ERROR_CHECK(esp_timer_stop_periodic(timer_handler, 6000));
while (true)
{
//other stuff here
esp_timer_dump(stdout);
vTaskDelay(pdMS_TO_TICKS(1000));
}
}

Related

why is my loop function hanging when it reaches fgets();

I am just trying to toggle on Board LED and listen to incoming Data from the terminal window at the same time, but the whole Loop function hangs when it reachs the fgets(), until I send something the the terminal window then it continues to loop. There must be something like "if Serial available , then start to read ?? Here is my Code, I'm new in Atmel studio
#include <asf.h>
#include <string.h>
char incomingData [256];
// /**
// * \brief Configure UART for debug message output.
// */
static void configure_console(void)
{
const usart_serial_options_t uart_serial_options = {
.baudrate = CONF_UART_BAUDRATE,
#ifdef CONF_UART_CHAR_LENGTH
.charlength = CONF_UART_CHAR_LENGTH,
#endif
.paritytype = CONF_UART_PARITY,
#ifdef CONF_UART_STOP_BITS
.stopbits = CONF_UART_STOP_BITS,
#endif
};
// /* Configure console UART. */
sysclk_enable_peripheral_clock(CONSOLE_UART_ID);
stdio_serial_init(CONF_UART, &uart_serial_options);
}
int main (void)
{
/* Insert system clock initialization code here (sysclk_init()). */
board_init();
sysclk_init();
configure_console();
/* Insert application code here, after the board has been initialized. */
gpio_set_pin_low(LED0_GPIO);
while (1)
{
printf("Hello\r\n");
gpio_toggle_pin(LED0_GPIO);
fgets(incomingData,sizeof(incomingData),stdin);
printf("%s\r\n",incomingData);
}
}

Pic 18f4550 capture mode

I would like to measure a pulse using the pic 18f4550 in capture mode, this pulse is generated by the pic microcontroller itself, for this I use a function which plays the role of the XOR logic gate (you find the function that I've used below). with RC0 and RC2 the inputs and RC6 the signal output. the pulse leaving RC6 enters ccp2 to be measured.
The problem I found is that the ccp2 cannot detect the impulse generated by the microcontroller. I don't know if there are any conditions to connect the pins of the microcontroller or something.
If anyone has an answer or a hint to fix this, I will be grateful!
and if you have any questions feel free to ask .thanks !!
UPDATE: I changed some instructions in the code, now the RC6 output provides a signal. but my LCD does not display anything. the RC6 output is present below.
UPDATE 2: the while(1) in the xor() function blocking the rest of my program, so the program never get out of xor() and my LCD wont display anything. when I don't use the while loop in xor () my RC6 produce anything, the same for the LCD.
I don't know where the problem is, I did everything in my power to find the bug . but the system still not working!!!
I will leave the program as it is, so new readers can understand what I am talking about.
#include <stdio.h>
#include <stdlib.h>
#include "osc_config.h"
#include "LCD_8bit_file.h"
#include <string.h>
unsigned long comtage,capt0,x;
char pulse[20];
char cosinus[20];
float period,dephTempo,deph,phi;
void init (){
IRCF0 =1; /* set internal clock to 8MHz */
IRCF1 =1;
IRCF2 =1;
PIE2bits.CCP2IE=1;
PIR2bits.CCP2IF=0;
CCPR2 =0; /*CCPR1 is capture count Register which is cleared initially*/
T3CONbits.RD16=1;
T3CKPS0=0;
T3CKPS1=0;
TMR3CS=0;
TMR3IF=0;
T3CCP2=0; /*Timer3 is the capture clock source for CCP2*/
}
void xor()
{
while(1)
{
if (PORTCbits.RC0==PORTCbits.RC2)
{
PORTCbits.RC6=0;
}
else if (PORTCbits.RC0!=PORTCbits.RC2)
{
PORTCbits.RC6=1;
}
}
}
void main()
{
TRISCbits.TRISC0=1;
TRISCbits.TRISC2=1;
TRISCbits.TRISC6=0;
xor();
LCD_Init();
while(1)
{
CCP2CON = 0b00000101;
PIR2bits.CCP2IF = 0;
TMR3ON = 0;
TMR3 = 0;
while (!PIR2bits.CCP2IF);
TMR3ON = 1;
CCP2CON = 0b00000100;
PIR2bits.CCP2IF = 0;
while (!PIR2bits.CCP2IF);
comtage = CCPR2;
dephTempo = (((float)comtage /30.518)/65536 );
sprintf(pulse,"%.3f ",dephTempo);
LCD_String_xy(0,0,"the pulse width is : ");
LCD_String_xy(2,9,pulse);
}
}

How do I prevent shutdown or suspend during kernel driver firmware update?

I have a Linux device driver that implements the firmware update API. The driver updates the firmware on our device by using I2C commands to update an attached EEPROM. I use the firmware update API like so:
request_firmware_nowait(
THIS_MODULE, true, "DEVICE.img", &client->dev,
GFP_KERNEL, pdata,
&DEVICE_firmware_callback);
The issue I have is that if the system is powered down during this firmware update process then the attached EEPROM is left in a corrupt state and the device controller will not respond properly on the next boot, not even enough to start another firmware update to correct the issue.
I think a clean solution would be to prevent the system from powering down or suspending during this process, but I do not know how to implement that. Is there a way to have our device driver prevent the system from shutting down while the firmware update is in process?
You can use a reboot notifier along with a completion for this. Whenever you need to perform the firmware update:
Register the reboot notifier through register_reboot_notifier().
Initialize a completion using init_completion().
Start the firmware update. You could do this through a dedicated kthread.
When the update is finished, signal completion with complete().
Unregister the reboot notifier through unregister_reboot_notifier().
Your reboot notifier will detect a reboot (halt, reboot, power off), and will have the possibility to wait for the work to be done through wait_for_completion() (or one of its variants).
Here's an example module that does exactly this with a dummy kthread that just sleeps for 5 seconds:
// SPDX-License-Identifier: GPL-3.0
#include <linux/init.h> // module_{init,exit}()
#include <linux/module.h> // THIS_MODULE, MODULE_VERSION, ...
#include <linux/kernel.h> // printk(), pr_*()
#include <linux/reboot.h> // register_reboot_notifier()
#include <linux/kthread.h> // kthread_{create,stop,...}()
#include <linux/delay.h> // msleep()
#include <linux/completion.h> // struct completion, complete(), ...
#ifdef pr_fmt
#undef pr_fmt
#endif
#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
static DECLARE_COMPLETION(done_wasting_time);
int my_notifier(struct notifier_block *nb, unsigned long action, void *data) {
if (!completion_done(&done_wasting_time)) {
pr_info("Wait! I have some critical job to finish...\n");
wait_for_completion(&done_wasting_time);
pr_info("Done!\n");
}
return NOTIFY_OK;
}
static struct notifier_block notifier = {
.notifier_call = my_notifier,
.next = NULL,
.priority = 0
};
int waste_time(void *data) {
struct completion *cmp = data;
msleep(5000);
complete(cmp);
return 0;
}
static int __init modinit(void)
{
register_reboot_notifier(&notifier);
kthread_run(waste_time, &done_wasting_time, "waste_time");
return 0;
}
static void __exit modexit(void)
{
unregister_reboot_notifier(&notifier);
}
module_init(modinit);
module_exit(modexit);
MODULE_VERSION("0.1");
MODULE_DESCRIPTION("Test module: wait for a critical job to finish before"
" rebooting or powering down.");
MODULE_AUTHOR("Marco Bonelli");
MODULE_LICENSE("GPL");
Output on my test machine:
# insmod reboot_notifier_test.ko
# reboot
[ 6.031410] reboot_notifier_test: Wait! I have some critical job to finish...
[ 9.998207] reboot_notifier_test: Done!
[ 10.003917] reboot: Power down

Atmel SAM4S Xplained UART

I've a SAM4s Xplained and want to use the UART1 but can't find a example or help. I tried on my own but it doesn't work.
Here is my code so far:
conf_uart.h
#include "asf.h" //uart.h etc. included here
#include <sam4s_xplained.h>
#define UART_SERIAL_BAUDRATE 9600
#define UART_SERIAL_CHANNEL_MODE UART_MR_CHMODE_AUTOMATIC //UART_MR_CHMODE_NORMAL
#define UART_SERIAL_MCK 240000000UL //CHIP_FREQ_CPU_MAX (tired both!)
#define UART_SERIAL_MODE UART_MR_PAR_NO
void uart_custom_init(void);
conf_uart.c
#include "conf_uart.h"
uint8_t received_byte;
void uart_custom_init(void) {
sysclk_init();
const sam_uart_opt_t uart_console_settings = {
UART_SERIAL_BAUDRATE,
UART_SERIAL_CHANNEL_MODE,
UART_SERIAL_MCK,
UART_SERIAL_MODE
};
uart_init(UART1,&uart_console_settings); //Init UART1
uart_enable_rx(UART1); //Enable RX (receiving)
uart_enable_tx(UART1); //Enable TX (transmitting)
uart_enable(UART1); //Enable UART1
uart_enable_interrupt(UART1,UART_IER_RXRDY); //Interrupt reading ready
NVIC_EnableIRQ(UART1_IRQn);
}
void UART1_Handler() {
uint32_t dw_status = uart_get_status(UART1);
if(dw_status & UART_SR_RXRDY) {
uint8_t received_byte;
uart_read(UART1, &received_byte);
uart_write(UART1, received_byte);
}
}
I tried different things. As Example I activated the automatic echo, but I don't recieve anything on my Computer and I don't receive anything at my SAM4s.
Here is my working code:
Offline
conf_uart.h
#include "asf.h" //uart.h etc. included here
#define UART_SERIAL_BAUDRATE 9600
#define UART_SERIAL_CHANNEL_MODE UART_MR_CHMODE_NORMAL
#define UART_SERIAL_MODE UART_MR_PAR_NO
/* =============== UART1 =============== */ //(UART0 is defined but not UART1)
#define PINS_UART1 (PIO_PB2A_URXD1 | PIO_PB3A_UTXD1)
#define PINS_UART1_FLAGS (PIO_PERIPH_A | PIO_DEFAULT)
#define PINS_UART1_MASK (PIO_PB2A_URXD1 | PIO_PB3A_UTXD1)
#define PINS_UART1_PIO PIOB
#define PINS_UART1_ID ID_PIOB
#define PINS_UART1_TYPE PIO_PERIPH_A
#define PINS_UART1_ATTR PIO_DEFAULT
void uart_custom_init(void);
void sendViaUart(uint8_t data);
conf_uart.cpp
#include "conf_uart.h"
void uart_custom_init(void) {
sysclk_init();
// set the pins to use the uart peripheral
pio_configure(PINS_UART1_PIO, PINS_UART1_TYPE, PINS_UART1_MASK, PINS_UART1_ATTR);
//enable the uart peripherial clock
pmc_enable_periph_clk(ID_UART1);
const sam_uart_opt_t uart1_settings =
{ sysclk_get_cpu_hz(), UART_SERIAL_BAUDRATE, UART_SERIAL_MODE };
uart_init(UART1,&uart1_settings); //Init UART1 and enable Rx and Tx
uart_enable_interrupt(UART1,UART_IER_RXRDY); //Interrupt reading ready
NVIC_EnableIRQ(UART1_IRQn);
}
void sendViaUart(uint8_t data) {
while (!(UART1->UART_SR & UART_SR_TXRDY));
uart_write(UART1, data);
}
void UART1_Handler() {
uint32_t dw_status = uart_get_status(UART1);
if(dw_status & UART_SR_RXRDY) {
uint8_t received_byte;
uart_read(UART1, &received_byte);
sendViaUart(received_byte);
}
}
best regards
Leo
closed -
The problem is that the UART on this board Sam4S Explained Pro is not mapped to PB2A and PB3A. The UART is mapped to PB2A and PA22A. It took me a long day to figure this out because it's wrong in the documentation.
You might also like this page:
It contains the setup for SAM4S uart and lots of other examples.
ASF Source Code Document It uses USART0, and i know you want to use USART1. But still a good reference.
Hope this helps

How to define a timer in avr-gcc

I am learning to use avr-gcc, but I have no idea, how to solve the following task:
The 8 bits from Port B should alternately set from 0 to 1 with an interval of 500 mili seconds.
I appreciate your help.
You can use #include <util/delay.h> , and if you write : _delay_loop_2(1000); you will have a delay of 1 ms;
You could use this function:
void delay()
{
for(int i=0;i<500;i++)
_delay_loop_2(1000);
}
Have a look at this example. This a very basic code for timer0:
#include<avr/io.h>
#include<avr/interrupt.h>
#define F_CPU 1000000UL
unsigned int t=0;
main()
{
DDRD=0xFF;
TCCR0=(1<<CS00);
TCNT0=0;
TIMSK=(1<<TOIE0);
sei();
while(1);
}
ISR(TIMER0_OVF_vect)
{
t++;
if(t==40000)
{
PORTD=~PORTD;
t=0;
}
}
As #Alex said you can #include <util/delay.h>, but instant of using the provided code (by #Alex) you can simple use _delay_ms(500);
This will provide you a delay of 500ms.
The choice is yours, just keep in mind that in both cases the frequency of your clock must be defined properly to your compiler:
Example for 16MHz:#define F_CPU 16000000UL

Resources