Implementing Task Scheduling and Memory Management in Embedded Systems
Time-Sliced Task Scheduling
Time-sliced scheduling involves structuring each task with its execution interval, counter, and function pointer. A timer generates interrupts at fixed intervals (e.g., every 1 second). When an interrupt occurs, each task's counter increments. When a task's counter matches its predefined interval, the associated function executes.
To handle task execution order, store task structures in an array and iterate through them sequentially. For each task meeting its execution condition, invoke its function via the function pointer.
NOR Flash vs. NAND Flash Comparison
- NOR Flash has slower write and erase speeds compared to NAND.
- Code can execute directly from NOR Flash, but not from NAND Flash.
- NOR offers higher reliability with a lower bit error rate.
- NOR uses separate address and data buses, allowing random byte access. NAND shares address and data lines, requiring page-based reads and block erasures. Booting from NAND requires copying initial data to SRAM.
- NOR has smaller capacity and higher cost per bit than NAND.
- NOR is typically used for code and critical data; NAND is suited for bulk data storage.
- NOR and NAND occupy different address spaces: NOR uses memory-mapped addresses, while NAND uses internal addressing.
- NAND supports bad block management in software; NOR becomes unusable if damaged.
Internal Flash Memory
STM32 microcontrollers (e.g., ZET6 with 512KB Flash, 64KB SRAM; C8T6 with 64KB Flash, 20KB SRAM) feature internal Flash starting at adress 0x08000000. The Flash memory includes program storage, system memory, and option bytes (for read/write protection and watchdog configuration).
Operations like full chip erase, page erase, and data write require unlocking the Flash, performing the operation, and relocking. Flash writes are half-word oriented; writing a word involves two half-word operations. When saving data from SRAM to Flash, erase the target page first. Since SRAM holds the status flag, copying SRAM to Flash restores the flag after erasure.
void Flash_Save_Data(uint32_t flash_addr, uint32_t *sram_data, uint32_t data_size)
{
Flash_Erase_Page(flash_addr);
for(uint32_t idx = 0; idx < data_size; idx++)
{
Flash_Write_Word(flash_addr + idx * 4, sram_data[idx]);
}
}
W25Q64 SPI Flash Memory
Key characteristics of W25Q64 include:
- Minimum erase unit: sector.
- Erase options: sector, block, or full chip.
- Maximum write unit: page (256 bytes). Writes exceeding one page require looping.
- Minimum write unit: 1 byte. Writes can range from 1 to 256 bytes per operation.
- Write operations must respect page boundaries; crossing a page requires waiting for the current page write to complete.
- Write latency must be handled in software.
EEPROM Operation
EEPROMs vary by model in storage capacity and page size. Write operations must respect page boundaries. Below is an example of a page-aware write function for I2C EEPROM:
uint8_t EEPROM_Write_Buffer(uint8_t *data_buf, uint16_t start_addr, uint16_t data_len)
{
uint16_t idx, retry_count;
uint16_t current_addr = start_addr;
for (idx = 0; idx < data_len; idx++)
{
if ((idx == 0) || (current_addr & (EEPROM_PAGE_SIZE - 1)) == 0)
{
I2C_Stop();
for (retry_count = 0; retry_count < 1000; retry_count++)
{
I2C_Start();
I2C_Send_Byte(EEPROM_DEV_ADDR | I2C_WRITE);
if (I2C_Wait_Ack() == 0) break;
}
if (retry_count == 1000) goto error;
I2C_Send_Byte((uint8_t)current_addr);
if (I2C_Wait_Ack() != 0) goto error;
}
I2C_Send_Byte(data_buf[idx]);
if (I2C_Wait_Ack() != 0) goto error;
current_addr++;
}
I2C_Stop();
return 1;
error:
I2C_Stop();
return 0;
}
The code checks if writing the first byte or starting a new page, then re-initiates the I2C sequence. The address increments after each byte, and page boundaries are handled automatically.
To initialize EEPROM only once, use a flag stored at the beginning of the EEPROM space. On startup, check this flag; if absent, write default values and set the flag. For float data, use a byte pointer to the float variable's address or a union for type conversion.
OLED Multi-Level Menu Implementation
Each menu page is represented as an array of structures, where each structure defines a menu item, including pointers to parent and child pages, and display attributes. Navigation requires tracking the cursor position and the index of the first displayed item.
When the cursor moves beyond the visible range, adjust the starting index and cursor position accordingly. For transitions between parent and child menus, save the parent's cursor and start index before switching, and restore them when returning.
SHT20 Humidity/Temperature Sansor
After sending a read command (device address + read bit), the SHT20 may not acknowledge immediately if a measurement is in progress. Use a polling loop to wait for acknowledgment:
do
{
Delay_Microseconds(8);
I2C_Start();
I2C_Send_Byte(SHT20_READ_ADDR);
Set_SDA_High();
Set_SCL_High();
}
while(Read_SDA_State());
Set_SCL_Low();