I'm trying to learn how to write drivers for GPIO pins in STM32F4 Discovery. I was going through the tutorials and I came across this line:
static void hal_gpio_configure_pin_mode (GPIO_TypeDef *GPIOx, uint16_t pin_no, uint32_t mode)
{
GPIOx->MODER |= (mode << (2* pin_no));
}
I am relatively new to embedded systems and don't know what GPIOX->MODER |= (mode << (2* pin_no)); does. Also, I don't know why pin_no is 16 bit while mode is 32 bit. I know that << is the left shift bitwise operator. But I still don't get the complete context.
Can anybody explain all this?
Trying to explain the line GPIOx->MODER |= (mode << (2* pin_no));:
GPIOx is a pointer to a structure
GPIOx->MODER accesses the member MODER inside this structure
x |= y is an abbreviation of x = x | y, which means "perform a logic OR of x and y, and write the result back to x
mode << (2* pin_no) means left-shift the content of variable mode by twice pin_no bits.
Hence, the line means "take the content of GPIOx->MODER, bitwise-OR it with the left-shiftet content of mode.
Related
I'm not sure if this is happening when assigning a variable specifically but when debugging the assembly code, the compiler executes RJMP $+0000 where it hangs the program.
EDIT: I added included libraries if that's relevant
#define __DELAY_BACKWARD_COMPATIBLE__
#define F_CPU 8000000UL
#include <avr/io.h>
#include <avr/delay.h>
#include <stdint.h>
void ReadTemp(uint8_t address){
ADCSRA = ADCSRA | 0b10000111; //enable ADC, CLK/128 conversion speed
ADMUX = ADMUX | 0b01000000; //Use internal 2.56V Vref and PA0 as input, right-hand justified
ADCSRA |= (1 << ADSC); //start conversion
while(!(ADCSRA & (1 << ADIF))) {} // wait until process is finished;
uint8_t low_value = ADC & 0x00FF;
// or low_value = ADCL;
uint8_t high_value = ADC & 0xFF00; //problem here
...
}
I don't know what any of this is doing, but I do see an error in the bitwise math.
uint8_t low_value = ADC & 0x00FF;
uint8_t high_value = ADC & 0xFF00; //problem here
low_value and high_value are both 8 bits (uint8_t). I am going to go out on a limb here and say ADC is 16 bit. For high_value, you are anding ADC with 0xFF00 then truncating the value to 8 bit. high_value will always be zero.
What should be done is:
uint8_t high_value = (ADC & 0xFF00) >> 8;
This will grab the left byte of ADC and shift it right by 8 bits then assign it to the high_value byte storage giving you the correct value.
How you are doing low_value is correct. As a matter of fact, you could simply do:
uint8_t low_value = ADC;
There is something somewhat suboptimal here:
uint8_t low_value = ADC & 0x00FF;
You are reading ADC, which is a 16-bit register, implemented as a pair
of 8-bit registers. As shown in the disassembly, this requires two in
instructions, one per byte. And then you are just throwing away one of
those bytes. You may think that the compiler is smart enough to avoid
reading the byte it is going to discard right away. Unfortunately, it
cannot do that, as I/O registers are declared as volatile. The
compiler is forced to access the register as many times as the source
code does.
If you just want the low byte, you should read only that byte:
uint8_t low_value = ADCL;
You then wrote:
uint8_t high_value = ADC & 0xFF00;
As explained in the previous answer, high_value will be zero. Yet the
compiler will have to read the two bytes again, because the I/O register
is volatile. If you want to read the high byte, read ADCH.
But why would you want to read those two bytes one by one? Is it to put
them back together into a 16-bit variable? If this is the case, then
there is no need to read them separately. Instead, just read the 16-bit
register in the most straight-forward fashion:
uint16_t value = ADC;
A long time ago, gcc didn't know how to handle 16-bit registers, and
people had to resort to reading the bytes one by one, and then gluing
them together. You may still find very old example code on the Internet
that does that. Today, there is absolutely no reason to continue
programming this way.
Then you wrote:
//problem here
Nope, the problem is not here. That is not what generated the rjmp
instruction. The problem is probably right after that line, in the code
you have chosen not to post. You have some bug that manifests itself
only when optimizations are turned on. This is typical of code that
produces undefined behavior: works as expected with optimizations off,
then does weird “unexplainable” things when you enable optimizations.
I wrote a simple program to generate PWM wave with 50% duty cycle. Then I went for debugging in AtmelStudio. All registers except OCR0 were assigned there respective values. Why OCR0 not assigned any value.
ATmega32, Fast PWM.
#include <avr/io.h>
int main(void)
{
DDRB = (1 << PB3);
TCCR0 |= (1 << WGM01) | (1 << WGM00) | (1 << COM01);
OCR0 = 127;
TCCR0 |= (1 << CS02);
return 0;
}
So anyway.
You're using the 8-bit counter0 on your Atmega32. Let's see how you set it up:
// Set Pin B3 as output, others as input
DDRB = (1 << PB3);
// Set Clear on compare match + Fast PWM mode + Counter stopped
TCCR0 |= (1 << WGM01) | (1 << WGM00) | (1 << COM01);
// Set comparator value to 127
OCR0 = 127;
// Enable clkIO/256 from prescaler, turning on the counter
TCCR0 |= (1 << CS02);
Okay. First, a few things:
On initial setup, you usually want to assign the value and not or it, to be certain of its state.
Even after, setting it instead of or-ing it avoids a useless read. No impact on behavior for this register, but might be a bit better for performance.
The documentation recommends only enabling the output after you have set it up properly, to avoid spurious output. So you should move the first line last.
I'll be reading from that version of the datasheet.
Now, in fast PWM mode, according to table 38, and 40, the counter behaves like this:
It counts from BOTTOM to MAX (0 to 0xFF).
OCR0 is only used to toggle OC0 pin, not to reset the counting.
OCR0 has double-buffering. Its actual value is not updated until next cycle.
This might be your issue. If any of those are true:
Counter doesn't start properly (could happen if CS2-0 are not correct due to or-ing them instead of setting them).
Counter is stopped early (because your program ends and if the studio detects it, it could disable it at that point - I d'ont use the studio so I cannot really tell).
Then it is possible the value you write to the double buffer never makes it to the actual register. Alas the datasheet doesn't explain in detail how this is handled. Nor does it tell whether reading OCR0 while double buffering is active returns current value or awaiting value.
I want to read and write from/to an unsigned char according to the table below:
for example I have following variables:
unsigned char hsi_div = 0x01; /* HSI/2 */
unsigned char cpu_div = 0x05; /* Fmaster/32 */
I want to write hsi_div to bits 4,3 and cpu_div to bits 2,1,0 (imagine the whole char is named CLK_DIVR):
CLK_DIVR |= hsi_div << 4; //not correct!
CLK_DIVR |= cpu_div << 2; //not correct!
And lets say I want to read the register back to make sure I did it correct:
if( ((CLK_DIVR << 4) - 1) & hsi_div) ) { /* SET OK */ }
if( ((CLK_DIVR << 2) - 1) & cpu_div) ) { /* SET OK */ }
Is there something wrong with my bitwise operations!? I do not get correct behaviour.
I assume CLK_DIVR is a hardware peripheral register which should be qualified volatile. Such registers should be set up with as few writes as possible. You change all write-able bits, so just
CLK_DIVR = (uint8_t)((hsi_div << 3) | (cpu_div << 0));
Note using fixed width type. That makes mentioniong it is an 8 bit register unnecessary. According to the excerpt, the upper bits are read-only, so they are not changed when writing. The cast keeps the compiler from issuing a truncation warning which is one of the recommended warnings to always enable (included in -Wconversion for gcc).
The shift count is actually the bit the field starts (the LSbit). A shift count of 0 means "no shifting", so the shift-operator is not required. I still use it to clarify I meant the field starts at bit 0. Just let the compiler optimize, concentrate on writing maintainable code.
Note: Your code bit-or's whatever already is in the register. Bit-or can only set bits, but not clear them. Addiionally the shift counts were wrong.
Not sure, but if the excerpt is for an ARM Cortex-M CPU (STM32Fxxxx?), reducing external bus-cycles becomes more relevant, as the ARM can take quite some cycles for an access.
For the HSIDIV bit fields you want:
hw_register = (hw_register & 0x18) | (hsi_value & 0x03) << 0x03;
This will mask the value to 2 bits wide then shift to bit position 3 and 4.
The CPUDIV fields are:
hw_register = (hw_register & 0x7) | (cpu_value & 7);
Reading the register:
hsi_value = (hw_register & 0x18) >> 3;
cpu_value = hw_register & 0x07;
Just
CLK_DIVR |= hsi_div << 3;
CLK_DIVR |= cpu_div << 0;
Since hsi_div is a 2-digit binary, you have to move it three positions to skip the CPUDIV field. And the cpu_div is already at the end of the field.
I am currently programming raspberry pi.
I wanted to get clear out some doubts, please can anybody help.
Here is the code snippet.
#define GPIO_BASE 0x20200000UL
gpio = (unsigned int*)GPIO_BASE; gpio[GPIO_GPFSEL1] |= (1 << 18);
This code is from http://www.valvers.com/embedded-linux/raspberry-pi/step01-bare-metal-programming-in-cpt1
I do understand the functionality of the code to switch on and switch off the LED .
I have problem understand the these statements
gpio = (unsigned int*)GPIO_BASE; gpio[GPIO_GPFSEL1] |= (1 << 18);
First you have some address in memory.
define GPIO_BASE 0x20200000UL
Under this address exists a control structure for GPIO. In your case it's just an array of ints. Writing a value to a certain field of that structure makes GPIO set its pins.
gpio = (unsigned int*)GPIO_BASE;
You select some register in your structure (the address (unsigned int*)GPIO_BASE + GPIO_GPFSEL1) and you set the 18th bit on.
gpio[GPIO_GPFSEL1] |= (1 < < 18);
The GPIO will likely respond with setting one of its pins to high state. The LED attached to that pin will start glowing.
Well ...
The first statement:
gpio = (unsigned int*)GPIO_BASE;
sets the pointer variable gpio equal to the value of GPIO_BASE, and also casts the latter to a pointer type.
The second
gpio[GPIO_GPFSEL1] |= (1 << 18);
does a bitwise OR of the value in gpio[GPIO_GPFSEL1] with the constant value 1 << 18. This "turns on" bit 18 (counting from 0) in the register GPIO_GPFSEL1.
Remember that in C, array indexing a[b] is the same as *(a + b), i.e. it's a pointer addition and dereferencing.
After
gpio = (unsigned int*)GPIO_BASE;
gpio points to 0x20200000 memory address. This is "The base address of the GPIO peripheral (ARM Physical Address)".
Article that you've linked says that:
Back to the processor manual and we see that the first thing we need
to do is set the GPIO pin to an output. This is done by setting the
function of GPIO16 to an output. Bits 18 to 20 in the ‘GPIO Function
Select 1′ register control the GPIO16 pin.
Statement
#define GPIO_GPFSEL1 1
gpio[GPIO_GPFSEL1] |= (1 << 18);
breaks down to:
gpio[1] = gpio[1] | (1 << 18);
So, address (0x20200000 + sizeof(unsigned int)) is dereferenced and OR operator sets the bit 18 to 1.
I am learning program AVR uCs.
An example code snippet contains this line:
DDRC |= (0 << 0) | (0 << 1); // PIN C0, C1 as input for buttons
I don't understand what sense
(0 << 0)
makes and in general what this line logically does.
I know what the DDRC is I only want to understand this logical operation.
May be the comment helps.
The code does nothing and might be wrong.
The author could have meant
DDRC |= (1 << 0) | (1 << 1);
which is short for
DDRC |= 3;
which reads the DDRC, sets the bottommost two bits, and writes that value back. The syntax using << and | attempts to make that clearer.
An alternative interpretation would be that the author intends to clear these two bits. In that case, the code is wrong, because it doesn't do that.
If the DDRC is the Data Direction Register for port C, chances are that writing a zero bit switches the direction to input, in which case the intention appears to be clearing the bits.
The appropriate code for that would be
DDRC &= ~( (1 << 0) | (1 << 1) );