I am hung up on how to move forward with FreeRTOS in my application. Let me propose a simple scenario. Assume I have main and a module which has some hardware specific code. This code could be for controlling a specific motor in a system or a sensor... any bit of hardware with a defined role. Within module.c I have a function called ModuleNameTask. In main I create the task using xTaskCreate and I pass ModuleNameTask. Since my ModuleNameTask is defined in module.c and not main.c, I now have to include bits of FreeRTOS within module.c in order to use functions like vTaskDelay. I don't like the fact that I am including these files within module.c as I feel its no longer portable.
So, how do I handle this? Should I remove that ModuleNameTask from module.c and place it in main.c? Or just accept the fact that I have to include bits of FreeRTOS into module.c. Any advice?
What functionality do you require from FreeRTOS for your module to work. Obviously there are some things or you wouldn't need to include the headers and you wouldn't be calling the functions.
Take these functions and put them in a separate header called os/<operating_sys>/freertos.h and wrap them in your own function names (e.g. my_createtask(<args>).). Now to port to a different OS you will need to provide a new file with new wrappers for your own functions.
If you do this poorly you'll notice that your createtask function looks exactly like the FreeRTOS function and can be easily mapped but when you want to use linux/vxWorks/other OS that the function doesn't have the right arguments.
Your createtask function should only contain the parameters that you care about. The others should be hard coded in the wrapper. This will make it easier to port (you'll have different parameters to hard code in other operating systems).
Abstract both the RTOS and the device layer.
Define an OS interface of your design (this may only be a subset of FreeRTOS functionality or even include higher level interfaces implemented using RTOS primitives) and implement this interface using FreeRTOS.
You then define your entire application including your device layer using only your RTOS abstraction layer interface. When you port your application to another platform or RTOS, you only need change the abstraction layer implementation, being sure to maintain the same semantics as the original implementation. If the device layer is also suitably abstracted so as to be able to be generic across different hardware you can do the same for hardware dependencies (i.e. abstract them from the physical implementation).
I have successfully used this approach for many years, using an RTOS abstraction in C++ that I have ported to FreeRTOS, VxWorks, Segger embOS and Keil RTX and even Windows and Linux (for test and simulation). You need not of course use C++, but it is well suited to the task.
In your abstraction you need to consider the following:
Threading
IPC (queues, pipes, event flags, mailboxes etc.)
Synchronisation (mutex, semaphores)
Timers
Interrupt handlers
Your interface might look very different from FreeRTOS itself, and it may be worth looking at a number of other RTOS interfaces to see what kind of features yours may need.
Related
I am trying to make a layered architecture and apply hardware abstraction using the HAL concept (hardware abstraction layer).
But I have to stick to the common features only between MCUs, in order to make a generic interface that can be portable between different MCUs. So that I won't have to change the upper layer at all when I move to another MCU.
But I won't be able to use costum features that exist in a specific MCU while others don't have it.
So if there is a specific extra feature in a gpio module that exists in a specific MCU and I want to use it but it doesn't exist in HAL (because it's not a common feature). How can I make an interface for it?
Example:
I want to make a HAL that contains standard interface between atmega328p and Dspic33. Dspic33 has a feature in the Gpio which is Internal Pull Down. This feature does not exist in the atmega328p (so I can't include it in the HAL standard interface).
So if I want to use this uncommon feature how am I going to do that?
You can either or all of the following:
provide an interface with abstracted semantic parameters, with e.g. the meaning "I want to use internal pull down, if present: yes/no"; on platforms which do not have it, the function would effectively be empty
provide a query API, which allows to check whether a feature is available; if it is then the calling code can use it, with implicit knowledge needed on how to do that (this can be done in the shape of a macro, which would allow querying without the knowledge whether the querying API itself exists, via #ifdef; which in turn would allow to skip implementing it on the environments which do not support the feature)
combine both, i.e. semantic interface with a return value indicating whether the feature has been successfully applied
I need to develop device libraries like uBlox, IMUs, BLE, ecc.. from scratch (almost). Is there any doc or tutorial that can help me?
Question is, how to write a device library using C/C++ (Arduino style if you want) given a datasheet and a platform like STM32 or other ARMs?
Thanks so much
I've tried to read device libraries from Arduino library and various Github, but I would like to have a guide/template to follow (general rules) to write proper device libraries from a given datasheet.
I'm not asking a full definitive guide, just where to start, docs, methods approach.
I've found this one below, but is very basic and quite lite for my targets.
http://blog.atollic.com/device-driver-development-the-ultimate-guide-for-embedded-system-developers
I don't think that you can actually write libraries for STM32 in Arduino style. Most Arduino libraries you can find in the wild promote ease of usage rather than performance. For example, a simple library designed for a specific sensor works well if reading the sensor and reporting the results via serial port is the only thing that firmware must do. When you work on more complex projects where uC has lots to do and satisfy some real time constraints, the general Arduino approach doesn't solve your problems.
The problem with STM32 library development is the complex connection between peripherals, DMA and interrupts. I code them in register level without using the Cube framework and I often find myself digging the reference manual for tables that shows the connections between DMA channels or things like timer master-slave relations. Some peripherals (timers mostly) work similar but each one of them has small differences. It makes development of a hardware library that fits all scenarios practically impossible.
The tasks you need to accomplish are also more complex in STM32 projects. For example, in one of my projects, I fool SPI with a dummy/fake DMA transfer triggered by a timer, so that it can generate periodic 8-pulse trains from its clock pin (data pins are unused). No library can provide you this kind of flexibility.
Still, I believe not all is lost. I think it may be possible to build an hardware abstraction layer (HAL, but not The HAL by ST). So, it's possible to create useful libraries if you can abstract them from the hardware. A USB library can be a good example for this approach, as the STM32 devices have ~3 different USB peripheral hardware variations and it makes sense to write a separate HAL for each one of them. The upper application layer however can be the same.
Maybe that was the reason why ST created Cube framework. But as you know, Cube relies on external code generation tools which are aware of the hardware of each device. So, some of the work can be avoided in runtime. You can't achieve the same result when you write your own libraries unless you also design a similar external code generation tool. And also, the code Cube generates is bloated in most cases. You trade development time for runtime performance and code space.
I assume you will be using a cross toolchain on some platform like Linux, and that the cross toolchain is compatible with some method to load object code on the target CPU. I also assume that you already have a working STM32 board that is documented well enough to figure out how the sensors will connect to the board or to the CPU.
First, you should define what your library is supposed to provide. This part is usually surprisingly difficult. It’s a bit hard to know what it can provide, without knowing a bit about what the hardware sensors are capable of providing. Some iteration on the requirements is expected.
You will need to have access to the documentation for the sensors, usually in the form of the manufacturer’s data sheets. Using the datasheet, and knowing how the device is connected to the target CPU/board, you will need to access the STM32 peripherals that comprise the interface to the sensors. Back to the datasheets, this time for the STM32, to see how to access its peripheral interfaces. That might be simple GPIO bits and bytes, or might be how to use built-in peripherals such as SPI or I2C.
The datasheets for the sensors will detail a bunch of registers, describing the meaning of each, including the meanings of each bit, or group of bits, in certain registers. You will write code in C that accesses the STM32 peripherals, and those peripherals will access the sensors across the electrical interface that is part of the STM32 board.
The workflow usually starts out by writing to a register or three to see if there is some identifiable effect. For example, if you are exercising a digital IO port, you might wire up an LED to see if you can turn it on or off, or a switch to see if you can correctly read its state. This establishes that your code can poke or peek at IO using register level access. There may be existing helper functions to do this work as part of the cross toolchain. Or you might have to develop your own, using pointer indirection to access memory mapped IO. Or there might be specially instructions needed that can only be accessed from inline assembler code. This answer is generic as I don’t know the specifics of the STM32 processor or its typical ecosystem.
Then you move on to more complex operations that might involve sequences of operations, like cycling a bit or two to effect some communication with the device. Or it might be as simple as finding the proper sequence of registers to access for operation of a SPI interface. Often, you will find small chunks of code are complete enough to be re-used by your driver; like how to read or write an individual byte. You can then make that a reusable function to simplify the rest of the work, like accessing certain registers in sequence and printing the contents of register that you read to see if they make sense. Ultimately, you will have two important pieces of information: and understanding of the low-level register accesses needed to create a formal driver, and an understanding of what components and capabilities make up the hardware (ie, you know how the device(s) work).
Now, throw away most of what you’ve done, and develop a formal spec. Use what you now know to include everything that can be useful. Use what you now know to develop a spec that includes an appropriate interface API that your application code can use. Rewrite the driver, armed with the knowledge of how are the pieces work, and taking advantage of the blank canvas afforded you by the fresh rewrite of the spec. Only reuse code that you are completely confident is optimal and appropriate to the format dictated by the spec. Write test code for all of the modules, and use the test code to actually test that the code works and that it conforms to the spec. Re-use the test code every time you modify anything it tests.
I want to to write a module that need some RTOS APIs like Mbox and Task creation API !
I'm trying to have structured code and to do that I'm looking at some libraries like "lwip" . In "lwip" there is a file named Sys-arch.c which in my knowledge is an abstraction layer to RTOS APIs ! but in my port it included cmsis_os.h and used that APIs . Why did they do that instead of using cmsis_os directly?
Should I have a new OS layer in order to have portable code or CMSIS_OS is enough ?
This answer is very opinion based.
In my experience it is always a good idea to use function/defines around your OS accesses. If you use CMSIS_OS or your own layer doesn't make a big difference beside you have more work if you use your own and especially porting and testing becomes very cumbersome with more than one OS.
The CMSIS_OS binds you to the Cortex-M systems but since they implement what you would implement in your layer as well and in quite usual way, it is rather simple to port from CMSIS_OS to your own layer later. It is not that simple if you use direct calls to a specific OS in your code directly but it is also possible if you only rely on standard features (take a look at CMSIS_OS what are common features of RTOS are) and don't use special features of your OS.
Why did they do that instead of using cmsis_os directly?
Because:
The idea is to abstract the API from any RTOS. If your target did not use CMSIS RTOS, you'd have to write a porting layer in any case.
the CMSIS RTOS API is ARM Cortex-M specific and lwip is not.
Should I have a new OS layer in order to have portable code or CMSIS_OS is enough ?
CMSIS is only enough if you will only ever target ARM Cortex-M, and there is a CMSIS layer for any RTOS you might be required to use. CMSIS is a portability abstraction, but not perhaps a usability abstraction. You might choose to implement a simpler abstraction of your own over CMSIS that can also be ported to other targets.
lwIP is nicely structured so that as long as your RTOS API supports its semantic requirements, then all you have to do is to adapt sys_arch.c to your OS API and you are done. By making sys_arch.c using the CMSIS_OS API abstraction, that would mean that you can use any CMSIS OS API compliant OS without changing that port of sys_arch.c. It's an extra layer of indirection that only you can decide whether it is worth it or not. If you do not plan to use different RTOS underneath, then there is no reason not to have a sys_arch.c that is specific to a single RTOS.
Anyway, lwIP RTOS requirements are fairly modest. Just about a dozen functions, but really only involve mailbox and semaphores with certain characteristics.
I have a Linux driver for an external MCU application. The driver and the MCU communicate over a bus using our own protocol.
I would like to share the program code for the protocol features between the kernel module and the MCU but since it's not possible to build a lib for the kernel my only idea so far is to write the code "as kernel as possible" and then just copy the entire .c file between the platforms.
Are there any other ways? Surly I can't be the first to want to do this.
I'm talking about code reuse, not IPC mechanisms.
Thanks!
It requires some hardware abstraction so the code implementing the protocol needs to be generic as possible not requiring any hardware specific details.
The file implementing the protocol could have functions like init, exit, read, write and interrupt. The hardware implementation itself (gpio, memory, bus) can be accessed through function pointers which are registered at time when calling the init function. The directory structure can be set up like #smbear suggested
If we can already execute C programs on cortex-m like micro-controllers, Why do we even need to install RTOS (or other operating systems).?
What benefits it can provide if micro-controller is intended to be multi-purpose.?
No you dont need an RTOS only if you need/want the features of the (particular) RTOS. You can program the microcontroller the way you/we always have without one if you prefer.
Typical things an RTOS might bring,
Memory management (who owns memory)
Interrupt handling support
Scheduling (pre-emptive or co-operative)
Usually several drivers in a BSP for your hardware/SOC
Debug tools
Some sort of shell
File systems
IPC (inter-process communitation)
A tool suite
A build environment
Memory protection
Networking
Your application may or may not need these features depending on your end goal. Some of them may be detrimental to your organizations work flow (like the tool suite and build environment). As a product matures, you may end up needing features you didn't account for.
However, a completely custom solution will probably have a smaller foot print. The race conditions involved in interrupt handling can be quite difficult to get right. Probably most RTOS will give a better implementation than something custom that evolves over time. If you are very dedicated, a state machine with polling of devices can be more optimal (hard real time) but again it is difficult to get right.
If the RTOS is BSD (or other permissive) licensed , it maybe possible to reuse the driver code to your own custom infra-structure. At some point your code may become an 'RTOS' of sorts. There are many to choose from.
POSIX compliance is a common standard. If you confine your code to POSIX, you are portable to many different RTOS/OS. However, most often an API that is more rich than POSIX; it is one way they differentiate each other. You may be able to use more 3rd party libraries if the RTOS is POSIX compliant.
An operating system provides a level of abstraction between the code written by an application programmer and the actual hardware the program runs on.
So you don't have to worry, as an application programmer, about the details of the hardware, as they are handled by drivers.
And thus you can compile the same program for many different hardware platforms, if they run the same (or a compatible) operating system.