theCore icon indicating copy to clipboard operation
theCore copied to clipboard

Implement basic platform support for NXP Kinetis KE02 MCUs (Cortex M0+)

Open forGGe opened this issue 8 years ago • 42 comments

Task is to integrate theCore with KE02 MCUs

Refs:

Must include

  • [ ] JSON-based configurator
  • [ ] Documentation page with available periphery
  • [ ] At least one example
  • [ ] BAT test suite

forGGe avatar Feb 16 '17 12:02 forGGe

Working branch for this issue : https://github.com/forGGe/theCore/tree/g230_kinetis_ke02_exp_support

forGGe avatar Mar 02 '17 21:03 forGGe

Hi there,

I'm interested to work on this issue. So what is the current state of KE02 support ?

iia avatar Apr 07 '18 00:04 iia

Hi @iia ,

Currently we have the g230_kinetis_ke02_exp_support branch that pretty outdated and should be refreshed.

If you would like to contribute to this issue, I can guide you with steps required to bring KE02 alive and assist in development.

If you want me to implement KE02 support, I can rearrange priorities and complete the task.

Let me know what you think.

forGGe avatar Apr 07 '18 09:04 forGGe

Hi @forGGe ,

I'm interested in contributing to this issue. So it would be great if you can provide with some assistance. To be more precise an overview of the project, the main parts and how they relate and connect among themselves. And of course what is involved to add support for new platforms.

iia avatar Apr 07 '18 15:04 iia

Hi @iia,

I really appreciate your interest in contributing!

Below is an overview you requested.

Overview

theCore tries to provide a framework that consistent enough to make portable applications for different kinds of microcontrollers. "Portable" means that you just write your application code once and then compile it for every compatible device.

For example, an application code for reading humidity sensor and writing samples to the MicroSD card will be the same, no matter where you attached MicroSD card and humidity sensor - to STM32F4 or to TI TM4C microcontroller. In a some way, theCore looks like HAL-on-steroids.

(Besides just providing consistent APIs, theCore aims to be a full-featured framework, see Roadmap for more information)

Project main parts

To achieve that goal theCore provides different kinds of modules:

  • architecture modules - placed under arch directory. The goal of architecture module is to provide the early startup and initialization code, shared by different microcontrollers. This is where your program starts. Architecture module then passes execution to the platform module, described below.

  • platform modules - most important and hard part. Placed under platform directory. Goal of specific platform module is to initialize MCU (clock, watchdog, etc.) and give a user (and theCore) similar APIs for every supported periphery - UART, SPI, etc.

  • device modules - external device drivers, placed under dev directory. Those modules provides support for things that are usually attached to MCU: LCDs, audio codecs, sensors, etc.

  • lib modules - various libraries, placed under lib directory such as memory allocators, vendor-specific libs, FATFS and other stuff that does not fall in any of previous categories.

  • kernel modules - RTOS-related modules, placed under kernel directory. Only FreeRTOS is really supported for now.

  • system module - placed under sys directory - it is just a little part of theCore code that initializes theCore itself. There you will find runtime constructor calls and console greetings.

Project configuration

Besides just providing classes to access different devices or MCU peripheries, often it is required to additionally specify how those modules interacts with each other (say, you have attached LCD to MCU) or you need to configure specific module parameters (baud rate of UART console).

theCore gives you an option to specify that details in a JSON configuration file, rather than write C/C++ code that initializes each module in question in a required way (writing C/C++ code can be tedious and error-prone).

Part of theCore, responsible for such configuration is basically called the configurator.

Good example is TI TM4C configuration for LED demo. Path to that configuration file then passed to theCore in main project file

Essentially, theCore configurator is just a code-generation tool, which takes a JSON file and produces corresponding C/C++ definitions that you can use inside your application code

See the filesystem module example that shows how incoming JSON converted into the C/C++ code. Configurator is written using Python Cog utility. The aforementioned file system, Cog-based configurator can be found here.

Configuration based on JSON is somewhat described in the respective documentation page.

Generated code is available if to include ecl/core_generated.hpp header.

Buildsystem

Not much to say here, CMake is used everywhere. Where it cannot handle things like code generation, Python is used.

Module interaction

arch and platform are the only modules that interact directly. Arch module calls theCore main routine, theCore main routine then calls platform initialization code and user's main

All other modules sit aside and wait until they will be used by the configurator tool.

You will get more insights about specific modules while hacking KE02 platform.

forGGe avatar Apr 07 '18 18:04 forGGe

I will take an action of refreshing the g230_kinetis_ke02_exp_support branch and will send you more instructions about platform creation soon.

Let me know what you think about it.

forGGe avatar Apr 07 '18 18:04 forGGe

Hi @forGGe ,

Thanks for the detailed overview. I'm ordering a KE02 dev board. Let me know after you have refreshed the branch.

iia avatar Apr 07 '18 20:04 iia

Just for reference: The OpenSDA support, included by default in the KE02 MCU makes debugging really painful.

See also: https://www.eevblog.com/forum/microcontrollers/freescale-opensda-linux/

Right now, I'm debugging my fresh, new KE02 dev board by just uploading binaries via the virtual mass-storage that appears after I connect the board.

So, I will try to upload correct J-Link compatible MCU firmware, found at these pages: https://www.segger.com/downloads/jlink#JLinkOpenSDABoardSpecificFirmwares https://www.segger.com/products/debug-probes/j-link/models/other-j-links/opensda-sda-v2/

And I hope my board will stay functional :)

forGGe avatar Apr 07 '18 20:04 forGGe

Hi @forGGe,

From where you ordered your board?

iia avatar Apr 08 '18 12:04 iia

From where you ordered your board?

Aliexpress, but I can't find it there anymore. I'll try to check other suppliers.

forGGe avatar Apr 08 '18 22:04 forGGe

@iia, branch g230_kinetis_ke02_exp_support is updated.

Here is instructions of how to run simple demo on your KE02 dev board:

  1. install JLink on your host system (it is not yet shipped with Nix)

  2. download theCore

  3. install Nix: https://forgge.github.io/theCore/guides/getting-started.html#using-nix

  4. cd to theCore directory

  5. enter Nix shell: nix-shell .

  6. create build dir: mkdir ke02_build && cd ke02_build

  7. build a project:

    cmake ../examples/ke02_hello -DCMAKE_BUILD_TYPE=Debug  -DCMAKE_TOOLCHAIN_FILE=../toolchains/arm-cm0-plus-gnu.cmake 
    make 
    
  8. flash image w/ help of JLink.

    Using GDB:

     # Run JLinkGDB server
    JLinkGDBServerCLExe -device MKE02Z64xxx2 -endian little -if SWD
    
    # Run GDB in another console
    arm-none-eabi-gdb ./ke02_hello -x ../scripts/ke02_jlink.gdbinit
    
    # Flash image
    (gdb) taget_load
    Loading section .text, size 0x1958 lma 0x0
    Loading section .data, size 0x14 lma 0x1958
    Start address 0x58c, load size 6508
    Transfer rate: 52064 bits in <1 sec, 2169 bytes/write.
    Resetting target (Type = 6)
    Writing register (SP = 0x20000C00)
    Writing register (PC = 0x0000058D)
    # Run image
    (gdb) c
    

    Using JLink itself:

    # Run JLink
    JLinkExe  -device MKE02Z64xxx2 -if SWD -Autoconnect 1 -Speed 1000
    
    # Sub-shell will be opened
    
    # Download image
    J-Link>loadbin ke02_hello.bin 0
    loadbin ke02_hello.bin 0
    Halting CPU for downloading file.
    Downloading file [ke02_hello.bin]...
    Comparing flash   [100%] Done.
    Verifying flash   [100%] Done.
    O.K.
    
    # Restart and go
    J-Link>r 6
    J-Link>g
    

forGGe avatar Apr 09 '18 19:04 forGGe

Also, check https://octopart.com/frdm-ke02z-nxp+semiconductors-70303061?r=sp&s=oR9dcxYPTvqj5TI7Sgx1Ug for list of available suppliers

forGGe avatar Apr 09 '18 19:04 forGGe

@forGGe,

Thanks for all the info. I got the board today and everything worked and I could execute ke02_hello.bin. Since now I have a working setup I can take a better look on the whole system. BTW as much as I could figure out for today you are using the driver lib for KExx series which is posted here in the build system right?

iia avatar Apr 11 '18 00:04 iia

Hi @iia,

Thanks for all the info. I got the board today and everything worked and I could execute ke02_hello.bin.

Great!

BTW as much as I could figure out for today you are using the driver lib for KExx series which is posted here in the build system right?

Yes, I also uploaded it to https://github.com/forGGe/kexx_driverlib master branch contains a small fix. Not all files are used from there though. See kexx CMakefile for more info theCore_get_thirdparty() CMake routine is responsible for getting that dependency.

By default, thirdparty git tree is located ${CORE_DIR}/.thirdparty directory, and worktree is placed in ${CMAKE_CURRENT_BINARY_DIR}/theCore_thirdparty_worktrees:

https://github.com/forGGe/theCore/blob/186e9e9ad22536af9a268719113104d64b7e3ebb/CMakeLists.txt#L24-L45

You can control where to download the KEXX driver library. See https://forgge.github.io/theCore/guides/thirdparty-cache.html . (I see that text there is broken, will fix ASAP)

High level architecture

Now, let me give you some ideas about the platform you going to implement.

I recommend you to start with the UART driver and all the infrastructure required to configure it.

Here is the case: theCore platform must take the JSON file, defined in the application:

https://github.com/forGGe/theCore/blob/186e9e9ad22536af9a268719113104d64b7e3ebb/examples/ke02_hello/target.json#L1-L13

and then convert it to, say, uart_cfg.hpp with approximately following contents:

#include <aux/uart.hpp> // Platform UART implementation

namespace ecl
{
    using UART0_driver = uart<uart_channel::ch0>;
    using platform_console = UART0_driver;

// I encourage you to place this definition in other file later, but for first steps, let it be here. 
#define  THECORE_CONFIG_USE_CONSOLE 1
}

Pay attention: the UART0 is included here as an example. FRDM-KE02 board's USB-to-UART is connected to the UART1 in fact

The uart_cfg.hpp then must be included in the aux/generated.hpp file, which is turn included by the ecl/generated.hpp header.

(_Sidenote: if you feel that naming is not consistent, I feel it, too. You can rename all aux/generated.hpp headers inside theCore to use correct namespace: core/platform_generated.hpp

The uart_cfg.hpp file must be generated using Python COG and a template file. I prefer to name the template file as uart_cfg.in.hpp.

See examples below.

Example implementation: TM4C platform

The UART driver (uart.hpp) is placed under platform/tm4c/export/aux dir.

The template file for the UART configuration (uart_cfg.in.hpp) is present in the TM4C templates directory

The template file for the IRQ handlers (one of which is UART) is also present in templates dir

Note: IRQ dispatching for TM4C happens in compile time. I.e. based on configuration given, we can be sure where to deliver an interrupt. I encourage you to use the compile-time dispatching for the KE02 as well. If you want the runtime dispatching - let me know, I will guide you how to use old, runtime IRQ manager in theCore

The template file for the pin configuration is also placed there.

All TM4C template files are then handled in CMakeLists.txt of the TM4C platform:

https://github.com/forGGe/theCore/blob/186e9e9ad22536af9a268719113104d64b7e3ebb/platform/tm4c/CMakeLists.txt#L27-L70

Check that entire file to get more insights.

Bypass UART driver

There is a little trickery for the UART driver used as a console output. The UART driver must be able to perform a low-latency output right in the platform periphery. Such shortcut is made in case we need to print something from IRQ context on in case of failed assertion.

It is called "bypass console" in terms of theCore.

You can check the TM4C platform files to see how it works:

forGGe avatar Apr 11 '18 12:04 forGGe

Yet, I didn't say to you where to put the UART baud rate, stop bits, etc. Let's stick with 115200/8/1 default configuration and after the UART driver will be ready, I will guide you how to handle that configuration.

forGGe avatar Apr 11 '18 12:04 forGGe

@forGGe,

Thanks again for the detailed explanation. Before I start with the UART driver I would like to explain my mental model of the overall system to verify if my concepts are correct.

I will try to represent my mental model of the system with a little ASCII art.

............................ [User Program] ............................ | | USES | V .................................................................................... [Platform] Generated based on the JSON file to use the drivers .................................................................................... | | USES | V ....................................................................................................................... [Drivers] Standard transparent interface to be used by the platform or user program. e.g, platform/tm4c/export/aux/uart.hpp ....................................................................................................................... | | USES | V .............................................................................................................. [Vendor API] Platform specific API provided by the vendor e.g, KEXX_DRIVERLIB .............................................................................................................. | | USES | V ..................... [Hardware] .....................

Is this correct?

BTW what does "ecl" stand for?

iia avatar Apr 12 '18 17:04 iia

@iia ,

Your mental model is correct enough. To be more precise, let me add there one item:

............................
[User Program]
............................
|                   |        
|                   | USES
| USES              V 
|                 ............................
|                   [External device drivers] 
|                     E.g. LCD driver, RFID reader, etc.
|                     Also generated by JSON
|                 ............................
|                   |        
|                   |   USES     
V                   V        
....................................................................................
[Platform]
Generated based on the JSON file to use the drivers
....................................................................................

I though it is important to place external device block there, since without that part, user application can't do much (except blinking LED)

If you find that extended model confusing, please let me know. I will try to explain it in more detail.

Also, I'm using here (and across theCore) following convention for naming entities:

  • platform - from HW point of view, the platform is a specific MCU, and nothing beyond that. Kinetis KE02 MCU is a platform. FRDM-KE02 board is not a platform (see below). From SW point of view the platform is a set of drivers and utilities related only to specific MCU, and nothing beyond that. For example, driver for LCD controller inside STM MCU is part of the platform, while LCD driver for PCD8544 Nokia display is not a part of the platform

  • target - from HW point of view, the target is a specific board based on a specific MCU. STM32F4 Discovery board is a target. FRDM-KE02 board is another kind of target. If you connect temperature sensor to FRDM-KE02 board you will get a new target. From SW point of view, the target is a set of drivers and utilities, that covers specific board with all devices connected to MCU PLUS the corresponding platform.

JSON file laying in the root of example project is a specification of a target. That is, it specifies what MCU is placed on the board (and how it should be configured) and what hardware is connected to the MCU (and how it should be configured).

forGGe avatar Apr 12 '18 20:04 forGGe

BTW what does "ecl" stand for?

ECL stands for "Embedded Core Library"

It is not so meaningful, but it has three required properties:

  • acronym is 3 chars wide, which is convenient for namespace name.
  • it has "Embedded" and "Core" words in it.
  • easy to pronounce

But I'm open for suggestions in that field :)

forGGe avatar Apr 12 '18 20:04 forGGe

Hi,

Platform and target clarification was useful. Thanks.

iia avatar Apr 13 '18 11:04 iia

Hi @forGGe,

Can you explain the bus architecture in device module? What I understand so far about it is that it is to provide an uniform interface to theCore applications to use peripherals that operate on a bus architecture e.g, SPI, I2C etc. It also seems that the platform serial driver must register to the bus so that UART becomes transparent to theCore applications.

Is my understanding correct? Can you provide a bit more detail of the bus mechanism e.g, how platform drivers register to the bus mechanism and how the bus mechanism is used?

iia avatar Apr 15 '18 12:04 iia

Hi @forGGe,

Can you explain a bit more about compile time interrupt dispatching as you mentioned about TM4C platform ?

iia avatar Apr 15 '18 12:04 iia

Hi @iia,

Let me reach my PC, I will answer your questions.

Regards, Max

On Sun, Apr 15, 2018, 3:05 PM Ishraq Ibne Ashraf [email protected] wrote:

Hi @forGGe https://github.com/forGGe,

Can you explain a bit more about compile time interrupt dispatching as you mentioned about TM4C platform ?

forGGe avatar Apr 15 '18 14:04 forGGe

Can you explain the bus architecture in device module? What I understand so far about it is that it is to provide an uniform interface to theCore applications to use peripherals that operate on a bus architecture e.g, SPI, I2C etc. It also seems that the platform serial driver must register to the bus so that UART becomes transparent to theCore applications.

Is my understanding correct?

You are totally correct. In current state of things, all platform drivers that are capable of doing data transfers are compatible with dev/bus abstraction.

Not only the bus module presents platform drivers in a common way, it is also extracts common functionality (to avoid duplication in every platform driver, obviously). Most notable is the thread-safety support. dev/bus provides lock()/unlock() methods to protect against race conditions when accessing platform-level driver.

Can you provide a bit more detail of the bus mechanism e.g, how platform drivers register to the bus mechanism and how the bus mechanism is used?

Act of registering to the bus system is a simple composition between dev/bus and corresponding platform driver.

Abstract example

Suppose we have platform UART driver, like that:


enum class uart_channel
{
    ch0,
    ch1,
    // ... 
};

template<uart_channel Ch>
class uart
{
// UART implementation ...
};

and dev/bus.hpp class (simplified interface):

template<typename PlatformBus>
class generic_bus
{
// Generic bus implementation ...
};

Then theCore can combine (based on configuration JSON) them in following way:

using uart1_driver = uart<uart_channel::ch1>;
using uart1_bus = generic_bus<uart1_driver>;

Now, the uart1_bus alias can be used in application level or in internal theCore machinery (i.e. in console subsystem).

Note that there are no run-time registering of the UART driver. theCore is aware which platform driver is used for which purpose, so it can directly aggregate common interface class and specific platform driver using C++ templates.

Real-world TM4C implementation example

Here is the TM4C UART class:

https://github.com/forGGe/theCore/blob/047b0a560b1b4942359ee537c0c67694a12a5175/platform/tm4c/export/aux/uart.hpp#L38-L54

Here is the TM4C UART generator (cog template in fact) (pay attention for #365 bug):

https://github.com/forGGe/theCore/blob/047b0a560b1b4942359ee537c0c67694a12a5175/platform/tm4c/templates/uart_cfg.in.hpp#L32-L57

Here is the example JSON (related to the UART only) provided by user:

{
    "platform": {
        "name": "tm4c",
        "console": "UART0",
        "uart": [
            {
                "id": "UART0",
                "alias": "test_uart",
                "comment": "UART-over-USB console output"
            },
            {
                "id": "UART1",
                "alias": "another_uart",
                "comment": "Example UART"
            }
        ]
    }
}

Here is what TM4C UART generator will generate in response to user JSON:

namespace ecl
{

// UART configuration ---------------------------------------------------------


/* UART-over-USB console output */
static constexpr uart_channel UART0_channel = uart_channel::ch0;
using UART0_driver = uart<UART0_channel>;
using platform_console = UART0_driver;
using test_uart = UART0_driver;

/* Example UART */
static constexpr uart_channel UART1_channel = uart_channel::ch1;
using UART1_driver = uart<UART1_channel>;
using another_uart = UART1_driver;

} // namespace ecl

And there is how theCore uses platform_console alias in console subsystem:

https://github.com/forGGe/theCore/blob/047b0a560b1b4942359ee537c0c67694a12a5175/lib/cpp/export/ecl/console_driver.hpp#L8-L23

Check also UART documentation for TM4C (again,pay attention for #365 bug): https://forgge.github.io/theCore/platform/ti-tivac-tm4c123g.html#uart

Few more thoughts

There is a less heavy abstraction that better suites for UART-based communications (and overall it is better for communication drivers that are not buses and shouldn't be shared in different modules) - https://github.com/forGGe/theCore/blob/develop/dev/bus/export/dev/serial.hpp#L25

So I want to rebase console driver from generic_bus to serial interface, i.e. instead current "chain":

static constexpr uart_channel UART0_channel = uart_channel::ch0;
using UART0_driver = uart<UART0_channel>;
using platform_console = UART0_driver;
using console_bus = ecl::generic_bus<platform_console>; 
using console_driver = ecl::console_pipe<console_bus>; 

use:

static constexpr uart_channel UART0_channel = uart_channel::ch0;
using UART0_driver = uart<UART0_channel>;
using platform_console = UART0_driver;
using console_bus = ecl::serial<platform_console>; 
using console_driver = ecl::console_pipe<console_bus>; 

But that's not related to your particular activity in KE02 platform implementation, it is just thoughts I"m sharing with you

Hope this shed some light on driver compositions in theCore.

forGGe avatar Apr 15 '18 20:04 forGGe

Can you explain a bit more about compile time interrupt dispatching as you mentioned about TM4C platform ?

Considering our discussion above about driver composition and a purpose of the user config (in JSON form), we can state that theCore is fully aware about all drivers used in the application.

Or, in other words, user must list all drivers that he want to use in that JSON.

It means that theCore knows where to deliver a specific platform interrupt. It also means that the platform driver don't need to register for interrupts in runtime. theCore can generate IRQ handler for the specific interrupt that will call corresponding platform driver routine.

Here is how it looks in TM4C.

IRQ table:

https://github.com/forGGe/theCore/blob/047b0a560b1b4942359ee537c0c67694a12a5175/platform/tm4c/export/platform/irq.S#L1-L18

IRQ handler generator:

https://github.com/forGGe/theCore/blob/047b0a560b1b4942359ee537c0c67694a12a5175/platform/tm4c/templates/irq.in.cpp#L131-L153

That if UART0 is listed in JSON will generate code similar to this:

/* 21 UART0 */
extern "C"
void UART0_Handler()
{
    ecl::uart_irq_proxy<ecl::uart_channel::ch0>::deliver_irq();
}

/* 22 UART1 */
extern "C"
void UART1_Handler()
{
    ecl::abort();
}

Ideally is to have similar thing made for KE02 platform.

Let me know your feedback about it!

forGGe avatar Apr 15 '18 20:04 forGGe

Hi @forGGe,

Thanks again for the excellent explanations. I added the UART driver for KE02 which registers to the bus system and used by iostream but can't test it as the compilation fails with the following linking error,

Scanning dependencies of target ke02_hello
[ 82%] Building CXX object CMakeFiles/ke02_hello.dir/main.cpp.obj
[ 83%] Building CXX object CMakeFiles/ke02_hello.dir/home/ishraq/git/theCore/platform/ke02/console.cpp.obj
[ 84%] Building CXX object CMakeFiles/ke02_hello.dir/home/ishraq/git/theCore/arch/arm_cm/execution.cpp.obj
[ 85%] Building CXX object CMakeFiles/ke02_hello.dir/home/ishraq/git/theCore/lib/types/err.cpp.obj
[ 86%] Building CXX object CMakeFiles/ke02_hello.dir/home/ishraq/git/theCore/lib/cpp/arm_eabi.cpp.obj
[ 88%] Building CXX object CMakeFiles/ke02_hello.dir/home/ishraq/git/theCore/lib/cpp/streams.cpp.obj
[ 89%] Building CXX object CMakeFiles/ke02_hello.dir/home/ishraq/git/theCore/lib/thread/no_os/mutex.cpp.obj
[ 90%] Building CXX object CMakeFiles/ke02_hello.dir/home/ishraq/git/theCore/lib/thread/no_os/semaphore.cpp.obj
[ 91%] Building CXX object CMakeFiles/ke02_hello.dir/home/ishraq/git/theCore/lib/thread/no_os/spinlock.cpp.obj
[ 92%] Building CXX object CMakeFiles/ke02_hello.dir/home/ishraq/git/theCore/lib/allocators/alloc.cpp.obj
[ 93%] Building CXX object CMakeFiles/ke02_hello.dir/home/ishraq/git/theCore/lib/newlib/stubs.cpp.obj
[ 94%] Linking CXX executable ke02_hello
CMakeFiles/ke02_hello.dir/home/ishraq/git/theCore/lib/thread/no_os/semaphore.cpp.obj: In function `std::__atomic_base<bool>::exchange(bool, std::memory_order)':
/nix/store/cmzy23dckxx052dq4lrh7vvfn3sqw09l-gcc-arm-embedded-5.4-2016q2-20160622/arm-none-eabi/include/c++/5.4.1/bits/atomic_base.h:413: undefined reference to `__atomic_exchange_1'
/nix/store/cmzy23dckxx052dq4lrh7vvfn3sqw09l-gcc-arm-embedded-5.4-2016q2-20160622/arm-none-eabi/include/c++/5.4.1/bits/atomic_base.h:413: undefined reference to `__atomic_exchange_1'
CMakeFiles/ke02_hello.dir/home/ishraq/git/theCore/lib/thread/no_os/semaphore.cpp.obj: In function `ecl::binary_semaphore::try_wait(std::chrono::duration<long long, std::ratio<1ll, 1000ll> >)':
/home/ishraq/git/theCore/lib/thread/no_os/semaphore.cpp:78: undefined reference to `SystemCoreClock'
collect2: error: ld returned 1 exit status
make[2]: *** [CMakeFiles/ke02_hello.dir/build.make:367: ke02_hello] Error 1
make[1]: *** [CMakeFiles/Makefile2:74: CMakeFiles/ke02_hello.dir/all] Error 2
make: *** [Makefile:84: all] Error 2

As far as I can guess it seems like something about the std::chrono library.

Here is the patch.

iia avatar Apr 16 '18 00:04 iia

Hi @iia,

Sorry for a late response.

Thanks for submitting a patch and for your feedback! I suggest you to open pull-request with [WIP] pefix in its name, so we can comment there and put backlinks in this issue.

About __atomic_exchange_1: As far as I know, M0/M0+ lacks atomic access commands. Thus, standard C/C++ library does not provide any simulating instructions for that.

You can find some info here: https://stackoverflow.com/questions/5745880/simulating-ldrex-strex-load-store-exclusive-in-cortex-m0

So you need to implement that __atomic_exchange_1 routine by yourself (or find another way to get that function, i.e. via some library). I suggest you to put it in platform.cpp file.

As far as I can google it, it should have following signature (see https://developer.arm.com/docs/100073/0609/the-arm-c-and-c-libraries/iso-c-library-implementation-definition/standard-c-library-implementation-definition):

uint8_t __atomic_exchange_1(uint8_t *dest, uint8_t val, int model);

It is a specific version of the regular atomic_exchange builtin, I guess. These builtins are described here: https://gcc.gnu.org/onlinedocs/gcc/_005f_005fatomic-Builtins.html

As for SystemCoreClock you need to do two things:

  • define global variable in platform.cpp: uint32_t SystemCoreClock;
  • initialize core clocks in platform_init()
  • write clock value to the SystemCoreClock (funny that KE02 driver lib doesn't provide such functionality)

For that, I guess you need to check datasheet and examples of PLL configuration. I propose to stick with internal oscillator for now.

Also, support for external oscillator should be added in some point in time (and clock speed for that external oscillator must be provided via user's JSON), but you can postpone it for now. .

forGGe avatar Apr 16 '18 21:04 forGGe

write clock value to the SystemCoreClock (funny that KE02 driver lib doesn't provide such functionality)

Or you can do a shortcut - if you know for sure clock configuration from a very start of the MCU, you can just set SystemCoreClock to that value. And fix that later.

forGGe avatar Apr 16 '18 21:04 forGGe

Hi,

In this case the system clock is meant to be the RTC of the MCU which is required for measuring time duration. Right?

iia avatar Apr 19 '18 11:04 iia

Hi @iia ,

Sorry, was busy with my work, thus answered so late.

I'm actually talking about main processor clock.

If you check Figure 5-1 of the KE02 Reference Manual, you will see this picture:

clock_diagram

The SystemCoreClock must be equal to the clock on the line called "Core Clock" (see right side of the picture).

Core Clock can be supplied by the ICS (Internal Clock Source) module. The ICS description is located in the same datasheet, page 263.

It has different modes of operation, one of which is FEI: FLL engaged internal, is what we are looking for.

According to the reference manual:

In FLL engaged internal mode, which is the default mode, the ICS supplies a clock derived from the FLL which is controlled by the internal reference clock.

So idea is to remove current ICS code from platform.cpp file (I have copied it from sysinit.c file of KEXX driver lib) and configure ICS to work in FEI mode (or, as RM says, it works by default) and using RM calculate which clock frequency will be on the Core Clock line.

This frequency then must be assigned to the SystemCoreClock variable.

Now, you are probably think how you going to test your assumptions about clock speed?

There is a function:

https://github.com/forGGe/theCore/blob/047b0a560b1b4942359ee537c0c67694a12a5175/arch/arm_cm/export/arch/execution.hpp#L124-L136

that you can use to measure delays. If your clock value is correct, then this function must do a delay with a right amount of milliseconds. Note that arch_spin_wait is imprecise, so use large values, like 1000ms to measure delays.

Let me know your thoughts about it.

forGGe avatar Apr 20 '18 20:04 forGGe

Hi @forGGe,

Thanks for the info on clock. But I couldn't manage to resolve the atomic exchange issue. I tried implementing the routing __atomic_exchange_1 with provided signature but with no luck. Ideas ?

iia avatar Apr 23 '18 22:04 iia