theCore-embedded / theCore

theCore: C++ embedded framework
https://forgge.github.io/theCore
Mozilla Public License 2.0
81 stars 23 forks source link

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

Open forGGe opened 7 years ago

forGGe commented 7 years ago

Task is to integrate theCore with KE02 MCUs

Refs:

Must include

forGGe commented 7 years ago

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

iia commented 6 years ago

Hi there,

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

forGGe commented 6 years ago

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.

iia commented 6 years ago

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.

forGGe commented 6 years ago

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:

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 commented 6 years ago

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.

iia commented 6 years ago

Hi @forGGe ,

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

forGGe commented 6 years ago

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 :)

iia commented 6 years ago

Hi @forGGe,

From where you ordered your board?

forGGe commented 6 years ago

From where you ordered your board?

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

forGGe commented 6 years ago

@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 commented 6 years ago

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

iia commented 6 years ago

@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?

forGGe commented 6 years ago

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 commented 6 years ago

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.

iia commented 6 years ago

@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?

forGGe commented 6 years ago

@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:

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 commented 6 years ago

BTW what does "ecl" stand for?

ECL stands for "Embedded Core Library"

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

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

iia commented 6 years ago

Hi,

Platform and target clarification was useful. Thanks.

iia commented 6 years ago

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 commented 6 years ago

Hi @forGGe,

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

forGGe commented 6 years ago

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 notifications@github.com 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 commented 6 years ago

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 commented 6 years ago

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!

iia commented 6 years ago

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.

forGGe commented 6 years ago

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:

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 commented 6 years ago

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.

iia commented 6 years ago

Hi,

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

forGGe commented 6 years ago

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.

iia commented 6 years ago

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 ?

forGGe commented 6 years ago

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 ?

Hi @iia,

It is quite strange. Let me apply your patch and try implementing it, so I can play around with it.

I'll be back to you with results.

Regards, Max

forGGe commented 6 years ago

Hi again, @iia ,

I'm sorry for late follow-up again, I'm busy these days due to my work schedule.

So, I was able to resolve link error, by using following signature:

extern "C"
uint8_t __atomic_exchange_1(volatile void *dest, uint8_t val, int model)
{
 // ... 
} 

placed in platform.cpp

I suppose, implementation should be something like this (pseudocode!):

extern "C"
uint8_t __atomic_exchange_1(volatile void *dest, uint8_t val, int model)
{
   (void)model;
   disable_irq();
   uint8_t *u8_dest = (uint8_t*)dest;
   uint8_t old_val = *u8_dest;
   *u8_dest = val;
   enable_irq();

   return old_val;
}

Note that I didn't test that implementation. Hope to hear your results!

iia commented 6 years ago

Hi @forGGe,

No worries about late replies. I couldn't try the solution yet but will later today. I can already see the signature of the function is different from what I tried with according to the ARM documentation page. How did you figure out this working function signature?

Cheers.

forGGe commented 6 years ago

Hi @iia,

Actually when I put into arch.cpp:

extern "C" uint8_t __atomic_exchange_1(uint8_t*, uint8_t, int) { /* ... */  } 

I got:

/home/user/projects/thecore/thecore/arch/arm_cm/arch.cpp:22:66: error: 
new declaration 'uint8_t __atomic_exchange_1(uint8_t*, uint8_t, int)' ambiguates 
built-in declaration 'unsigned char __atomic_exchange_1(volatile void*, unsigned char, int)' [-Werror]

So I just used that error as a guidance :)

Regards, Max

iia commented 6 years ago

Hi @forGGe,

Just if I read the error messages a bit further! Thanks BTW.

iia commented 6 years ago

Hi @forGGe ,

I created initial PR for the Kinteis KE02 support.

Cheers.

forGGe commented 6 years ago

@iia , looks awesome! Thanks! Do you want me to conduct a full code-review or just some particular part?

forGGe commented 6 years ago

By the way, examples (along with main repo) should be moved under theCore-embedded organizatoin. Relevant task for KE02 example is #379 .

For now, one example is almost moved: https://github.com/theCore-embedded/example_cs43l22_audio and similar instructions I expect for KE02 examples as well.

Note that there is no hurry in 379, I suggest to merge/complete KE02 first, and then proceed with moving examples. Nevertheless, there is a challenge of automating the binary flashing into the KE02 FRDM board.

I.e. ideally, the user should be able to do following:

tcore bootstrap
tcore init <hello_world_example_link>
cd hello-world
tcore compile --target=frdm-ke02
tcore flash

And he will get the hello-world displayed in the minicom terminal

(of course, it assumes that you have desire to mess with python a bit :) let me know what you think about it)

iia commented 6 years ago

Hi @forGGe,

A full code review would be nice.

Eventually moving the examples to "theCore-embedded" seems to be a good idea as it seem to unify the process even more. But I agree for KE02 this can be done eventually.

What would be the the next task for the KE02 port in your opinion?

Cheers.

forGGe commented 6 years ago

Hi @iia,

I think what we left with (in this task) is to:

  1. finish code review
  2. add the documentation page
  3. add the test suite for FRDM-KE02 (same as done for bunch of other platforms), see https://github.com/forGGe/theCore/tree/develop/tests/

As for (1) - review is in process, as for (2) and (3) - I'm going to create the small doc page and the test suite by myself and I will send you details how to build/run/display doc and conduct tests. So in case you have something to add or change - you will be able to do so.

As for further work on KE02, I suggest following roadmap:

forGGe commented 6 years ago

Let me know if you have suggestions for the roadmap.

forGGe commented 6 years ago

See also: https://github.com/forGGe/theCore/milestone/6