In this video, we will discuss how data is oriented in our code and data memory. Micro controllers have complex memory architectures. There are variety of memories being interconnected with the CPU. This include Register memory, peripheral memory, code and data memory. External core memory interfaces to the micro controller through a number of different Busses. This is important because a load store architecture requires that we do all of the processing in the CPU, after we have loaded data into the local general purpose registers. Once processed, we can then rewrite that data back to memory. The process to reading or writing a piece of data is not as simple as calling a load or a store. There's some specific orientation and alignment requirements for memory that need to be taken into account for our programs to work correctly Memory is oriented in a Byte addressable model. We have a 32 bit address space, which means we have over 4 billion unique addresses. Since each address represents a Byte, we have 4 gigabytes of address space. However, much of the data operations that we perform on a micro controller use more than one Byte. We often perform math with half words, words, floats, or doubles, a range of one to eight Bytes of data manipulation. This only becomes more complicated when we begin to define data structures. A data structure can contain any number of variables, each with different sizes. These can be integer types, floating point types, pointers, or even other structures. Structures are a high level software construct that is architecture independent, but they can be organized more efficiently by knowing how data is oriented in memory. The underlying instructions set architecture gives us three types of Load/Store instructions. These include byte, half-word and word length load stores. There are no instructions for bit manipulation or larger than word manipulation. Bit manipulation must be done with larger data types being loaded and stored or using bit banded memory regions. For larger data types we actually need to perform multiple loads to get the data into the CPU registers for processing. This means that if you tend the write programs with types that are bigger than the architecture word size, you're spending more CPU cycles performing loads in stores and additional processing on larger data types. This adds extra overhead to your data processing. What makes these loads and stores even more complicated is that they are designed to work on specific address alignments, meaning bytes, half-words and words are required to be oriented at certain address offsets depending on their data size. Alignment will have effects on both CPU efficiency and your memory efficiency. Aligned accesses make reading and writing to memory as efficient as possible, but they may potentially waste memory space. Unused memory is used to pad memory spots until the data type can be aligned. These bytes are refered to as padding. Unaligned memory will force the CPU to do more work to access data, but it will more efficiently pack your data into memory. This is referred to as packing data. For instance, bytes can be stored at any address without issue. Any address in memory space is byte addressable and therefore byte accesses are always aligned. There are exceptions for unused memory locations or the bit banded regions. However, half-words, words, and double words require certain address alignment. Half-words, must be stored at a two byte boundary. Meaning, half-words can only be stored when aligned to an even address. This will include all the addresses that end with hex, zero, two, four, six, eight, a, c, and e. Half-words at a maximum will waste one padded byte for them to be aligned. Words need to be aligned at four byte boundaries. These are addresses that can end in hex, zero, four, eight, or c. These can pad a maximum of three bytes. You can extend this to larger types like doubles. Double words must be aligned to an eight byte boundary, or addresses that end with zero or eight. Word alignment is the most efficient for a programmer, as it will reduce the amount of manipulation a CPU must perform on the data once it's inside the CPU. Further, CPU instructions for our arm architecture can vary in size, from two to four bytes. These are forced to be aligned at least a half-ward boundary, and cannot support unaligned accesses. If your application is looking to be optimized for speed, you'll want to make sure all your memory interactions are aligned. If you're looking to optimize for space, you'll want to try and pack all of your data. Unfortunately, you may have an architecture that does not support unaligned accesses. Meaning your load and store word instruction cannot be given any address. In such a case, multiple loads and extra processing will need to be done to read or write an unaligned access. Multiple stores will have to be done for an unaligned access as well. An example would be unaligned word that is aligned on a half-word boundary. In order to operate on this you would have to do two half-word loads. One for the upper half-word and one for the lower half-word. These loads would go into two separate registers. You would then have to shift the upper word two bytes up and combine it with a lower half-word register. This would require about four extra operations to interact with an unaligned memory access just to get into the registers for processing. This would be a lot of processing overhead compared to a single load instruction. Let us look at another example. Here we have a very simple data structure declared with three internal members. An 8-bit var1, a 32-bit var2, and an 8-bit var3. Now, depending on how you declare the structure and the architecture you're using, it can get allocated many different ways. If this structure was aligned and using fast standard data types, it could potentially take up the 12 bytes. This could take a minimum of six bytes if we force the structure to be packed. In order to specify packing or padding of a data item, we can apply a compiler attribute to variable or structure. Unfortunately, these attributes are not portable across compilers. But we will cover these in more detail later in the course. Alignment is an important concept with how we organize the data in memory. This applies to both code and data memory. An architecture is designed to interface with memory certain ways based on the instruction set, while an engineer might think they are writing code that is space efficient, they may have some performance issues. Knowing the implications of how you store data in memory can help you optimize and avoid potential bugs.