Select Page

Customized Library for TIVA Board with standardized peripheral function format

I.INTRODUCTION

ARM has become the leading architecture in the microcontroller world, especially with its Cortex-M series. These processors are widely used due to their performance and low power consumption. However, while the
processor core is common across different vendors, each microcontroller manufacturer designs its own way of connecting and using peripherals like timers, GPIOs, and UARTs. This creates differences in how we program them.
One major issue is the lack of standardization in peripheral access. Although the processor may be the same, the way to interact with peripherals can vary greatly between manufacturers. This leads to low code portability—code written for one microcontroller often needs to be heavily rewritten for another, even if both use ARM cores.
Additionally, each vendor provides its own software development kit (SDK) and peripheral drivers, which are not consistent across platforms. This inconsistency makes embedded programming harder for developers who want to switch between different microcontroller brands or develop cross-platform applications. As a result, embedded development becomes more tedious and fragmented. Developers must spend time learning new APIs and register definitions for each platform. A more unified standard for peripheral programming could help make development smoother and more efficient across ARM-based microcontrollers.

Currently we have three major embedded software’s which are platform independent:

1.0 Proposed Solution:

Developed a customized library specifically for the TIVA microcontroller board. This library includes low-level library includes low-level drivers for essential peripherals such as GPIO (digital input/output), UART (serial
communication), timers, PWM, SPI, and I2C. Alongside these, I built higher-level libraries for commonly used components like LCD displays, seven-segment displays, and D1307, making it easier to interface hardware
components.
The goal is to adopt an Arduino-style development approach, using simplified and intuitive function names such as Digital.pinMode() and Serial.println(). This not only makes the code more readable but also lowers the
entry barrier for beginners. I aim to maintain a standardized function format that promotes code portability across different microcontrollers and platforms. Ultimately, this library will serve as a helpful tool for rapid
prototyping, enabling developers to build and test embedded applications more efficiently.

II. Tiva Lib File structure:

The current file structure is organized in a modular and scalable manner to support clean development and easy portability. It consists of distinct directories and files, each serving a specific role in the overall system
architecture.
1. Drivers: This folder contains architecture-independent peripheral drivers that define standard interfaces for common hardware functionalities such as digital I/O (Digital), serial communication (Serial), Pulse Width Modulation (PWM), Analog-to-Digital Conversion (ADC), I2C communication (I2cMaster), and others. These drivers are written in a generic format and do not rely on any specific microcontroller architecture, making them reusable across different platforms as long as the appropriate backend support is provided.
2 Lib: This directory hosts higher-level libraries that are built on top of the driver layer. These libraries simplify the use of specific hardware modules like seven-segment displays (seven_segment.h), character LCDs (lcd.h), and real-time clocks like the DS1307 (ds1307.h). They rely on the functionality provided by the drivers, but their implementation remains architecture-agnostic, ensuring easy portability as long as the required drivers are available.
3 Util: The utility folder includes helper libraries that are mostly independent of the hardware drivers or the Lib layer. These include commonly used components such as ringbuf.h for circular buffer operations and standard utilities for string manipulation or memory operations. Some exceptions exist, like delay.h, which may depend on architecture-specific timers to function correctly.
4. Arch: This folder holds architecture-specific implementations of the driver functions. Files like tiva_c_digital.h, tiva_c_uart0.h, and tiva_c_pwm.h are examples that provide the necessary hardware level interactions for the Tiva C microcontroller series. This abstraction layer allows the high-level driver interfaces to remain unchanged while supporting multiple architectures underneath.
5. Config.h: This is a user-configurable header file that allows customization of the system’s behavior. It includes options to select the target compiler, microcontroller architecture, system clock frequency, and other configuration settings required by various drivers and libraries. This makes the setup flexible and adaptable to different hardware environments.

2.1 Drivers: File Structure:

This folder contains driver functions. Currently supported functions are:
• Digital
• Serial
• Timer
• Software Timer
• PWM
• ADC
• I2cMaster
• etc.

 

2.2 Lib Structure:
This folder contains library functions. Currently supported libraries are:
• LiquidCrystal
• SevenSegment
• SevenSegmentMulti
• RTC1307

2.3 Util File Structure:
Currently supported utilities:
• Delay (blocking software delay)
• Ringbuf
To Do:
• Stdlib.h
• Stdio.h
• Etc.

2.4 Arch File structure:
The file structure of Arch is as shown below:

III. Morey_os Tiva Lib: Installation steps for CCS:

• Create an empty project either by using GCC compiler or TI
compiler
• Remove startup file from the project
• Paste complete morey_os folder
• Expand morey_os folder in project explorer window
• Open config.h
• If GCC compiler:
• #define COMPILER GCC_COMPILER
• If TI comoiler
• #define COMPILER TI_COMPILER
• Optional macros like
• #define SERIAL_ENABLE

3.1 Digital driver:

3.1.1 Supported functions:
• Include header file
• #include “morey_os/drivers/Digital.h”
• Supported functions
• Digital.pinMode(pin,mode);
• pin : A0-A7, B0-B7….F0-F5
• mode: OUTPUT, INPUT, INPUT_PULLUP, INPUT_PULLDOWN, OUTPUT_OPENDRAIN
• Eg : Digital.pinMode(F1,OUTPUT);
• Eg: Digital.pinMode(F0,INPUT_PULLUP)
• Digital.write(pin,value);
• pin : A0-A7, B0-B7….F0-F5
• Value : LOW, HIGH, TOGGLE
• Implemented using atomic operation
• value = Digital.read(pin);
• pin : A0-A7, B0-B7….F0-F5
• Value: HIGH/LOW or 1/0
• Digital.attachCallback(pin,mode,digitalCallback_t callback);
• pin : A0-A7, B0-B7….F0-F5
• mode: FALLING_EDGE, RISING_EDGE, BOTH_EDGES, LOW_LEVEL, HIGH_LEVEL
• Callback function pointer of type
• Void (*digitalCallback)(uint8_t pin)
• Digital.detachCallback(pin)
• pin : A0-A7, B0-B7….F0-F5

3.2 LCD Lib:

3.2.1Supported Functions:

typedef struct lcd_struct
{
uint8_t lcd_pin_rs;
uint8_t lcd_pin_en;
uint8_t lcd_pin_d4;
uint8_t lcd_pin_d5;
uint8_t lcd_pin_d6;
uint8_t lcd_pin_d7;
uint8_t cols;
uint8_t rows;
uint8_t x;
uint8_t y;
} LiquidCrystal_t;

void lcd_begin(LiquidCrystal_t * lcd_struct, uint8_t cols, uint8_t rows);
void lcd_clear(LiquidCrystal_t * lcd_struct);
void lcd_setCursor(LiquidCrystal_t * lcd_struct, uint8_t x, uint8_t y);
void lcd_write(LiquidCrystal_t * lcd_struct, char data);
void lcd_print(LiquidCrystal_t * lcd_struct, char * data_string);

3.3 SevenSegment Lib:
3.3.1 Supported Function:
typedef struct seven_segment_struct
{
uint8_t segment_pin_a;
uint8_t segment_pin_b;
uint8_t segment_pin_c;
uint8_t segment_pin_d;
uint8_t segment_pin_e;
uint8_t segment_pin_f;
uint8_t segment_pin_g;
uint8_t segment_pin_h;
uint8_t segment_type;
} SevenSegment_t;

uint8_t digit2symbol(uint8_t digit);
uint8_t reverse_symbol(uint8_t symbol);
void SevenSegment_begin (struct seven_segment_struct * seven_segment_obj, uint8_t segment_type);
void SevenSegment_print (struct seven_segment_struct * seven_segment_obj, uint8_t digit);
void SevenSegment_printDot (struct seven_segment_struct * seven_segment_obj, uint8_t digit);
void SevenSegment_printReverse (struct seven_segment_struct * seven_segment_obj, uint8_t digit);
void SevenSegment_printDotReverse (struct seven_segment_struct * seven_segment_obj, uint8_t digit);
void SevenSegment_customPrint (struct seven_segment_struct * seven_segment_obj, \
uint8_t custom_data_pin_a, uint8_t custom_data_pin_b, uint8_t custom_data_pin_c, uint8_t custom_data_pin_d, \
uint8_t custom_data_pin_e, uint8_t custom_data_pin_f, uint8_t custom_data_pin_g, uint8_t custom_data_pin_h);
void SevenSegment_symbolPrint (struct seven_segment_struct * seven_segment_obj, uint8_t symbol);

3.4 SevenSegmentMulti Lib:
3.4.1 Supported Functions:

typedef struct seven_segment_multi_struct
{
SevenSegment_t * seven_segment_obj;
uint8_t segment_count;
uint8_t * segment_common_pins;
uint8_t symbol_display[8];
uint8_t count;
uint8_t switch_on;
uint8_t switch_off;
} SevenSegmentMulti_t;

void SevenSegmentMulti_begin (SevenSegmentMulti_t * seven_segment_multi_obj, SevenSegment_t *
seven_segment_obj, \
uint8_t * segment_common_pins, uint8_t segment_count);
void SevenSegmentMulti_callback(SevenSegmentMulti_t * seven_segment_multi_obj);

void SevenSegmentMulti_config(SevenSegmentMulti_t * seven_segment_multi_obj, uint8_t mode);
void SevenSegmentMulti_print (SevenSegmentMulti_t * seven_segment_multi_obj, uint16_t number);
void SevenSegmentMulti_printReverse (SevenSegmentMulti_t * seven_segment_multi_obj, uint16_t number, uint8_t
* reverse_position);
void SevenSegmentMulti_printDot(SevenSegmentMulti_t * seven_segment_multi_obj, uint16_t number,\
uint8_t * dot_position);
void SevenSegmentMulti_printDotReverse(SevenSegmentMulti_t * seven_segment_multi_obj, uint16_t number,\
uint8_t * dot_position, uint8_t * reverse_position);
void SevenSegmentMulti_customPrint (struct seven_segment_multi_struct * seven_segment_multi_obj, uint8_t * *
custom_data);

3.5 Serial (Uart) driver:
3.5.1 Supported Functions:
• Include header file
• #include “morey_os/drivers/Serial.h”
• Supported functions
• Serial.begin(baudrate,mode);
• Baudrate : 9600, 115200, etc.
• mode: SERIAL_8N1, SERIAL_8O2, etc.
• Serial.write(byte);
• byte : ‘a’, 0x0A, etc.
• Serial.print(“Hello”);
• Serial.println(“Hello with new line”);
• bytes = Serial.available();
• Bytes : no of byte available for read
• data = Serial.read();
• data : single byte read
• Serial.flush();
• Clear Rx buffer without reading
• len=Serial.stringAvailable();
• Len = number of strings available
• Serial.readString( char * string);
• String: read string terminated by terminator
• Serial.terminator(term_string,len);
• term_string : “\r\n”, etc.
• len = length of terminator, eg 2

3.6 Timer driver:
3.6.1 Supported Functions:
• uint8_t begin( uint8_t mode, timerCallback_t callback_fcn);
• uint8_t start(float delay_ms);
• uint8_t restart(void);
• uint8_t pause(void);
• uint8_t resume(void);
• uint8_t (stop(void);
• float currentMs(void);
• uint8_t isTimerExpired(void);

3.7 SoftwareTimer driver:
3.7.1 Supported Functions:
• void begin(const struct timer_driver * host_timer,uint32_t resolution_ms);
• uint8_t start(uint8_t timer_no, uint32_t delay_ms, uint8_t mode, softwareTimerCallback_t timer_callback);
• uint8_t restart(uint8_t timer_no);
• uint8_t pause(uint8_t timer_no);
• uint8_t resume(uint8_t timer_no);
• uint8_t stop(uint8_t timer_no);
• uint32_t currentMs(uint8_t timer_no);
• uint8_t isTimerExpired(uint8_t timer_no);
• void delay(uint32_t delay_ms);
• void end(void);

3.8 PWM driver:
3.8.1 Supported Functions:
• uint8_t begin(uint8_t pwm_gen, uint16_t freq, uint8_t mode);
• uint8_t end(uint8_t pwm_pin);
• uint8_t setDutyCycle(uint8_t pwm_pin, float duty_cycle);
• float getDutyCycle(uint8_t os_pwm_pin);
• uint8_t config(uint8_t parameter, uint32_t value, void * value_struct);

3.9 ADC driver:
3.9.1 Supported Functions:
• uint8_t begin(uint8_t adc_pin);
• uint8_t end(uint8_t adc_pin);
• uint16_t read(uint8_t adc_pin);

3.10 I2cMaster Driver:
3.10.1 Supported Functions:
• void begin(uint32_t baudrate);
• void end(void);
• uint8_t transfer(uint8_t slave_address, void * data_tx, uint16_t data_tx_len, void * data_rx, uint16_t
data_rx_len);

3.11 DS1307 Lib:
3.11.1 Supported Functions:
• uint8_t rtc1307_begin(const struct i2c_master_driver * i2c_port, uint32_t i2c_baud, uint8_t mode);
• uint8_t rtc1307_setTime(uint8_t hour, uint8_t minute, uint8_t second);
• uint8_t rtc1307_setDate(uint8_t day, uint8_t date, uint8_t month, uint8_t year);
• uint8_t rtc1307_getTime(uint8_t * hour, uint8_t * minute, uint8_t * second);
• uint8_t rtc1307_getDate(uint8_t *day, uint8_t * date, uint8_t * month, uint8_t * year);