PLAIN – User Instructions

PLAIN can map an ADC value as a easyIPC object and access it directly. The design here should be recognizable for anyone that have used Modbus or CANopen in the past. Modbus, as an example, can map its registers into easyIPC registers.

We do however also support User instructions. As we add modules that enable themselves as part of PLAIN Assembly they can also add their own specialized instructions. This creates challenges of it’s own where we need to real-time linker to convert category codes or reject an application as it is downloaded.

The way this works is that the new instruction is a callback into C/C++ code with the instruction itself as the only parameter. The more complex part is adding this to the Assembler and Compiler (and not only the VM).

The idea is that we use an XML script to describe our VM. This will describe the added instructions and be required by the Assembler. A specialized utility can generate C tables needed to add the same information into the firmware library.

PLAIN – Reviewed VM

My original VM used a 32 bit instruction set that result in a bit of wasted memory, so I am reducing this to 16 bit. This leaves the shortest instruction 16 bit and the longest 16 x 16 bit. I also want to reduce the number of instructions and only keep the high level ones to reduce the size of the VM. The list below is the minimal basic instructions on category 0.

NOP No Operation.
Move Move
Goto Goto/Unconditional jump.
For FOR Loop
Assign Assign operation
While WHILE Loop
Loop Generic Loop
Exit  Terminate a process
Raise Raise an event. The same as calling a function without creating a stack Return entry.
Call Call a function and create a stack Return entry. A function can be PLAIN or C/C++ function.
If If statement
ElsIf Else If Statement
Else Else
Switch Switch

Some of the specialized instructions needed by the parse tree on expressions and math is removed. I plan to implement this differently, but we might need to add some basic instructions back.

PLAIN VM versus Java VM and .NET

One of the questions we should ask is why we don’t use Java or C# since they both have a similar VM design? .NET Micro would actually run on the F405 MCU’s as well. The answer lies in the requirement “Real-time centric”. In short these VM’s introduce a design that causes them to have a Not Recommended status in higher quality standards like IEC61508 and MISRA.

Exceptions is a mechanism that allows you to do a jump in code execution if you detect an error. I have replaced this with a new mechanism called Event’s that behave exactly the opposite way – an exception makes a try catch jump that causes yet another exception cascading to a fatal error if it is not handled. You have seen it – this long Java or C# exception error that stop an application and make a minor error fatal. It is a nightmare to handle in a real-time system.

Event’s is basically a return code allowing you to continue processing depending on what happens – if it is not coded nothing shall happen. The difference is that a minor error remains minor.

Garbage Handler is a replaced with a Controlled Memory handler. Java/C# uses dynamic memory through a manager that will allocate/remove memory at it’s own doing. This creates errors of it’s own, but most importantly is that we don’t allow dynamic memory usage. We need a memory manager to ensure that all “dynamic” memory usage actually is static.

The third issue is features like size of VM library, inclusion of native C/C++ code and in general how well we target small MCU’s. I am not sure how small I can get the level 2 implementation, but I have a wage hope that I can run it on a STM32F030F4 with only 16Kb Flash and 4Kb SRAM – PBASIC introduced back in 1979 was a VM running from 8Kb ROM so it should be possible, but lets see.

PLAIN – Basic Assembly Instructions

This is from my current implementation that focused on proof of concept. The list is basic instructions that will be reviewed and described in more details later.

  •                         uint16_t Op_NOP(uint16_t in, uint8_t length);
  •                         uint16_t Op_Move(uint16_t in, uint8_t length);
  •                         uint16_t Op_Add(uint16_t in, uint8_t length);
  •                         uint16_t Op_Sub(uint16_t in, uint8_t length);
  •                         uint16_t Op_Div(uint16_t in, uint8_t length);
  •                         uint16_t Op_Mul(uint16_t in, uint8_t length);
  •                         uint16_t Op_Goto(uint16_t in, uint8_t length);
  •                         uint16_t Op_For(uint16_t in, uint8_t length);
  •                         uint16_t Op_Set(uint16_t in, uint8_t length);
  •                         uint16_t Op_While(uint16_t in, uint8_t length);
  •                         uint16_t Op_Loop(uint16_t in, uint8_t length);
  •                         uint16_t Op_Exit(uint16_t in, uint8_t length);
  •                         uint16_t Op_Event(uint16_t in, uint8_t length);
  •                         uint16_t Op_Call(uint16_t in, uint8_t length);
  •                         uint16_t Op_If(uint16_t in, uint8_t length);
  •                         uint16_t Op_Ifeq(uint16_t in, uint8_t length);
  •                         uint16_t Op_Ifneq(uint16_t in, uint8_t length);
  •                         uint16_t Op_Ifls(uint16_t in, uint8_t length);
  •                         uint16_t Op_Ifgt(uint16_t in, uint8_t length);
  •                         uint16_t Op_Ifgte(uint16_t in, uint8_t length);
  •                         uint16_t Op_Iflse(uint16_t in, uint8_t length);
  •                         uint16_t Op_Switch(uint16_t in, uint8_t length);
  •                         uint16_t Op_Calc(uint16_t in, uint8_t length);

 

PLAIN – Virtual Machine

Languages like Java C# etc all use a virtual machine. This is a software package that need to start and interpret some kind assembly code. Languages like C/C++ compile into native assembly code that is much faster, but also tied to the hardware it run’s on.

A virtual machine have the advantage that we extend the platform with build in features made available in C/C++. This high level code occupy less space than binary code and executes under our control. The drawback is that it executes slower than native code, but I plan to challenge that by introducing very high level assembly instructions.

I would like to create a native assembler at some point, but for now I want to play around with a Virtual Machine design.

VM Block

The diagram above show how we link things together in the firmware. We use easyIPC protocols to communicate, RTOS and HAL + other modules tom access electronics and do complex stuff. The VM executes logic that control what we do.

Instruction Format

Our VM needs it’s own assembly language so we can use a 32 bit design as indicated above. A 8 bit Op-Code + 4 bit Category code leaves 16 pages of 256 instructions. Category 0 is the build in one, but other categories can be used for extended instructions. Length is the added number of 32 bit register, meaning an instruction can be 32 x 16 bits long.

Instruction Move

This show the MOVE R1, R2 that will copy content of R1 into R2. As this is an array of 31 parameters we can extend this to MOVE R1,R2,R3;R4 etc that copies R1 into R2,R3,R4. Op Code 0 is NOP (No Operation).

VM Tables

This diagram illustrate the internal core of the VM. We have a table holding 32 bit instructions stored in Flash. A Registers table that is located in SRAM for generic use in our logic, and an object table that use address 0x8000 to 0xFFFF to access easyIPC mapped content. Notice that the total register size is 64Kb to make the most of a 16 bit parameter. Stack is located in SRAM at 0x7FFF and up. Each PLAIN Module have it’s own, private stack.

PLAIN contains a set of registers known as easyIPC object registers located between 8000h and FFFFh. These are accessed the same way as stack and generic registers, but are wired to other software or hardware. If these registers are changed events will be generated to allow PLAIN or C/C++ to process changes.

The PLAIN specification allows an application to organize it’s own layout of these objects to guarantee that an application will execute correctly. The issue is that registers for selected hardware need to be located somewhere, and with various hardware/software combinations you end up with far too many registers for the world to be unique. To solve this the Assembler will create a map where all software and hardware is mapped correctly with PLAIN logic. This result in a map that follows the application. The run-time engine will need to map and resolve these calls as the PLAIN application is loaded.

This is work in progress so expect changes as we implement this. The design draft above is based on a proof of concept implementation done about a year ago.

Introducing PLAIN

One of the challenges with a distributed system consisting of multiple Raspberry PI’s, multiple Hat’s and multiple RS-X connected devices is how to control it all. At the end we are running a complex, distributed system and coding logic on this level using a classic programming language like C/C++ is not straight forward. C/C++ is unbeatable dealing with low level electronics, performance and algorithms, but it is a bit clumsy to write higher level logic involving distributed logic. I would like to keep C/C++ to deal with low level things and HOW we do things, but I need something better to describe the logic and WHAT we want done. Having used years with various programming languages, PLC and CNC machinery I basically want to create something new that does things a bit differently.

I decided some time ago to name this PLAINProgramming Language for Automation Industry – basically a language/Logic concept to control robotics on distributed systems. We can evolve this a bit as we move forward, but I have a few key requirements:

  • Generic in nature.
  • Extendable and able to use C/C++ modules.
  • Deal with distributed, high level logic.
  • Support a future graphical CASE tool.
  • State-engine and event based Logic at core.
  • Easy to read top-down text, no cryptic syntax.
  • Easy to learn – read Logic in 5 min – yet powerfully to support Professionals.
  • Embeddable into other solutions.
  • Real-Time Centric.

The previous work on easyIPC fits straight into this work as is establish a plug & play communication network using multiple techniques. What I lack is an Ethernet based protocol, but I will return to this later.

At this point I am planning a language specification, compiler and Virtual Machine. The specification will need to evolve as we move forward on try & fail. Actually I want to start with the Virtual Machine.

7x Stepper Hat

rpi7xStepperThis is a very simple design to support 28BYJ-48 from a Hat. Using up to 4 x ULN2003 I get exactly 7×4 PWM signals. The only challenge is the connectors as I need to use 5 pin 2.54 pitch in this case since the steppers come with this attached (the 3D use the wrong package). I am only capable of mounting 3 of the 7 connectors on the edge.

8xDC Motor Hat – Connectors

8xDC_wSens1

One of the “challenges” with the Raspberry PI Hat size/format is that I always lack space for connectors. The 8 x DC Motor controller is an excellent example as I can manage 8 motor controllers, but adding connectors that support right angle is a challenge. It is not that the connectors don’t exist, it is size combined with cost.

Looking at the toy robot I am using I decided to add 2.54 pitch right angle connectors because this allows me space to add 8x sensor connectors as well. This results in a single board with 8 x DC Motors and 8 x End-Stop/Encoders. All accessible from the side offering straight or right angle connectors.

8xDC_wSens2

The pictures above show two different ways of mounting the Connectors – just experimenting for now.

8xDC Motor Hat

hat8xdc

An updated draft of 8xDC Motor Hat with TVS diodes and spike cutters. I am not happy with the connectors here. They are “ok”, but they are not easily to mount from within a stack and a bit expensive. I need to find alternatives. The 5.08 Power Connector is fine, it’s the 2.54 pitch motor connector in front I need to re-work.

A DC Motor driver like LM9110 that we use here is very popular and sufficient to drive a lot of small motors. In this case I need 5 to drive a toy robot arm so added 8. The input to the driver is 2x PWM signals driving a H-Bridge. The principle is simple as you switch on the PWM signal in the direction you want to drive. A bit more complicated is functions like speed, break and acceleration. The difference from the 32xServo is that we this time need to use PWM at a selected frequency with a duty cycle to indicate speed. With 8 motors this means we will be using 16 PWM signals.

Bit-banging will not work this time because we would need to iterate at 10,000Hz to achieve a frequency of 500Hz with 10% accuracy. I would like to adjust the frequency out for optimized motor drive and this is a perfect job for the Hardware Timers on the MCU. We will be using STM32F103RB or STM32F105RB that have a load of timers supporting 4 channels each. Each have a resolution of 16 – 32 bits, so we will not have any challenge with accuracy.

Finding 16 PWM signals works fine on F103 & F105 LQFP64 with Timer1,2,3 & 4 as they all have all 4 channels available on the same pins.