I'm trying to get encoder data to my stm32 h7 and display counter value through uart.
I can see counter value 0 through my uart terminal but counter value never goes up...
I'm using encoder mode.
Please, help me to do this
static void Encoder_init(void)
{
RCC->APB2RSTR &= ~(1 << 1);
RCC->APB2ENR |= (1 << 1); //TIM8 clk enable
TIM8->CR1 &= ~(1 << 0); //tim8 disable
TIM8->SMCR |= (0x03 << 0); //SMS set
TIM8->CCER &= ~(1 << 1); //CC1P
TIM8->CCER &= ~(1 << 5); //CC2P
TIM8->CCER &= ~(1<<3); //CC1NP LOW
TIM8->CCER &= ~(1<<7); //CC2NP LOW
TIM8->CCMR1 |= (1<<0); //CC1S
TIM8->CCMR1 |= (1<<8); //CC2S
TIM8->PSC = 0; //prescaler zero
TIM8->ARR = 0xFFFF;
TIM8->CR1 |= (1 << 0); //tim8 enable}
}
void tEncoder(void *pvParameters)
{
uint8_t encoder_data;
char buf[4];
char val;
RCC->AHB4RSTR &= ~(1 << 2);
RCC->AHB4ENR |= (1 << 2);
GPIOC->MODER &= ~(0x03 << 12);
GPIOC->MODER &= ~(0x03 << 14);
GPIOC->PUPDR |= (1<<6) | (1<<7);
Encoder_init();
while(1) {
vTaskDelay(1000);
if(encoder_data!=TIM8->CNT) {
encoder_data = TIM8->CNT;
int2str(buf, encoder_data);
uart7_buffer_putstr(buf);
SystemPrint("tEncoder counting\n\r");
}
}
}
Related
I am trying to make an state machine with button. When i press the button, state will change. But I can not read the button from IDR. How can i read the button press with IDR ? if( GPIOA->IDR |= (1U << 1) ) this part has a problem i think or should i enable some registers or clocks ?
`
int main(void) {
uint32_t ButtonPress = 0;
/* Enable GPIOA clock */
RCC->IOPENR |= (1U << 0);
/* Setup PA0 as output */
GPIOA->MODER &= ~(3U << 2*0);
GPIOA->MODER |= (1U << 2*0);
/* Setup PA1 as input */
GPIOA->MODER &= ~(3U << 2*1);
GPIOA->MODER |= (0U << 2*1);
/* Setup PA1 as Button1 */
// GPIOA->IDR |= (1U << 1);
while(1) {
if( GPIOA->IDR |= (1U << 1) )
ButtonPress++;
if(ButtonPress == 0)
/* Turn off LED */
GPIOA->ODR ^= (1U << 0);
else if(ButtonPress == 1){
/* Turn on LED 2sec interval */
GPIOA->ODR |= (1U << 0);
delay(LEDDELAY);
delay(LEDDELAY);
GPIOA->ODR ^= (1U << 0);
delay(LEDDELAY);
delay(LEDDELAY);
}
else if(ButtonPress == 2){
/* Turn on LED 1sec interval */
GPIOA->ODR |= (1U << 0);
delay(LEDDELAY);
GPIOA->ODR ^= (1U << 0);
delay(LEDDELAY);
}
else if(ButtonPress == 3){
/* Turn on LED 0.5sec interval */
GPIOA->ODR |= (1U << 0);
delay(LEDDELAY/2);
GPIOA->ODR ^= (1U << 0);
delay(LEDDELAY/2);
}
else if(ButtonPress == 4){
/* Turn on LED 0.1sec interval */
GPIOA->ODR |= (1U << 0);
delay(LEDDELAY/10);
GPIOA->ODR ^= (1U << 0);
delay(LEDDELAY/10);
}
else if(ButtonPress == 5){
/* Turn on LED */
GPIOA->ODR |= (1U << 0);
}
else
/* Button Reset */
ButtonPress = 0;
}
return 0;
}
`
I am trying to make an state machine with button. When i press the button, state will change. But I can not read the button from IDR.
You are attempting to write to the IDR with this line
if( GPIOA->IDR |= (1U << 1) )
Since the IDR is read-only, the statement always evaluates to false.
Instead, you should use:
if (GPIOA->IDR & GPIO_PIN_1) { // GPIO_PIN_1 is a macro for (1U << 1)
ButtonPress++;
}
to evaluate the value of GPIOA pin 1.
In the code I wrote, I chose the PA1 port as an input and connected a button to this input port, then I wrote an interrupt to this button.
first, I write like this and it didn't work
EXTI->EXTICR[0] |= (0U << 8*1);
then, I wrote like this,
EXTI->EXTICR[0] |= (1U << 8*3); and it worked.
I am trying to make PA1 to be an input. and A = 0 this is why i want to write 0U and i want to write 8*1 cause of port is Px1.
my code :
/* External interrupt at PA1 port */
EXTI->EXTICR[0] |= (1U << 8*3);
But I think it should be like,
/* External interrupt at PA1 port */
EXTI->EXTICR[0] |= (0U << 8*1);
Can you explain, why PA1 input is (1U << 83) and not (0U << 81)
When I write
/* External interrupt at PA1 port */
EXTI->EXTICR[0] |= (1U << 8*3);
This, the program is working successfully. But I didn't understand why I have to write (1U << 83), shouldn't I write (0U << 81)?
This is my FULL code :
/*
* project name : 05_EXTIbuttonSM
* file name : main.c
*
* author : Cem Furkan Demirkıran
*
* date : 2022.10.27
*
* description : A state machine blink the external LED at different intervals.
* Assigned each speed to a mode, and attach a button to cycle through the modes.
* Used external interrupts to detect button presses and used the handler to
* change the states. Each button press will cycle through these modes.
*/
#include "stm32g0xx.h"
/* 1 Sec is 1600000 */
void delay(volatile uint32_t);
uint32_t ButtonPress = 0;
/* Interrupt Handlers */
void EXTI0_1_IRQHandler(void){
if (ButtonPress != 5) {
ButtonPress ++;
}
else {
ButtonPress = 0;
}
delay(100000);
EXTI->RPR1 |= (1U << 1);
}
int main(void) {
/* Enable GPIOA clock */
RCC->IOPENR |= (1U << 0);
/* Setup PA0 as output */
GPIOA->MODER &= ~(3U << 2*0);
GPIOA->MODER |= (1U << 2*0);
/* Setup PA1 as input */
GPIOA->MODER &= ~(3U << 2*1);
GPIOA->MODER |= (0U << 2*1);
/* External interrupt at PA1 port */
EXTI->EXTICR[0] |= (1U << 8*3);
/* Mask and Rising on Px1 */
EXTI->IMR1 |= (1U << 1);
EXTI->RTSR1 |= (1U << 1);
/* Setup NVIC */
NVIC_SetPriority(EXTI0_1_IRQn, 0);
NVIC_EnableIRQ(EXTI0_1_IRQn);
while(1) {
switch(ButtonPress){
case 0:
/* Turn off LED */
GPIOA->ODR = (0U << 0);
break;
case 1:
/* Turn on LED 2sec interval */
GPIOA->ODR |= (1U << 0);
delay(3200000);
GPIOA->ODR ^= (1U << 0);
delay(3200000);
break;
case 2:
/* Turn on LED 1sec interval */
GPIOA->ODR |= (1U << 0);
delay(1600000);
GPIOA->ODR ^= (1U << 0);
delay(1600000);
break;
case 3:
/* Turn on LED 0.5sec interval */
GPIOA->ODR |= (1U << 0);
delay(800000);
GPIOA->ODR ^= (1U << 0);
delay(800000);
break;
case 4:
/* Turn on LED 0.1sec interval */
GPIOA->ODR |= (1U << 0);
delay(160000);
GPIOA->ODR ^= (1U << 0);
delay(160000);
break;
case 5:
/* Turn on LED */
GPIOA->ODR |= (1U << 0);
break;
}
}
return 0;
}
void delay(volatile uint32_t s) {
for(; s>0; s--);
}
This is working code after the Answers.
Added Volatile
Changing (1U << 83) to (0U << 81)
Also Changing Handler for bouncing problem.
/*
* project name : 05_EXTIbuttonSM
* file name : main.c
*
* author : Cem Furkan Demirkıran
*
* date : 2022.10.27
*
* description : A state machine blink the external LED at different intervals.
* Assigned each speed to a mode, and attach a button to cycle through the modes.
* Used external interrupts to detect button presses and used the handler to
* change the states. Each button press will cycle through these modes.
*/
#include "stm32g0xx.h"
/* 1 Sec is 1600000 */
void delay(volatile uint32_t);
volatile uint32_t ButtonPress = 0;
/* Interrupt Handlers */
void EXTI0_1_IRQHandler(void){
if (ButtonPress != 5) {
delay(50);
if(ButtonPress !=5)
ButtonPress ++;
else
ButtonPress = 0;
}
else {
ButtonPress = 0;
}
delay(100000);
EXTI->RPR1 |= (1U << 1);
}
int main(void) {
/* Enable GPIOA clock */
RCC->IOPENR |= (1U << 0);
/* Setup PA0 as output */
GPIOA->MODER &= ~(3U << 2*0);
GPIOA->MODER |= (1U << 2*0);
/* Setup PA1 as input */
GPIOA->MODER &= ~(3U << 2*1);
GPIOA->MODER |= (0U << 2*1);
/* External interrupt at PA1 port */
EXTI->EXTICR[0] |= (0U << 8*1);
/* Mask and Rising on Px1 */
EXTI->IMR1 |= (1U << 1);
EXTI->RTSR1 |= (1U << 1);
/* Setup NVIC */
NVIC_SetPriority(EXTI0_1_IRQn, 0);
NVIC_EnableIRQ(EXTI0_1_IRQn);
while(1) {
switch(ButtonPress){
case 0:
/* Turn off LED */
GPIOA->ODR = (0U << 0);
break;
case 1:
/* Turn on LED 2sec interval */
GPIOA->ODR |= (1U << 0);
delay(3200000);
GPIOA->ODR ^= (1U << 0);
delay(3200000);
break;
case 2:
/* Turn on LED 1sec interval */
GPIOA->ODR |= (1U << 0);
delay(1600000);
GPIOA->ODR ^= (1U << 0);
delay(1600000);
break;
case 3:
/* Turn on LED 0.5sec interval */
GPIOA->ODR |= (1U << 0);
delay(800000);
GPIOA->ODR ^= (1U << 0);
delay(800000);
break;
case 4:
/* Turn on LED 0.1sec interval */
GPIOA->ODR |= (1U << 0);
delay(160000);
GPIOA->ODR ^= (1U << 0);
delay(160000);
break;
case 5:
/* Turn on LED */
GPIOA->ODR |= (1U << 0);
break;
}
}
return 0;
}
void delay(volatile uint32_t s) {
for(; s>0; s--);
}
In this case, 8 means the number of bits per bitfield, and 3 or 1 is the number of whole bitfields you want to skip. The 0 or 1 on the left is the value you put in the bitfield.
I would advise you to use named constants here rather than magic numbers, to make the code easier to read.
If you do:
EXTI->EXTICR[0] |= (1U << 8*3);
This means skip 3 fields each of 8 bits and put the value 1 in the fourth field. This sets up an interrupt on PB3.
EXTI->EXTICR[0] |= (0U << 8*1);
This means skip 1 field of 8 bits and put the value 0 in the second field. This sets up an interrupt on PA1.
Note also that using |= you are only setting bits. If the peripheral is in its default reset state of having the register at all zeros then this is fine, but if you have already written to the field you want to change then you may also need to clear some bits with & and '~' too.
I'm testing some things on a Attiny85 and thought about the best way to handle the interrupt rutine. I know it is bad to have a lot of code in the interrupt handler, but I'm uncertain of any other ways to do this. I want my main program to sleep and wake on PCINT, the PCINT comes from multiple pins (rotary encoder A, b & switch and a receiving UART) so I was thinking just having a lot of code in the handler.
The code to determining which pin caused the interrupt, would look like this
#include <avr/io.h>
#include <stdint.h> // has to be added to use uint8_t
#include <avr/interrupt.h> // Needed to use interrupts
volatile uint8_t portbhistory = 0xFF; // default is high because the pull-up
int main(void)
{
DDRB &= ~((1 << DDB0) | (1 << DDB1) | (1 << DDB2)); // Clear the PB0, PB1, PB2 pin
// PB0,PB1,PB2 (PCINT0, PCINT1, PCINT2 pin) are now inputs
PORTB |= ((1 << PORTB0) | (1 << PORTB1) | (1 << PORTB2)); // turn On the Pull-up
// PB0, PB1 and PB2 are now inputs with pull-up enabled
PCICR |= (1 << PCIE0); // set PCIE0 to enable PCMSK0 scan
PCMSK0 |= (1 << PCINT0); // set PCINT0 to trigger an interrupt on state change
sei(); // turn on interrupts
while(1)
{
/*main program loop here */
}
}
ISR (PCINT0_vect)
{
uint8_t changedbits;
changedbits = PINB ^ portbhistory;
portbhistory = PINB;
if(changedbits & (1 << PB0))
{
/* PCINT0 changed */
}
if(changedbits & (1 << PB1))
{
/* PCINT1 changed */
}
if(changedbits & (1 << PB2))
{
/* PCINT2 changed */
}
}
And then ofc inside each of the if-statements in the interrupt handler, there would be code handling something, like this code, turning on the Timer0
TCNT0 = 0; // Set counter to 0
OCR0A = SERIAL_BIT_TIME; // Call timer interrupt in middle of first bit
position = 0; // Reset position and data
TIMSK |= 1 << OCIE0A; // Enable interrupt for compare register A (timer interrupt)
TIFR |= 1 << OCF0A; // Clear timer interrupt flag to prevent it jumping directly there
PCMSK &= ~(1 << SERIAL_RECEIVE); // Disable pin change interrupt
or with the switch input, the code inside the if-statement would be
if (lightState)
{
dali.transmit(ADDRESS, OFF);
lightState = 0;
}
else
{
dali.transmit(ADDRESS, ON);
lightState = 1;
}
Would this be a dumb solution?
volatile uint8_t flag;
int main(void)
{
DDRB &= ~((1 << DDB0) | (1 << DDB1) | (1 << DDB2)); // Clear the PB0, PB1, PB2 pin
// PB0,PB1,PB2 (PCINT0, PCINT1, PCINT2 pin) are now inputs
PORTB |= ((1 << PORTB0) | (1 << PORTB1) | (1 << PORTB2)); // turn On the Pull-up
// PB0, PB1 and PB2 are now inputs with pull-up enabled
PCICR |= (1 << PCIE0); // set PCIE0 to enable PCMSK0 scan
PCMSK0 |= (1 << PCINT0); // set PCINT0 to trigger an interrupt on state change
sei(); // turn on interrupts
while(1)
{
gotosleep();
do
{
switch(flag)
{
case 1:
dosomething1();
break;
case 2:
dosomething2();
break;
case 3:
dosomething3();
break;
}
cli();
flag = 0;
sei();
}while(flag);
}
}
ISR (PCINT0_vect)
{
uint8_t changedbits;
changedbits = PINB ^ portbhistory;
portbhistory = PINB;
if(changedbits & (1 << PB0))
{
flag = 1;
}
if(changedbits & (1 << PB1))
{
flag = 2;
}
if(changedbits & (1 << PB2))
{
flag = 3;
}
}
On ATmega 32u4 I've got two timers. One is for measuring ticks between interrupts and second which counts 1/60 of number of ticks. I'm not sure I'm allowed what I'm doing and if that is correct. If you could tell me what is wrong I would greatfull.
void setup(){
EIMSK |= (1 << INT2); //INT2 enable
EICRA |= (1 << ISC21) | (1 << ISC20); //INT2 RISING EDGE
DDRD &= ~(1 << PD2); //PD0 (INT0)(3) as input
PORTD &= ~(1 << PD2); //PD0 pulldown
TCCR1B |= (1 << CS11); //prescaler 8
//TIMER3 - 1/60
TCCR3A |= (1 << WGM32); //CTC Mode
TCCR3B |= (1 << CS31); //prescaler 8
TIMSK3 |= (1 << OCIE3A); //compate interrupt enable
sei();
}
ISR(INT2_vect) {
TCNT3 = 0;
OCR3A = TCNT1 / 60;
TCNT1 = 0;
degree = 30;
}
ISR(TIMER3_COMPA_vect) {
Color * currentColor = &bColor;
if (degree == 0)
degree = 59;
else degree--;
if (degree == time.second)
currentColor = &sColor;
else if (degree == time.minute)
currentColor = &mColor;
else if (degree % 5 == 0 && degree / 5 == time.hour)
currentColor = &hColor;
//set pwm
RedReg = currentColor->Red;
GreenReg = currentColor->Green;
BlueReg = currentColor->Blue;
}
I am learning embedded development on the STM3220G-EVAL board with the STM32F207 microcontroller. I have tried to test the I2C interface by interfacing the two I2C2 and I2C3 modules on the same chip and sending/receiving a character. Here is the code I have currently written (using mdk-arm 5):
#include <stm32f2xx.h>
volatile uint8_t data = 'a', recv = 'x';
void i2c_init(void);
void I2C2_EV_IRQHandler(void)
{
volatile uint16_t stat, dummy;
stat = I2C2->SR1;
switch(stat)
{
// SB set; read SR1 and write slave address in DR to clear
case 0x01:
dummy = I2C2->SR1;
// Send address of slave
I2C2->DR = (0x08 << 1);
break;
// ADDR set; read SR1 and SR2 to clear
case 0x02:
dummy = I2C2->SR1;
dummy = I2C2->SR2;
break;
// TxE set; write to DR to clear
case 0x80:
I2C2->DR = data;
break;
// TxE and BTF set; generate stop condition to clear
case 0x84:
// Generate stop
I2C2->CR1 |= (1 << 9);
break;
}
}
void I2C3_EV_IRQHandler(void)
{
volatile uint16_t stat, dummy;
stat = I2C3->SR1;
switch(stat)
{
// ADDR set; read SR1 and SR2 to clear
case 0x02:
dummy = I2C3->SR1;
dummy = I2C3->SR2;
break;
// STOPF set; read SR1 and write CR1 to clear
case 0x10:
dummy = I2C3->SR1;
I2C3->CR1 &= ~(1 << 0);
break;
// RxNE set; read DR to clear
case 0x40:
recv = I2C3->DR;
break;
}
}
int main()
{
i2c_init();
// Generate START condition
I2C2->CR1 |= (1 << 8);
while(1)
{
if(!(I2C2->OAR1 & (1 << 14)))
I2C2->OAR1 |= (1 << 14);
if(!(I2C3->OAR1 & (1 << 14)))
I2C3->OAR1 |= (1 << 14);
if(recv != 'x')
break;
}
return 0;
}
void i2c_init(void)
{
// Enable GPIOA, GPIOC, GPIOF, I2C2 and I2C3 peripherals
RCC->AHB1ENR |= (1 << 0);
RCC->AHB1ENR |= (1 << 2);
RCC->AHB1ENR |= (1 << 5);
RCC->APB1ENR |= (1 << 22);
RCC->APB1ENR |= (1 << 23);
// Set GPIO mode to AF
GPIOA->MODER |= (1 << 17);
GPIOC->MODER |= (1 << 19);
GPIOF->MODER |= (1 << 1);
GPIOF->MODER |= (1 << 3);
// Set GPIO type to OD
GPIOA->OTYPER |= (1 << 8);
GPIOC->OTYPER |= (1 << 9);
GPIOF->OTYPER |= (1 << 0);
GPIOF->OTYPER |= (1 << 1);
// Set GPIO speed to 50MHz
GPIOA->OSPEEDR |= (1 << 17);
GPIOC->OSPEEDR |= (1 << 19);
GPIOF->OSPEEDR |= (1 << 1);
GPIOF->OSPEEDR |= (1 << 3);
// Link to AFs
GPIOA->AFR[1] |= (1 << 2);
GPIOC->AFR[1] |= (1 << 6);
GPIOF->AFR[0] |= (1 << 2);
GPIOF->AFR[0] |= (1 << 6);
// Reset clocks
I2C2->CR2 = 0x00;
I2C3->CR2 = 0x00;
I2C2->CCR = 0x00;
I2C3->CCR = 0x00;
// Enable interrupts
I2C2->CR2 |= (1 << 9);
I2C2->CR2 |= (1 << 10);
I2C3->CR2 |= (1 << 9);
I2C3->CR2 |= (1 << 10);
NVIC_EnableIRQ(I2C2_EV_IRQn);
NVIC_EnableIRQ(I2C3_EV_IRQn);
// Must set bit 14 in OAR1 to 1
I2C2->OAR1 |= (1 << 14);
I2C3->OAR1 |= (1 << 14);
// Set addresses
I2C2->OAR1 = (0x04 << 1);
I2C3->OAR1 = (0x08 << 1);
// Set peripheral clock frequency
I2C2->CR2 |= 0x08;
I2C3->CR2 |= 0x08;
I2C2->CCR |= 0x28;
I2C3->CCR |= 0x28;
I2C2->TRISE = 0x09;
I2C3->TRISE = 0x09;
// Enable ACK
I2C2->CR1 |= (1 << 10);
I2C3->CR1 |= (1 << 10);
// Enable I2C peripherals
I2C2->CR1 |= (1 << 0);
I2C3->CR1 |= (1 << 0);
}
The problems I am facing are:
The execution never goes into the interrupt handlers (verified by
breakpoints)
The SB bit in SR1 of the master (I2C2) is never set even though i have set the START bit in CR1
The SDA line is HIGH but the SCL line is pulled LOW
I am using a pullup of 13K on SDA and 10K on SCL. Pin numbers used are PF0, PF1 (I2C2 SDA, SCL) and PA8, PC9 (I2C3 SCL, SDA). Using the internal or external pullups causes the SR2 register to display that the bus is busy.
Also I have not enabled I2C2 and I2C3 in RTE_Device.h. It just seems to provide convenience typedefs. (EDIT : Tried to enable these, it does not help)
Could anyone help me in solving this problem? I seem to have hit a dead end.
(EDIT : After setting up a few jumpers on the board, the master event handler is successfully being called. But still some problems persist. Now the acknowledge failure bit is being set, and the slave handler is not called. Bus lines have been verified to be HIGH when idle.)
Sorry for the delay in mentioning this, but I have successfully solved this problem by using the STM32 CPAL library available from ST. I have tested this library with the onboard accelerometer by reading the 'WHO_AM_I' register in the accelerometer. The code for this is:
#include "cpal_i2c.h"
int main()
{
// Configuration
CPAL_TransferTypeDef RxStruct;
uint8_t RxBuf;
RxStruct.pbBuffer = &RxBuf;
RxStruct.wAddr1 = 0x39;
// Initialization
CPAL_I2C_StructInit(&I2C1_DevStructure);
I2C1_DevStructure.CPAL_Mode = CPAL_MODE_MASTER;
I2C1_DevStructure.CPAL_ProgModel = CPAL_PROGMODEL_DMA;
I2C1_DevStructure.pCPAL_I2C_Struct->I2C_ClockSpeed = 100000;
I2C1_DevStructure.pCPAL_TransferRx = &RxStruct;
I2C1_DevStructure.pCPAL_TransferTx = pNULL;
CPAL_I2C_Init(&I2C1_DevStructure);
// Communication
RxStruct.wNumData = 1;
RxStruct.wAddr2 = 0x0F;
if(CPAL_I2C_Read(&I2C1_DevStructure) != CPAL_PASS)
{
// Error
}
while(I2C1_DevStructure.CPAL_State != CPAL_STATE_READY);
while(1);
return 0;
}