I am completely new to embedded programming, I'm examining the code below and trying to understand how it work, but I really got stuck.
The program is used to count and print out the numbers from 0 to 9.
So can someone please explain the line const uint8_t ? why do I need an array of heximal number here?
#include <avr/io.h>
#include <util/delay.h>
#include "debug.h"
const uint8_t segments[10] = {0xFC,0x60,0xDA,0xF2,0x66,0xB6,0xBE,0xE4,0xFE,0xF6};
int main(void) {
uint8_t i=0; //s
int g;
init_debug_uart0();
/* set PORT A pins as outputs */
DDRA = 0xFF;
for (;;) {
PORTA = segments[i];
printf("%d\n\r",i);
_delay_ms(1000);
if (i >=9) {
fprintf(stderr , "Count Overflow\n\r"); i = 0;
scanf("%d", &g);
}else
i++;
}
}
And a final question, does anyone know good sources to read about embedded programming? Currently i'm learning about the IIMatto, 8-bits processor and it has 32-registers, designed in Harvard architecture and has 1 level pipeline.
The const uint8_t segments[10] = {0xFC,0x60,0xDA, ... simple defines a constant 10-byte array of bytes.
Code does not need an array of hexadecimal, it could have been decimal.
But consider the benefit of
0xFC,0x60,0xDA,0xF2,0x66,0xB6,0xBE,0xE4,0xFE,0xF6
// versus
252,96,218,...
A casual inspection shows that the number of bits set in each byte is
6,2,5,5,...
This just happens to match the number of segments set in a 7-segment display of the digits 0,1,2,3 ...
Closer inspection of the bits set will detail which bit activate what segment.
Other methods could be employed to get this mapping of 7-segment to digit, but showing the data in hexadecimal is one step closer than decimal.
Perhaps code could be like (the proper segment mapping is TBD).
typedef enum {
LED7_a = 1 << 0,
LED7_b = 1 << 1,
LED7_c = 1 << 2,
LED7_d = 1 << 3,
LED7_e = 1 << 4,
LED7_f = 1 << 5,
LED7_g = 1 << 6,
LED7_dp = 1 << 7
} LED7_Segment_t;
/* ****************************************************************************
7 Segment Pattern
Layout
aaa
f b
f b
ggg
e c
e c
ddd dp
**************************************************************************** */
const uint8_t segments[] = {
/*'0*/ LED7_a | LED7_b | LED7_c | LED7_d | LED7_e | LED7_f ,
/*'1*/ LED7_b | LED7_c ,
/*'2*/ LED7_a | LED7_b | LED7_d | LED7_e | LED7_g,
/*'3*/ LED7_a | LED7_b | LED7_c | LED7_d | LED7_g,
/*'4*/ LED7_b | LED7_c | LED7_f | LED7_g,
/*'5*/ LED7_a | LED7_c | LED7_d | LED7_f | LED7_g,
/*'6*/ LED7_a | LED7_c | LED7_d | LED7_e | LED7_f | LED7_g,
/*'7*/ LED7_a | LED7_b | LED7_c ,
/*'8*/ LED7_a | LED7_b | LED7_c | LED7_d | LED7_e | LED7_f | LED7_g,
/*'9*/ LED7_a | LED7_b | LED7_c | LED7_d | LED7_f | LED7_g};
First of all, ask yourself where is segments used, what is it used for, how is it used?
Hints:
Where: Used to assign a value to PORTA
What: PORTA Is an output from an embedded system. Perhaps to an external device. segments is used to store outputs.
How: Each time around the loop, the value i is incremented. i is used as the index for segments when its value is assigned to PORTA.
Also: A hexadecimal number, specifically 2 digits long, is a byte which is 8 bits. Look on your microcontroller for up to 8 pins labelled "PORTA"
When writing to PORTA (an I/O port) you are concerned with the state of individual I/O lines associated with each bit.
To display a specific set of segments representing a digit on a 7-segment display, you have to write a specific bit pattern - one bit for each segment you wish to light. The segments array is indexed by the digit you want to display, and the value at that index represents the bit pattern on PORTA required to light the segments that represent that digit.
The reason hexadecimal is used is because there is a direct mapping of single hexadecimal digit to exactly four binary digits, so hex is a compact way of representing bit patterns. For an experienced embedded developer, mentally converting a bit-pattern to hex and vice versa becomes second nature. If the values were decimal, the representation would bear no direct relationship to the bit pattern, and the conversion or mental visualisation of the bit pattern less simple.
The hex digit to binary pattern conversion is as follows:
0 0000
1 0001
2 0010
3 0011
4 0100
5 0101
6 0110
7 0111
8 1000
9 1001
A 1010
B 1011
C 1100
D 1101
E 1110
F 1111
0xFC = 11111100
0x60 = 1100000
0xDA = 11011010
....
you need an array of hex numbers, most probably you have connected some sort of device to portA, and in this device
0xFC or 11111100 means display 0,(when portA pins 7,6,5,4,3,2, are high and 1,0 are low this device will display 0
0x60 or 11000000 means display 1(when PortA pins 7,6 are high and the rest low, this device will display 1.
and so on..
The memory locations in the microcontroller are 8 bits wide so 16 I/O will require two 8 bit registers called PORTA and PORTB. in your case its only 8bits wide ie. 8 I/O pins per PORTA, another 8 for PORTB and so on.
the outputs of these ports are controlled by the 8bits..
Suppose we wish to turn on an LED which we are going to connect to bit 4 on PORTB. We first of all have to instruct the microcontroller to ensure that PORTB bit 4 is an output.(the micro needs to know if ports are outputs are inputs you cant just plug stuff in)
in a pic micro you would say TRIA = 0x00010000 this tell the micro portB4 is an output.Now that we have said its an output, PORTA = 0b00010000 sets this portB4 to a high voltage, in other words this will illuminate the LED or whatever you have connected to the port.
PORTA = 0b00000000 // turns off PORTA outputs,
PORTA = 0b10000000 // turns on PORTA pin 7
The hexadecimal values its just a notation, the first letter represents the first 4 bits of your int and the other the other four bits because you are declaring a const uint8 variable wich means an unsigned integer of 8 bits, this is an integer but without sign, the bit of the sign is removed, so it can store 2^8 posibles values.
I'm just answering the first question. Hope it help!!
Related
I Have a PC Program that is communicating over a TCP/IP Connection to an Embedded board (Infineon XE169 (C166 Family)).
This PC Program request what data is stored on a certain address.
The PC Program is uC/Probe, and I cannot change how this program is working.
uC/Probe for example sends this message:
____________________________________________________________________________________________________________
| Prefix | Length |Pkt_nr|Unused| Format | read size | Address to read |Unused|Postfix|
|--------------------|-----------|------|------|-----------|-----------|----------------------|------|-------|
|0x75 0x43 0x50 0x72 | 0x00 0x08 | 0x00 | 0x00 | 0x02 0x00 | 0x04 0x00 | 0xDC 0x3E 0x61 0x00 | 0x00 | 0x2F |
|u C P r | 8 | 0 | 0 | 2 | 4 | 0x613EDC | 0 | / |
|____________________|___________|______|______|___________|___________|______________________|______|_______|
This is a message to request the data from address 0x613EDC and read 4 bytes from there.
When looking in the .map file I can see that at this location the OSTCBCurPtr variable is placed.
This variable is an OS_TCB* thus at the requested address is the address placed where this variable is pointing to.
I've now manually looked in the .map file what kind of variable is placed on the address. But can I get the variable type trough the C code on the Embedded board. All I want to know is if the object that lies on that specific location is a pointer or not, if it's an uint16_t, uint8_t, char or whatever is unimportant to me.
Background information, why I want to know this
The Embedded board will sent back the requested data to the uC/Probe program. But the pointers are stored in a strange way in the XE169 chip.
The pointer of above example is for example stored like this:
_______________________________________
| Address | 0 | 1 | 2 | 3 |
|-----------|------|------|------|------|
|0x00613EDC | 0xE6 | 0x1F | 0x84 | 0x01 |
|___________|______|______|______|______|
Because the value's are stored little endian this would result in the number
0x01841FE6.
This number is currently send back to uC/Probe. But his number isn't the correct location of the, a little calculation has to be done to get to the actual address location.
We have to take apart this 32bits number and split it into 2 16 bit numbers.
Then we get:
Hex: 0x0184 and 0x1FE6
Bits: 0b0000000110000100 and 0001111111100110
Now the 16 upper bits have to move 2 bits to the right. The 2 least significant bits of these upper 16 bits become the 2 most significant bits on the lower 16 bits.
This results into:
Hex: 0x0061 and 0x1FE6
Bits: 0b0000000001100001 and 0001111111100110
When we paste these 2 16 bit numbers back to the 32 bit number we have the address where the pointer is pointing to:
0x00611FE6
And this is the number I have to sent back to uC/Probe.
This calculation only has to happen for when uC/Probe requests pointers, for non pointers it just needs to send back the data read from the given address.
That's why I need to know if the requested data is a pointer, hopefully someone can help me with this.
I'm reading the Multiboot2 specification. You can find it here. Compared to the previous version, it names all of its structures "tags". They're defined like this:
3.1.3 General tag structure
Tags constitutes a buffer of structures following each other padded on u_virt size. Every structure has
following format:
+-------------------+
u16 | type |
u16 | flags |
u32 | size |
+-------------------+
type is divided into 2 parts. Lower contains an identifier of
contents of the rest of the tag. size contains the size of tag
including header fields. If bit 0 of flags (also known as
optional) is set if bootloader may ignore this tag if it lacks
relevant support. Tags are terminated by a tag of type 0 and size
8.
Then later in example code:
for (tag = (struct multiboot_tag *) (addr + 8);
tag->type != MULTIBOOT_TAG_TYPE_END;
tag = (struct multiboot_tag *) ((multiboot_uint8_t *) tag
+ ((tag->size + 7) & ~7)))
The last part confuses me. In Multiboot 1, the code was substantially simpler, you could just do multiboot_some_structure * mss = (multiboot_some_structure *) mbi->some_addr and get the members directly, without confusing code like this.
Can somebody explain what ((tag->size + 7) & ~7) means?
As mentioned by chux in his comment, this rounds tag->size up to the nearest multiple of 8.
Let's take a closer look at how that works.
Suppose size is 16:
00010000 // 16 in binary
+00000111 // add 7
--------
00010111 // results in 23
The expression ~7 takes the value 7 and inverts all bits. So:
00010111 // 23 (from pervious step)
&11111000 // bitwise-AND ~7
--------
00010000 // results in 16
Now suppose size is 17:
00010001 // 17 in binary
+00000111 // add 7
--------
00011000 // results in 24
Then:
00011000 // 24 (from pervious step)
&11111000 // bitwise-AND ~7
--------
00011000 // results in 24
So if the lower 3 bits of size are all zero, i.e. a multiple of 8, (size+7)&~7 sets those bits and then clears them, so no net effect. But if any one of those bits is 1, the bit corresponding to 8 gets incremented, then the lower bits are cleared, i.e. the number is rounded up to the nearest multiple of 8.
~ is a bitwise not. & is a bitwise AND
assuming 16 bits are used:
7 is 0000 0000 0000 0111
~7 is 1111 1111 1111 1000
Anything and'd with a 0 is 0. Anything and'd with 1 is itself. Thus
N & 0 = 0
N & 1 = N
So when you AND with ~7, you essentially clear the lowest three bits and all of the other bits remain unchanged.
Thanks for #chux for the answer. According to him, it rounds the size up to a multiple of 8, if needed. This is very similar to a technique done in 15bpp drawing code:
//+7/8 will cause this to round up...
uint32_t vbe_bytes_per_pixel = (vbe_bits_per_pixel + 7) / 8;
Here's the reasoning:
Things were pretty simple up to now but some confusion is introduced
by the 16bpp format. It's actually 15bpp since the default format is
actually RGB 5:5:5 with the top bit of each u_int16 being unused. In
this format, each of the red, green and blue colour components is
represented by a 5 bit number giving 32 different levels of each and
32786 possible different colours in total (true 16bpp would be RGB
5:6:5 where there are 65536 possible colours). No palette is used for
16bpp RGB images - the red, green and blue values in the pixel are
used to define the colours directly.
& ~7 sets the last three bits to 0
I have been going over a perl book i have recently purchased, and while reading I noticed a block of code that confused me..
use integer;
$value = 257;
while($value){
unshift #digits, (0..9,a..f)[$value & 15];
$value /= 16;
}
print digits;
the book mentions the purpose was to reverse the order of digits. however, new to perl I am having trouble figuring out what [$value & 15] is doing.
It's a bitwise and operation.
What it's doing is performing a bitwise and using the value of 15 and whatever value is contained in $value.
The resulting value is the decimal value that corresponds to the result of a bitwise and with the lower 4 bits of the value.
Ex:
$value = 21
which has a binary representation of: 0b10101
Performing a bitwise and with 15 means that any bits in $value will be zeroed if they are either outside the lower 4 bit range, or contain no 1's in the lower 4 bits.
The result is:
0b10101
&
0b 1111
-------
0b00101 = 5
Looking up the truth tables for performing bitwise operations will help with stuff like this in the future, but when performing an AND with any value, the result is only true, when both bits are 1, 0 otherwise.
V1 | V2 | V1 & V2
-----------------
0 | 0 | 0
0 | 1 | 0
1 | 0 | 0
1 | 1 | 1
What does the & mean in this code:
(number >> 9) & 0b111
I know about & in terms of pointers. But not sure how it works in the code above
Lets break it down:
(number >> 9) & 0b111
| | | | |
| | | | Binary '7'*
| | | Binary AND
| | Number to shift by
| Binary shift operator
Variable
We'll start with the expression in the parenthesis:
(number >> 9)
This performs a binary right-shift by 9 places. For example:
1101101010010011 will be shifted to become:
0000000001101101
The & symbol is Binary AND. Where the bits are both 1 in both of the source variables, the returned value will have those bits set:
01101
& 11010
= 01000
So your code shifts your number by 9 places and performs AND on the result against b111. As the three least significant bits are all set in the second input, the result of this operation will be the bits that are set in the bottom three bits of the shifted input.
Example:
number = 1101101010010011
number >> 9 = 0000000001101101
(number >> 9) & '111' = 0000000000000101
An alternate way of thinking about it is as follows: The line extracts bits 10-12 and returns them as the result.
XXXXbbbXXXXXXXXX -> bbb
A common use for this is to apply a mask to a value to extract the bits. E.g. some libraries allow you to pass parameters with enumerable types like this:
set_params(option_a | option_b);
which sets both option_a and option_b.
Whether a parameter is set can be read by:
set_params(unsigned int params)
{
if (params & option_a)
{ /* do option_a stuff */}
}
*assuming your compiler has a binary extension to the C spec. otherwise you could use 0x7 (hex 7) or just 7
It is the bitwise AND operator.
More info here:
Wikipedia link
& is Bitwise AND
The C operators are here:
https://en.wikipedia.org/wiki/Operators_in_C_and_C%2B%2B
I have been given the following bit of code as an example:
Make port 0 bits 0-2 outputs, other to be inputs.
FIO0DIR = 0x00000007;
Set P0.0, P0.1, P0.2 all low (0)
FIO0CLR = 0x00000007;
I have been told that the port has 31 LED's attached to it. I cant understand why, to enable the first 3 outputs, it is 0x00000007 not 0x00000003?
These GPIO config registers are bitmaps.
Use your Windows calculator to convert the hex to binary:
0x00000007 = 111, or with 32 bits - 00000000000000000000000000000111 // three outputs
0x00000003 = 11, or with 32 bits - 00000000000000000000000000000011 // only two outputs
Because the value you write to the register is a binary bit-mask, with a bit being one meaning "this is an output". You don't write the "number of outputs I'd like to have", you are setting 8 individual flags at the same time.
The number 7 in binary is 00000111, so it has the lower-most three bits set to 1, which here seems to mean "this is an output". The decimal value 3, on the other hand, is just 00000011 in binary, thus only having two bits set to 1, which clearly is one too few.
Bits are indexed from the right, starting at 0. The decimal value of bit number n is 2n. The decimal value of a binary number with more than one bit set is simply the sum of all the values of all the set bits.
So, for instance, the decimal value of the number with bits 0, 1 and 2 set is 20 + 21 + 22 = 1 + 2 + 4 = 7.
Here is an awesome ASCII table showing the 8 bits of a byte and their individual values:
+---+---+---+---+---+---+---+---+
index | 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 |
+---+---+---+---+---+---+---+---+
value |128| 64| 32| 16| 8 | 4 | 2 | 1 |
+---+---+---+---+---+---+---+---+