Bare metal programming in C for Raspberry pi - c

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.

Related

C - XMPLAB DDRD/DDRB not assignable error

I am working on a project translating some Arduino code of a RFM Hopper Transmissor to C, but there are few concepts that I don't fully understand like the DDRB and DDRD.
For example, I call these two methods:
InputSDIO();
OutputSDIO();
which are declared in another file with these lines:
#define InputSDIO() (DDRB &= (~_SDIO))
#define OutputSDIO() (DDRB |= (_SDIO))
and it gives me the following error
error: expression is not assignable
Furthermore, I also get the same error from this call,
RX_ANTOut();
which is defined in another file with the following line:
#define RX_ANTOut() (DDRD |= (RX_ANT))
As I said, the code comes from an Arduino project of a transmissor. If you need any more info or if my question could be more detailed feel free to ask.
In DDRB and DDRD the DDR is data direction register and it determines if a pin is an input or output (the uC is an Atmel AVR), DDRB is the DDR of port B, DDRD of port D. SDIO is a port configuration that is usually implemented as a bitmask. The operators &= and |= have the same meaning as +=, -=,... so i.e. a &= b means a = a & b and so DDRB &= (~SDIO) is equivalent to DDRB = DDRB & (~SDIO) what is a common way of bitmasking the ~ is logical negation & is logical AND, | is logical OR.
SDIO is an 8 bit (? what AVR model exactly is this ? ) binary number something like 0b01110010 that masks the pins of the port, i.e. port D
https://blog.podkalicki.com/bit-level-operations-bit-flags-and-bit-masks/,
What is Bit Masking?
In the datasheet of the ATmega128RFA1 (https://cdn.sparkfun.com/datasheets/Dev/AVR/ATmega128RFA1_Datasheeta.pdf) the function of the DDRs is on page 191 in chapter 14.2.2 Configuring the Pin

Bitwise operations in C coding

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.

AVR (debugging) PWM generation

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.

How to read/write into specific bits of a unsigned char

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.

C shift zero or shift by zero

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) );

Resources