A User-Friendly Embedded Design Framework

    Follow and star the public account for exciting content

Source: https://gitee.com/MacRsh/mr-library

Introduction to mr-library

MR framework is a lightweight framework designed specifically for embedded systems. It fully considers the demands of embedded systems in terms of resources and performance. By providing standardized device management interfaces, it greatly simplifies the difficulty of embedded application development and helps developers quickly build embedded applications.

The framework provides standardized interfaces for opening (open), closing (close), controlling (ioctl), reading (read), and writing (write). It decouples the application from the underlying hardware drivers, allowing applications to operate without understanding the implementation details of the drivers.

When hardware changes, only the underlying drivers need to be adapted, allowing applications to seamlessly migrate to new hardware. This greatly enhances software reusability and scalability in response to new hardware.

A User-Friendly Embedded Design Framework
Project Structure Diagram

Key Features

  • Standardized device access interfaces
  • Decoupling of application and driver development
  • Simplified development of underlying drivers and applications
  • Lightweight and easy to get started with, low resource consumption
  • Modular design, with decoupled parts developed independently, extremely low hardware migration costs
  • Supports usage in bare-metal and operating system environments

Main Components

  • Device framework: provides standardized device access interfaces
  • Memory management: dynamic memory management
  • Tools: common data structures such as linked lists, queues, balanced trees, etc.
  • Various functional components

Standardized Device Interfaces

All operations on devices can be accomplished through the following interfaces:

Interface Description
mr_dev_register Register device
mr_dev_open Open device
mr_dev_close Close device
mr_dev_ioctl Control device
mr_dev_read Read data from device
mr_dev_write Write data to device

Example:

struct mr_spi_dev spi_dev;

int main(void)
{
    /* Register SPI10 device (CS active low) to SPI1 bus */
    mr_spi_dev_register(&spi_dev, "spi1/spi10", 0, MR_SPI_CS_ACTIVE_LOW);

    /* Open SPI10 device under SPI1 bus */
    int ds = mr_dev_open("spi1/spi10", MR_OFLAG_RDWR);
    
    /* Send data */
    uint8_t wr_buf[] = {0x01, 0x02, 0x03, 0x04};
    mr_dev_write(ds, wr_buf, sizeof(wr_buf));
    
    /* Receive data */
    uint8_t rd_buf[4] = {0};
    mr_dev_read(ds, rd_buf, sizeof(rd_buf));
    
    /* Close device */
    mr_dev_close(ds);
}

Configuration Tool

MR provides a Kconfig visual configuration tool, allowing developers to configure without delving into the source code.

Kconfig automatically generates configuration option interfaces based on the configuration file. Developers can choose the functionalities they need to enable and set relevant parameters through simple operations.

A User-Friendly Embedded Design Framework
Configuration Tool
A User-Friendly Embedded Design Framework
Configuration Tool 1

Quickly trim the required functionalities by modifying parameters. After configuration, the configuration file is automatically generated through a Python script.

Directory Structure

Name Description
bsp Board Support Package
components Components
device Device Files
document Documentation
driver Driver Files
include Library Header Files
source Library Source Files
Kconfig Configuration File
kconfig.py Automatic Configuration Script
LICENSE License

Getting Started

Configuring the Kconfig Environment

Note: Kconfig is not mandatory, but recommended (installation and configuration are very quick, and subsequent tutorials will take Kconfig as an example).

  1. Verify if Python is installed by running python --version in the command line to check the Python version (Kconfig relies on python, please install it if not present).

  2. Install Kconfig using the following command in the command line:

    python -m pip install windows-curses
    python -m pip install kconfiglib
    
  3. Run menuconfig -h in the command line to verify if the installation was successful.

Importing the Framework into the Project

  1. Download the latest version of the source code from Gitee or Github repositories to your local machine.

  2. Import the source code into the directory where your project is located. For example, in an STM32 project:

    A User-Friendly Embedded Design Framework
    Project Directory
  3. If the chip you are using has already been adapted with BSP, please refer to the configuration tutorial in the corresponding BSP to complete the BSP configuration.

  4. Remove unnecessary files in the bsp, document, and module directories (if GIT is not needed, you can also remove the .git file). After completion, the directory structure will look as follows:

    A User-Friendly Embedded Design Framework
    Project Directory 1
  5. Add the files to your IDE (most IDEs can automatically recognize files under the project path, so this step may not be necessary). For example, in keil:

    A User-Friendly Embedded Design Framework
    Project Directory Keil

    Add all files from the source, device, and driver directories.

Configuring Menu Options

  1. Open the command line tool in the mr-library directory and run menuconfig for menu configuration.

    A User-Friendly Embedded Design Framework
    Project Directory 2

    Note: After adding the corresponding chip driver, Device configure and Driver configure will be displayed. Please refer to the tutorial under BSP for Driver configure.

  2. Select Device configure and press enter to enter the menu, configuring functionalities as needed.

    A User-Friendly Embedded Design Framework
    Project Directory 3
  3. After configuration is complete, press Q to exit the menu configuration interface and press Y to save the configuration.

Generating Configuration Files

  1. Open the command line tool in the mr-library directory and run python kconfig.py to automatically generate the configuration file mr_config.h.

Adding Include Paths

  1. Add the include path of mr-library in the compiler, for example in keil:

    A User-Friendly Embedded Design Framework
    Project Directory 4
  2. Configure automatic initialization (GCC environment), find the linking script file under your project with the suffix .ld (usually link.ld), and add the following code to the script file: Note: If you are in an environment like keil that can automatically generate linking scripts, please skip this step.

    /* mr-library auto init */
    . = ALIGN(4);
    _mr_auto_init_start = .;
    KEEP(*(SORT(.auto_init*)))
    _mr_auto_init_end = .;
    

    Example:

    A User-Friendly Embedded Design Framework
    Project Directory 5
  3. Configure GNU syntax. If you are using a non-GCC compiler, please enable GNU syntax. For example, in keil:

    AC5:

    A User-Friendly Embedded Design Framework
    Project Directory 6

    AC6:

    A User-Friendly Embedded Design Framework
    Project Directory 7
  4. Introduce #include "include/mr_lib.h" in your project.

  5. Add the mr_auto_init(); automatic initialization function in the main function.

Let’s Light Up a Light

#include "include/mr_lib.h"

/* Define LED pin (PC13)*/
#define LED_PIN_NUMBER                  45

int main(void)
{
    /* Automatic initialization */
    mr_auto_init();

    /* Open PIN device */
    int ds = mr_dev_open("pin", MR_OFLAG_RDWR);
    /* Set to LED pin */
    mr_dev_ioctl(ds, MR_CTL_PIN_SET_NUMBER, mr_make_local(int, LED_PIN_NUMBER));
    /* Set LED pin to push-pull output mode */
    mr_dev_ioctl(ds, MR_CTL_PIN_SET_MODE, mr_make_local(int, MR_PIN_MODE_OUTPUT));

    while(1)
    {
        /* Turn on LED */
        mr_dev_write(ds, mr_make_local(uint8_t, MR_PIN_HIGH_LEVEL), sizeof(uint8_t));
        mr_delay_ms(500);
        mr_dev_write(ds, mr_make_local(uint8_t, MR_PIN_LOW_LEVEL), sizeof(uint8_t));
        mr_delay_ms(500);
    }
}

Hello World

#include "include/mr_lib.h"

int main(void)
{
    /* Automatic initialization */
    mr_auto_init();

    /* Open Serial-1 device */
    int ds = mr_dev_open("serial1", MR_OFLAG_RDWR);
    /* Output Hello World */
    mr_dev_write(ds, "Hello World\r\n", sizeof("Hello World\r\n"));
    
    while(1);
}
Copyright Statement:This article is sourced from the internet, freely conveying knowledge, and the copyright belongs to the original author. If there are copyright issues, please contact me for deletion.

‧‧‧‧‧‧‧‧‧‧‧‧‧‧‧‧ END ‧‧‧‧‧‧‧‧‧‧‧‧‧‧‧

Follow my WeChat public account, reply "Join Group" to join the technical exchange group as per the rules.

Click "Read Original" for more shares, welcome to share, collect, like, and see.

Leave a Comment