Embedded System is a very broad term. It may mean the micro controller without the operating system or "normal" computer with the OS.
Some examples:
- uC reading the sensors and controlling the water flow through the pipe.
- Raspberry Pi run under Linux controlling the drone (it is embedded into the drone)
- PC computer controlling the laser cutter .
- mainframe computer in a radio telescope system
So there is no one answer to your question.
uCs will be programmed completely different way than the RPi used in the drone.
But your question is probably about the uC systems I think.
uC systems are usually programming is sometimes called a "bare metal" because programmers do not have the immediate software (abstraction layer) between their application and the actual hardware. So they access the memory, hardware registers and another resources directly. Even operating systems used in the bare metal development (called RTOS-es) are not even similar to the normal OSes like Linux or Windows. They are more libraries linked together with the bare metal application and just provide mechanisms of task management and communication, synchronization and data exchange.
Some questions you asked in the comments
DMA - Direct memory access - allows data transfer between the memory and peripherals or memory with no use of the processor core. Some uC have very complicated DMA & event systems - for example the timer overflow can trigger the ADC which triggers the DMA transfer storing the converted data into the memory.
Linker Script - defines what, how and where is stored in the memory. They may me very complicated and instruct that code or data to include or exclude, and how to organize the program memory. Below you have an example of the linker script for the STM32 family uC
/* Entry Point */
ENTRY(Reset_Handler)
_estack = 0x10004000; /* end of RAM */
/* Generate a link error if heap and stack don't fit into RAM */
_Min_Heap_Size = 0x100; /* required amount of heap */
_Min_Stack_Size = 0x1000; /* required amount of stack */
/* Specify the memory areas */
MEMORY
{
RAM (xrw) : ORIGIN = 0x20000000, LENGTH = 64K
CCMRAM (rw) : ORIGIN = 0x10000000, LENGTH = 16K
FLASH (rx) : ORIGIN = 0x8000000 + 32K, LENGTH = 512K - 34K
}
_FLASH_SIZE = LENGTH(FLASH);
/* Define output sections */
SECTIONS
{
/* The startup code goes first into FLASH */
.isr_vector :
{
. = ALIGN(4);
_vectors_start = .;
KEEP(*(.isr_vector)) /* Startup code */
. = ALIGN(4);
_vectors_end = .;
} >FLASH
.sizedata :
{
. = ALIGN(4);
KEEP(*(.sizedata))
KEEP(*(.sizedata*))
. = ALIGN(4);
} >FLASH
.flashdata :
{
. = ALIGN(4);
KEEP(*(.rodata)) /* .rodata sections (constants, strings, etc.) */
KEEP(*(.rodata*)) /* .rodata* sections (constants, strings, etc.) */
. = ALIGN(4);
} >FLASH
/* The program code and other data goes into FLASH */
.text :
{
. = ALIGN(4);
*(.text) /* .text sections (code) */
*(.text*) /* .text* sections (code) */
*(.glue_7) /* glue arm to thumb code */
*(.glue_7t) /* glue thumb to arm code */
*(.eh_frame)
KEEP (*(.init))
KEEP (*(.fini))
. = ALIGN(4);
_etext = .; /* define a global symbols at end of code */
} >FLASH
/* Constant data goes into FLASH */
.rodata :
{
. = ALIGN(4);
*(.rodata) /* .rodata sections (constants, strings, etc.) */
*(.rodata*) /* .rodata* sections (constants, strings, etc.) */
. = ALIGN(4);
} >FLASH
.ARM.extab : { *(.ARM.extab* .gnu.linkonce.armextab.*) } >FLASH
.ARM : {
__exidx_start = .;
*(.ARM.exidx*)
__exidx_end = .;
} >FLASH
.preinit_array :
{
PROVIDE_HIDDEN (__preinit_array_start = .);
KEEP (*(.preinit_array*))
PROVIDE_HIDDEN (__preinit_array_end = .);
} >FLASH
.init_array :
{
PROVIDE_HIDDEN (__init_array_start = .);
KEEP (*(SORT(.init_array.*)))
KEEP (*(.init_array*))
PROVIDE_HIDDEN (__init_array_end = .);
} >FLASH
.fini_array :
{
PROVIDE_HIDDEN (__fini_array_start = .);
KEEP (*(SORT(.fini_array.*)))
KEEP (*(.fini_array*))
PROVIDE_HIDDEN (__fini_array_end = .);
} >FLASH
/* used by the startup to initialize data */
_sidata = LOADADDR(.data);
_ROMEND = .;
/* Initialized data sections goes into CCMRAM, load LMA copy after code */
.data :
{
. = ALIGN(4);
_sdata = .; /* create a global symbol at data start */
*(.data) /* .data sections */
*(.data*) /* .data sections */
. = ALIGN(4);
_edata = .; /* define a global symbol at data end */
} >CCMRAM AT> FLASH
_ROMSIZE = _ROMEND - ORIGIN(FLASH) + _edata - _sdata;
_siccmram = ORIGIN(CCMRAM);
_sconfig = _ROMSIZE;
_econfig = _sconfig + 2K;
.bss :
{
/* This is used by the startup in order to initialize the .bss secion */
_sbss = .; /* define a global symbol at bss start */
__bss_start__ = _sbss;
*(.bss)
*(.bss*)
*(COMMON)
. = ALIGN(4);
_ebss = .; /* define a global symbol at bss end */
__bss_end__ = _ebss;
} >CCMRAM
/* RAM section
*/
/* Uninitialized data section */
.dummy :
{
. = ALIGN(4);
*(.dummy)
*(.dummy*)
. = ALIGN(4);
} > RAM AT > FLASH
.ram :
{
. = ALIGN(4);
_sram = .; /* create a global symbol at ccmram start */
*(.ram)
*(.ram*)
. = ALIGN(4);
_eram = .; /* create a global symbol at ccmram end */
} >RAM
/* User_heap_stack section, used to check that there is enough RAM left */
._user_heap_stack (NOLOAD):
{
. = ALIGN(8);
PROVIDE ( end = . );
PROVIDE ( _end = . );
. = . + _Min_Heap_Size;
. = . + _Min_Stack_Size;
. = ALIGN(8);
} >CCMRAM
/* Remove information from the standard libraries */
/DISCARD/ :
{
libc.a ( * )
libm.a ( * )
libgcc.a ( * )
}
.ARM.attributes 0 : { *(.ARM.attributes) }
}
MMU - some uCs have memory management units - but usually this peripheral only protects some memory areas. As you do not have the OS, you also do not have the file system - so nothing like mmap exists.
#define SRAM_BASE ((uint32_t)0x20000000)
it only defines in the human readable form the address of something. In this case probably it is just the address of the beginning of the SRAM memory. Another example:
#define PERIPH_BASE ((uint32_t)0x40000000U)
#define APB2PERIPH_BASE (PERIPH_BASE + 0x00010000U)
#define SPI1_BASE (APB2PERIPH_BASE + 0x00003000U)
#define SPI1 ((SPI_TypeDef *) SPI1_BASE)
unsigned char *mem[10240];
is not probably typed as you'd want... Perhaps you meantunsigned char mem[10240];
– Antti Haapala