How would the below two statements differ wrt timing / execution.
I am working on AT91CSAM7x512 device.
We were able to resolve a troublesome bug by changing the below assignment style.
I am using IAR Embedded Workbench Ver 4.41A. Is this happening due to some compiler directive or some other reason ?
AT91C_BASE_PIOA->PIO_PER |= (((unsigned int)1<<12) | ((unsigned int)1<<13));
AT91C_BASE_PIOA->PIO_ODR |= (((unsigned int)1<<12) | ((unsigned int)1<<13));
AT91C_BASE_PIOA->PIO_IFER |= (((unsigned int)1<<12) | ((unsigned int)1<<13));
MARK1.occurrence = 0;
MARK2.occurrence = 0;
AT91C_BASE_PIOA->PIO_PER |= (unsigned int)1<<12) ;
AT91C_BASE_PIOA->PIO_ODR |= (unsigned int)1<<12) ;
AT91C_BASE_PIOA->PIO_IFER |= (unsigned int)1<<12) ;
MARK1.occurrence = 0;
AT91C_BASE_PIOA->PIO_PER |= (unsigned int)1<<13) ;
AT91C_BASE_PIOA->PIO_ODR |= (unsigned int)1<<13) ;
AT91C_BASE_PIOA->PIO_IFER |= (unsigned int)1<<13) ;
MARK2.occurrence = 0;
Would this have anything to do with the way the stack is handeled # instructions
i am comparatively new to processors & need help with this.
Related
I am writing code for the STM32F031K6T6 MCU using the Keil uVision. The IDE information is shown in the image below:
enter image description here
The C/C++ options for Target are configured as shown here:
enter image description here
I started a new project, selected the chip, and configured the run-time environment as below:
enter image description here
I initialized the clock and configured the Flash registers for the appropriate latency. I tested the frequency using MCO and it seems correct. I also initialized some GPIOs, UART, and the SysTick. The peripheral registered is modified as expected as seen on the System View for the respective peripheral in the debugging mode.
The problem is that some functions, such as functions for sending and receiving data via UART and some functions that use GPIO ports only work in debugging mode when I run the code line-by-line. If I click the run button the code gets stuck and the chip stops responding. I still see the VAL and CURRENT registers of the SysTick updating.
This is an example of a function that works:
void System_Clock_init(void){
FLASH->ACR &= ~FLASH_ACR_LATENCY;
FLASH->ACR |= FLASH_ACR_LATENCY | 0x01;
RCC->CR |= RCC_CR_HSION;
while((RCC->CR & RCC_CR_HSIRDY) == 0);
RCC->CR &= ~RCC_CR_HSITRIM;
RCC->CR |= 16UL << 3;
RCC->CR &= ~RCC_CR_PLLON;
while((RCC->CR & RCC_CR_PLLRDY) == RCC_CR_PLLRDY);
RCC->CFGR &= ~RCC_CFGR_PLLSRC;
RCC->CFGR |= 10UL << 18;
RCC->CFGR &= ~RCC_CFGR_HPRE;
RCC->CFGR &= ~RCC_CFGR_PPRE;
RCC->CR |= RCC_CR_PLLON;
while((RCC->CR & RCC_CR_PLLRDY) == 0);
RCC->CFGR &= ~RCC_CFGR_SW;
RCC->CFGR |= RCC_CFGR_SW_PLL;
while((RCC->CFGR & RCC_CFGR_SWS) != RCC_CFGR_SWS_PLL);
}
This is an example of a function that doesn’t work:
void UV_LED_Driver(uint32_t d){
for(uint32_t i = 0; i<16; i++){
if(d&(((uint32_t)0x8000)>>i)){
SDI2_ON;
}
else {
SDI2_OFF;
}
CLK2
}
LATCH2
}
The macros used in the function above are defined as below:
// CLK2 -> PA5
// LE2 -> PA4
// SDI2 -> PA6
#define CLK2_OFF GPIOA->ODR |= (1UL << 5)
#define CLK2_ON GPIOA->ODR &= ~(1UL << 5)
#define LE2_OFF GPIOA->ODR |= (1UL << 4)
#define LE2_ON GPIOA->ODR &= ~(1UL << 4)
#define SDI2_ON GPIOA->ODR &= ~(1UL << 6)
#define SDI2_OFF GPIOA->ODR |= (1UL << 6)
#define CLK2 {CLK2_ON; us_Delay(1); CLK2_OFF;}
#define LATCH2 {LE2_ON; us_Delay(1); LE2_OFF;}
The GPIO pins used in the function above are initialized as follows:
// CLK2 -> PA5
// LE2 -> PA4
// SDI2 -> PA6
void UV_LED_Driver_Init(void){
RCC->AHBENR |= RCC_AHBENR_GPIOAEN;
GPIOA->MODER &= ~((3UL << 8) | (3UL << 10) | (3UL << 12));
GPIOA->MODER |= ((1UL << 8) | (1UL << 10) | (1UL << 12));
GPIOA->OTYPER &= ~(0x70UL);
GPIOA->PUPDR &= ~((1UL << 8) | (1UL << 10) | (1UL << 12));
GPIOA->OSPEEDR &= ~((3UL << 8) | (3UL << 10) | (3UL << 12));
GPIOA->OSPEEDR |= ((1UL << 8) | (1UL << 10) | (1UL << 12));
GPIOA->ODR |= (0x70UL);
}
And the us_Delay() function is based on SysTick. These are defined as:
static uint32_t usDelay = 0;
void SysTick_init(uint32_t ticks){
SysTick->CTRL = 0;
SysTick->LOAD = ticks - 1;
NVIC_SetPriority(SysTick_IRQn, (1<<__NVIC_PRIO_BITS) - 1);
SysTick->VAL = 0;
SysTick->CTRL |= SysTick_CTRL_CLKSOURCE_Msk;
SysTick->CTRL |= SysTick_CTRL_TICKINT_Msk;
SysTick->CTRL |= SysTick_CTRL_ENABLE_Msk;
}
void SysTick_Handler(void){
if(usDelay > 0){
usDelay--;
}
}
void us_Delay(uint32_t us){
usDelay = us;
while(usDelay != 0);
}
Now, this is the same UV_LED_Driver(uint32_t d) function defined as a macro (Runs as expected):
#define UV_LED_DRIVER(d) {for(int i = 0; i<16; i++){if(d&(0x000F>>i)){SDI2_ON;}else {SDI2_OFF;}CLK2}LATCH2}
This is the main():
#include <stm32f031x6.h>
#include "clock.h"
#include "LED_Driver.h"
#include "UART.h"
int main(void){
System_Clock_init();
Color_LED_Driver_Init();
UV_LED_Driver_Init();
Nucleo_Green_LED_Init();
UART_init();
SysTick_init(47);
//MCO_Init(); // Check PIN 18 (PA8) for the frequency of the MCO using an Oscilloscope
while(1){
UV_LED_DRIVER(~(0x0000)) // This runs well
//UV_LED_Driver((uint32_t)~(0x0000)); // If I run this line
//the debugger gets stuck here. It works if I run line-by-line
ms_Delay(100);
UV_LED_DRIVER(~(0xFFFF)) // This runs well
//UV_LED_Driver((uint32_t)~(0xFFFF)); // If I run this line
//the debugger gets stuck here. It works if I run line-by-line
ms_Delay(100);
}
}
Interestingly, if I define the functions as macros, they behave as desired. I finally tested the code on a STM32F429ZIT chip and it worked well, given the needed modifications in the initialization of the main clock and the GPIO.
Has anyone ever experienced anything similar or happens to know what could be causing this issue? I know that I could walk around this issue using CubeMX but I would like to find out what is causing this problem.
Thank you.
I asked the same question at the ST Community forum and the user waclawek.jan answered it. The problem is that I was calling the SysTick interrupt too often, not leaving any time for the main() to run. To fix the code, I just called the SysTick_init() function passing "479" as an argument instead of "47".
Thank you!
I have the assignment to create a running light on my Arduino with the following requirements/constraints
Requirements
Implement a socalled “runninglight” with 3 leds.
The on time of each led is the same, being 0.5 sec.
After the last Led is lit, the first starts again.
Constraints
The leds are connected to pin 8,9 and 10 of the Arduino. (don’t forget the resistors)
The running led must be implemented in the loop of the Arduino
The setup() function may contain any Arduino function/macro.
Only the Arduino function delay() is allowed in the loop.
No use of any other Arduino function/macro etc. in the loop.
No use of for/while in the loop() function
No use of your own defined functions
Your loop function must contain not more then 10 statements.
So in the loop you may only use
o Delay function
o Your variables
o The following characters/digits: * ( ) & ~ | ; = < > ! + - 0 1 2 3 4 5 6 7 8 9
I have tried the following code
#include <Arduino.h>
//mask for setting correct bits in register to setup leds to 1
#define DDBMASK 0x07
//masks for setting correct bits in register for led control to 1
#define LEDMASK 0x01
byte *ddBPtr; //point to ddB register (data direction)
byte *portBPtr; //point to portB resiger (data register)
void setup() {
//setup data direction register to set pins to output
ddBPtr = (byte *) 0x24;
*ddBPtr |= DDBMASK; // 0b0000 0111
//assign pointer to right register
portBPtr = (byte *) 0x25;
}
void loop() {
//use data register (portB) for controlling leds
*portBPtr ^= LEDMASK;
delay(500);
*portBPtr ^= LEDMASK;
*portBPtr ^= LEDMASK << 1;
delay(500);
*portBPtr ^= LEDMASK << 1;
*portBPtr ^= LEDMASK << 2;
delay(500);
*portBPtr ^= LEDMASK << 2;
}
Apparently this is possible with only one delay function and following the requirements and constrains. I have been stuck on this for hours and cant figure it out.
I tried the following which also does not work because I'm unable to reset my counter back to zero
void loop() {
//use data register (portB) for controlling leds
*portBPtr ^= (LEDMASK << ledCount);
delay(500);
*portBPtr ^= (LEDMASK << ledCount);
ledCount++;
//cant figure out a way to reset ledCount back to 0 after 3 itterations
//running light only runs once so first led does not light after third led is lit
}
What am I missing?
Perhaps this:
*portBPtr |= (1 << ledCount);
delay(500);
*portBPtr &= ~(1 << ledCount);
ledCount = (9 >> (ledCount << 1)) & 3;
This also avoids ^ which is not in your list of allowed symbols.
The line ledCount = (9 >> (ledCount << 1)) & 3 is like a lookup table with each entry taking up two bits. It maps 0 to 1, 1 to 2, 2 to 0. The normal way to write this code is ledCount = (1 + ledCount) % 3;
This might also work, being a little simpler:
delay(500);
*portBPtr = (1 << ledCount);
ledCount = (9 >> (ledCount << 1)) & 3;
By using assignment rather than | or & or ^, all the other bits will be zero, presumably causing the non-current leds to turn off.
I had two questions regarding writing into registers for ARM programming using C language.
1st: I'm trying to write to the Application Interrupt and Reset Control Register or AIRCR. It's a 32-bit register. I need two write 0x5FA values at bits 16 to 31 (the need of register). I also need to modify some other bits, but singularly. I meant, only bitwise (0 or 1). I know how to do this when it's only a bit. using *iser0 |= 0UL << 2; for example. But my question is that how can I write to a part of the register, namely, the AIRCR[31:16] while being able to manipulate other bits.
2nd: This issue is not my main issue, But when I compile my C program, It's return value is not 0. Is this abnormal? What has been my mistake?
#include <stdint.h>
typedef __int32 int32_t;
typedef unsigned __int32 uint32_t;
int main()
{
//Multi drive register
uint32_t* muer=(uint32_t*) 0x400E0E50UL;
*muer |= 1UL << 8;
uint32_t* mudr=(uint32_t*) 0x400E0E54UL;
*mudr |= 0UL << 8;
//Pio controller register
uint32_t* per=(uint32_t*) 0x400E0E00UL;
*per |= 1UL << 8;
uint32_t* pdr=(uint32_t*) 0x400E0E04UL;
*pdr |= 0UL << 8;
//output register
uint32_t* oer=(uint32_t*) 0x400E0E10UL;
*oer |= 0UL << 8;
uint32_t* odr=(uint32_t*) 0x400E0E14UL;
*odr |= 1UL << 8;
//edge select
uint32_t* esr=(uint32_t*) 0x400E0EC0;
*esr |= 1UL << 8;
//level select
uint32_t* lsr=(uint32_t*) 0x400E0EC4;
*lsr |= 0UL << 8;
//Rising edge
uint32_t* rehlsr=(uint32_t*) 0x400E0ED4;
*rehlsr |= 1UL << 8;
//Falling edge edge
uint32_t* fellsr=(uint32_t*) 0x400E0ED8;
*fellsr |= 0UL << 8;
//Interrupt set-enable register
uint32_t* iser0=(uint32_t*) 0xE000E100;
*iser0 |= 1UL << 11;
//Interrupt clear-enable register
uint32_t* icer0=(uint32_t*) 0xE000E180;
*icer0 |= 0UL << 11;
//AIRCR
uint32_t* aircr=(uint32_t*) 0xFA050000;
//VECTKEY
*aircr |= 0x5FA << 16;
//ENDIANESS
*iser0 |= 0UL << 15;
//PRIGRIOUP
*iser0 |= 5UL << 8;
//SYSRESETREQ
*iser0 |= 0UL << 2;
//VECTCLRACTIVE
*iser0 |= 0UL << 1;
//SYSRESETREQ
*iser0 |= 0UL;
}
This is my code.
Update:
I understood that I cannot do |= 0UL, instead, I should use &= 1 << bits.
I tried this one for my other code. But it still doesn't return 0, and surprisingly, it takes 10 seconds to compile.
#include<stdint.h>
int main()
{
//Pull up register
volatile uint32_t* puer=(uint32_t*) 0x400E0E64UL;
*puer &= 1 << 8;
volatile uint32_t* pudr=(uint32_t*) 0x400E0E60UL;
*pudr |= 1UL << 8;
//Multi drive register
volatile uint32_t* muer=(uint32_t*) 0x400E0E50UL;
*muer &= 1 << 8;
volatile uint32_t* mudr=(uint32_t*) 0x400E0E54UL;
*mudr |= 1UL << 8;
//Pio controller register
volatile uint32_t* per=(uint32_t*) 0x400E0E00UL;
*per |= 1UL << 8;
volatile uint32_t* pdr=(uint32_t*) 0x400E0E04UL;
*pdr &= 1 << 8;
//ABSR register
volatile uint32_t* absr=(uint32_t*) 0x400E0E70UL;
*absr &= 1 << 8;
//output register
volatile uint32_t* oer=(uint32_t*) 0x400E0E10UL;
*oer |= 1UL << 8;
volatile uint32_t* odr=(uint32_t*) 0x400E0E14UL;
*odr &= 1 << 8;
}
Update
I have not connected my micro to my PC. One possible issue is that I don't have these addresses on my machine?
In order to clear a single bit of a variable, you don't use *register |= 0 << bit but instead *register &= ~(1 << bit). If you want to manipulate more than one bit, essentially what you have to do is erase the relevant part and then overwrite it with your desired pattern.
This for example will delete the bits 4 to 6, and then overwrite them with the contents of value:
*register &= 0x7 << 4
*register |= (value & 0x7) << 4;
As for your second question:
Never ever try to run code that tries to access random memory locations like that on a PC. This is something you only do to access registers on a microcontroller. Your PC doesn't have those registers and even if it did, your operating system hides the actual physical memory from you anyway.
DISCLAIMER:
As pointed out by Lundin, using bitfields is compiler/architecture-dependent and therefore non-portable. If you want to use them, you will have to check your compiler's documentation to make sure they work as expected. When in doubt, prefer the solution above. Continue reading at your own risk ;-)
With that out of the way, what you could also do, in order to avoid the bit manipulation is something like this:
union
{
struct
{
uint32_t vectreset :1;
uint32_t vectclractive :1;
uint32_t sysresetreq :1;
uint32_t :5;
uint32_t prigroup :3;
uint32_t :4;
uint32_t endianness :1;
uint32_t vectkey :0;
};
uint32_t u32;
} *aircr = (void*)0xFA050000;
And then in your code, access the bitfield like this: (*aircr).vectkey = 0x5FA;
I went through the entire configuration of the Analog-to-digital converter [ADC]. When I worked on the registers, I made a mistake somewhere. Below are the configurations. The debugger via ST-Link after connecting 3.3 [V] to pins used in the project, during the measurement assigns them a value of 0x00 which indicates a failure. What am I doing wrong?
int main(void)
{
RCC->APB2ENR |= RCC_APB2ENR_ADC1EN;
//ADC attach
RCC->IOPENR = RCC_IOPENR_GPIOAEN | RCC_IOPENR_GPIOBEN;
GPIOB->MODER = GPIO_MODER_MODE14_1 | GPIO_MODER_MODE15_1;
//ADC_IN8 & ADC_IN9
/* configure ADC */
ADC1->ISR &= ~ADC_ISR_EOCAL & ~ADC_ISR_AWD;
//calibration flag, WATCHDOG flag
ADC1->ISR |= ADC_ISR_ADRDY;
ADC1->CR &= ~ADC_CR_ADSTART;
//The software is allowed to write smp bit only when ADSTART=0
ADC1->SMPR |= ADC_SMPR_SMP_0 | ADC_SMPR_SMP_1 | ADC_SMPR_SMP_2;
//111: 160.5 ADC clock cycles
ADC1->CFGR1 &= ~ADC_CFGR1_SCANDIR;
//Scan Direction 0: Upward scan (from CHSEL0 to CHSEL18)
ADC1->CFGR1 |= ADC_CFGR1_AWDCH_3 | ADC_CFGR1_AWDEN | ADC_CFGR1_WAIT | ADC_CFGR1_CONT | ADC_CFGR1_AUTOFF;
//AWDCH[4:0]: Analog watchdog channel selection, Continuous Mode
ADC->CCR |= ADC_CCR_LFMEN | ADC_CCR_VREFEN;
//Low Frequency Mode, V REFINT enable
ADC1->CHSELR |= ADC_CHSELR_CHSEL8 | ADC_CHSELR_CHSEL9 | ADC_CHSELR_CHSEL17;
//Channel Select 8 & 9
ADC1->IER |= ADC_IER_EOCIE | ADC_IER_EOSEQIE | ADC_IER_OVRIE | ADC_IER_EOSMPIE;
NVIC_EnableIRQ(ADC1_COMP_IRQn);
NVIC_SetPriority(ADC1_COMP_IRQn,3);
while(1)
{
ADC1->CR |= ADC_CR_ADEN;// | ADC_CR_ADSTART;
//Start the ADC conversion
while ((ADC1->ISR & ADC_ISR_ADRDY));
//Wait for stand up
while ((ADC1->ISR & ADC_ISR_EOC));
//wait for conversion flag
ADC1->CR |= ADC_CR_ADCAL;
//End of the calibration
delay(100);
uint16_t napiecie = ADC1->DR;
uint8_t hi = ((napiecie >> 8) & 0xff);
uint8_t lo = ((napiecie >> 0) & 0xff);
//DISABLE ADC
if ((ADC1->CR & ADC_CR_ADSTART) != 0){
ADC1->CR |= ADC_CR_ADSTP;
while ((ADC1->CR & ADC_CR_ADSTP) != 0);
}
ADC1->CR |= ADC_CR_ADDIS; //ADC disable command
while ((ADC1->CR & ADC_CR_ADEN) != 0);
ADC1->CR &= ~ADC_CR_ADSTART & ~ADC_CR_ADEN;
//ADC1->CR &= ~ADC_ISR_ADRDY; //Clear the ADRDY bit in ADC_ISR register by programming this bit to 1 (optional).
}
void ADC1_COMP_IRQHandler(void)
/* Interupt ADC */
{
if(ADC1->ISR & ADC_ISR_EOC){
uint16_t napiecie = ADC1->DR;
uint8_t hi = ((napiecie >> 8) & 0xff);
uint8_t lo = ((napiecie >> 0) & 0xff);
}
}
Two times you used lines like
ADC1->ISR &= ~ADC_ISR_EOCAL | ~ADC_ISR_AWD;
which looks really strange to me, as if the defines are 1 bit wide, which they most likely are, their bitwise OR is 0xFFFFFFFF (all F, no 0) and you're not changing the ISR and the CR (later in the code) at all! You need to use a bitwise AND, no?
ADC1->ISR &= ~ADC_ISR_EOCAL & ~ADC_ISR_AWD;
...
ADC1->CR &= ~ADC_CR_ADSTART & ~ADC_CR_ADEN;
Else some working code is available at https://electronics.stackexchange.com/questions/287073/get-internal-temperature-or-voltage-stm32l0/287162
https://github.com/ChristopherJD/STM32L053R8/blob/master/Intern_Project/ADC.c
and https://www.digikey.com/eewiki/pages/viewpage.action?pageId=47644832
I struggle masking a uint64_t variable by N bytes. I do not know N but I know it is 8 or less. My current code looks like this:
// uint64_t n is given
uint64_t mask;
for( mask = 0x00; n; n--) {
mask = mask<<8 | 0xFF;
}
for building the mask. What am I doing wrong here?
Edit:
The question was answered. Anyway, for better understanding:
I want a mask like this:
0x000000FF // or:
0x0000FFFF // or:
0x00FFFFFF
to take 1, 2 or more byte from the data. As the comments say, my code works! Maybe I had an bug anywere else!
It should work, according to the [operator precendence table1].
Still, it's more clear to write it as:
mask <<= 8;
mask |= 0xff;
or:
mask = (mask << 8) | 0xff;
You can also do it with a look-up table, of course.
I am not sure if I get the question right, but your mask looks like
0x00000000000000ff
0x000000000000ffff
0x0000000000ffffff
...
I assume that you want something like the following, to mask individual bytes:
0x00000000000000ff
0x000000000000ff00
0x0000000000ff0000
...
For this, you can use e.g. the following code:
for( mask = 0xff; n; n--) {
// Use the mask HERE
...
mask = mask<<8;
}
You could use this code snippet, to replace the bytenoth byte with dest mask, in src:
uint64_t replacemyByte(uint64_t src, uint64_t byteno,uint64_t dest)
{
uint64_t shift = (dest << (8 * byteno));
uint64_t mask = 0xff << shift;
return (~mask & src) | shift;
}
Or did I get the question wrong?