I am trying to rewrite the code from AVR to STM32. How to translate this code into STM32?
#define READ_IO PIND & (1 << PD4)
volatile unsigned char data_in = 0;
data_in = (READ_IO) >> PD4;
I use STM32CubeIDE
Assuming pin4 on port D.
data_in = !!(GPIOD -> IDR & (1 << 4));
Related
I have a custom board with device LPC1768. While every other functionalities (such as LCD on SPI, Ethernet, I2C EEPROM, etc.) are OK,
for some reason, while I can turn ON and OFF LEDs on the GPIO2 but I can't do the same for the pins on the GPIO1. Maybe I shouldn't blame whole GPIO1 (or myself) but at least the part I try to use.
If I connect a button on one of the the GPIO1 pins (with internal pull-ups and as an OUTPUT)
I can read the button inputs as it should be.
Here is the definition part as per the user manual;
#define FIO_BASE_ADDR (0x2009C000)
#define FIO1CLR (*(volatile unsigned int *)(FIO_BASE_ADDR + 0x3C))
#define FIO2CLR (*(volatile unsigned int *)(FIO_BASE_ADDR + 0x5C))
#define FIO1SET (*(volatile unsigned int *)(FIO_BASE_ADDR + 0x38))
#define FIO2SET (*(volatile unsigned int *)(FIO_BASE_ADDR + 0x58))
While a LED on the pin P2.5 turns ON and OFF as it should be;
FIO2SET = (1uL << 5); // P2.5
FIO2CLR = (1uL << 5); // P2.5
A LED on P1.18 doesn't turn ON;
FIO1SET = (1uL << 18); // P1.18
In order to test all the LEDs connected to the GPIO1 pins, I wrote two lines of code using LPC17xx.h and then proofed that it works, all the LEDs are turning ON and OFF accordingly.
LPC_GPIO1->FIOSET = 0xffffffff;
LPC_GPIO1->FIOCLR = 0xffffffff;
Any input highly appreciated.
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;
Im trying to display A on TERA TERM simulator but when i run my code on ATMEL STUDIO 7 the code doesn't stop running.
This is my code below i am running the program on the simulator tool available on atmel studio 7 and i believe i am configuring the UART correctly
#include <avr/io.h>
void configureUART(void);
void sendUART(unsigned char);
int main(void)
{
configureUART();
sendUART('A');
}
void sendUART(unsigned char transmitByte)
{
while ((UCSRA & (1 << UDRE))== 0);
// Data register is ready, transmit out the byte.
UDR = transmitByte;
}
void configureUART()
{
//Baud Rate Config 9600 => 0x4D
UBRRH = 0x00;
UBRRL = 0x4D;
//Need to use UCSRC Register w/ asynchronous op. and 1 stop bit w/ 8 data bits
UCSRC = (1 << URSEL) | (0 << USBS) | (1 << UCSZ0) | (1 << UCSZ0) ;
//Transmit and Receive
UCSRB = (1 << RXEN) | (1 << TXEN);
}
this is my code
#include "LPC17xx.h" // Device header
#include "GPIO_LPC17xx.h" // Keil::Device:GPIO
uint32_t voltag1 = 0 ;
uint32_t voltag2 = 0 ;
volatile uint32_t adstat;
int blink=1;
int main()
{
//Config timer
LPC_TIM1->MCR=2;
LPC_TIM1->MR0=20000000; //Match Resgister
LPC_TIM1->TCR=1;
LPC_TIM1->EMR = 0x00000030 ;
//Config ADC
LPC_PINCON->PINSEL1 |= (1 << 14) | (1 << 16); // connect pin to ADC
LPC_SC->PCONP |= ((1 << 12)); //enable power of ADC
LPC_ADC->ADCR = 0x06202001; //initialaze ADC
LPC_ADC->ADINTEN = 0x00000100; // global interup
NVIC_EnableIRQ(ADC_IRQn);
GPIO_SetDir(3,25,GPIO_DIR_OUTPUT);
while(1) {}
}
void ADC_IRQHandler(void)
{
adstat = LPC_ADC->ADSTAT; /* Read ADC clears interrupt */
blink++;
GPIO_PinWrite(3,25,blink%2);
voltag1 = (LPC_ADC->ADGDR >> 4) & 0xFFF;
//voltag2 = (LPC_ADC->ADDR1 >> 4) & 0xFFF;
}
when i use LPC_ADC->ADGDR it work fine but when i use LPC_ADC->ADDR1 its not working , why?
i used MAT for ADC interup
and when i use LPC_ADC->ADGDR everything works fine
but when i use LPC_ADC->ADDR1 for reading its not working and not change with MAT edge
There are way too many magic numbers in your code. Please use the corresponding defines for all those bits. This code is unreadable as is.
There is a wrong comment in your code, the interrupt flag for ADGDR is not cleared on ADSTAT read. Only a read of ADGDR clears it, and thats why your code does not work with ADDR1.
Had you used the definition to set ADINTEN, you might have spotted your error sooner. That flag is named ADGDINTEN and corresponds to the flag in ADGDR only.
You should enable IRQ of ch1 by:
LPC_ADC->ADINTEN = 1 << 1; //0x0002
I am trying to transmit a byte on the uart of an attiny2313 but the transmit hangs in the loop that waits until UDR is available.
I am using the internal 8MHz clock.
Uart configured for 9600baud 8bit 1stopbit
My init code is as following:
#define F_CPU 8000000UL
#define USART_BAUDRATE 9600UL
#define USART_UBBR_VALUE ((F_CPU / (USART_BAUDRATE << 4)) - 1)
UBRRL = (uint8_t)USART_UBBR_VALUE;
UBRRH = (uint8_t)(USART_UBBR_VALUE >> 8);
UCSRB = ((1 << TXEN) | (1<<RXEN));
UCSRC = ((1 << UCSZ1) | (1 << UCSZ0));
After init I enable global interrupts using sei().
Transfer:
while (!(UCSRA & (1<<UDRE)));
UDR = 'B';
It hangs on the while loop, when I remove power from the device, it finally breaks while loop on last moment and sents the B.
I have tried adding delay of 200ms after init but didn't work.
I use similar code for an atmega88 and this is working fine.
Anyone an idea why it stays in the while loop?