After using Arm Mbed OS to flash the LED , it is time to test and configure other important services. The following describes:
We continue our acquaintance with the technology of programming microcontrollers of the MKE18F family using ARM Mbed OS
An important component of the Mbed project is an automatic configuration and assembly system, both online and offline , i.e. locally on the user's computer. It is suggested to configure it by editing .json files with special names. Then the scripts in the Python project convert these files into header files, workspace files of the IDE selected by the user, linker batch files and other support files.
But the problem of the described method is in opacity from the point of view of source texts, since it is very difficult for us to track where and what the configuration system changes in the source code. On the other hand, in our case there are no motives to support the ability of the project to be automatically transferred to different IDEs.
Therefore, it was decided to abandon this approach. As it was written in the previous article, an online project for IDE IAR was simply generated, an unstructured pile of files was received in the IDE workspace, then they were systematized and the unnecessary was discarded. As a result, you no longer need to do configuration via .json files and there are only three specific places where the parameters affecting the Mbed configuration are located :
In the file mbed_config.h you can count about 130 defines, which at first is very annoying. But fortunately, most of them belong to the stacks of wireless protocols, which are currently not used in the project. For convenience, the records were sorted so that the actual ones are placed at the top. Initially, defaults for different modules in the mbed_config.h file are arranged randomly, but after sorting it looks like this:
#ifndef __MBED_CONFIG_DATA__ #define __MBED_CONFIG_DATA__ // Configuration parameters #define MBED_CONF_RTOS_PRESENT 1 // set by library:rtos #define MBED_ALL_STATS_ENABLED 1 //#define DEVICE_SLEEP=1 SLEEP #define MBED_CONF_APP_MAIN_STACK_SIZE 1024 #define MBED_CONF_APP_TIMER_THREAD_STACK_SIZE 512 #define MBED_CONF_APP_IDLE_THREAD_STACK_SIZE 512 #define MBED_CONF_PLATFORM_DEFAULT_SERIAL_BAUD_RATE 3000000 // set by library:platform #define MBED_CONF_PLATFORM_ERROR_ALL_THREADS_INFO 0 // set by library:platform #define MBED_CONF_PLATFORM_ERROR_FILENAME_CAPTURE_ENABLED 0 // set by library:platform #define MBED_CONF_PLATFORM_ERROR_HIST_ENABLED 0 // set by library:platform #define MBED_CONF_PLATFORM_ERROR_HIST_SIZE 4 // set by library:platform #define MBED_CONF_PLATFORM_FORCE_NON_COPYABLE_ERROR 0 // set by library:platform #define MBED_CONF_PLATFORM_MAX_ERROR_FILENAME_LEN 16 // set by library:platform #define MBED_CONF_PLATFORM_POLL_USE_LOWPOWER_TIMER 0 // set by library:platform #define MBED_CONF_PLATFORM_STDIO_BAUD_RATE 3000000 // set by library:platform #define MBED_CONF_PLATFORM_STDIO_BUFFERED_SERIAL 0 // set by library:platform #define MBED_CONF_PLATFORM_STDIO_CONVERT_NEWLINES 1 // set by library:platform #define MBED_CONF_PLATFORM_STDIO_CONVERT_TTY_NEWLINES 0 // set by library:platform #define MBED_CONF_PLATFORM_STDIO_FLUSH_AT_EXIT 1 // set by library:platform #define MBED_CONF_DRIVERS_UART_SERIAL_RXBUF_SIZE 256 // set by library:drivers #define MBED_CONF_DRIVERS_UART_SERIAL_TXBUF_SIZE 256 // set by library:drivers #define MBED_CONF_EVENTS_PRESENT 1 // set by library:events #define MBED_CONF_EVENTS_SHARED_DISPATCH_FROM_APPLICATION 0 // set by library:events #define MBED_CONF_EVENTS_SHARED_EVENTSIZE 256 // set by library:events #define MBED_CONF_EVENTS_SHARED_HIGHPRIO_EVENTSIZE 256 // set by library:events #define MBED_CONF_EVENTS_SHARED_HIGHPRIO_STACKSIZE 1024 // set by library:events #define MBED_CONF_EVENTS_SHARED_STACKSIZE 1024 // set by library:events #define MBED_CONF_EVENTS_USE_LOWPOWER_TIMER_TICKER 0 // set by library:events #define MBED_CONF_CELLULAR_DEBUG_AT 0 // set by library:cellular #define MBED_CONF_CELLULAR_RANDOM_MAX_START_DELAY 0 // set by library:cellular #define MBED_CONF_CELLULAR_USE_APN_LOOKUP 1 // set by library:cellular #define MBED_CONF_FILESYSTEM_PRESENT 1 // set by library:filesystem #define MBED_CONF_KINETIS_EMAC_RX_RING_LEN 16 // set by library:kinetis-emac #define MBED_CONF_KINETIS_EMAC_TX_RING_LEN 8 // set by library:kinetis-emac #define MBED_CONF_LORA_ADR_ON 1 // set by library:lora #define MBED_CONF_LORA_APP_PORT 15 // set by library:lora #define MBED_CONF_LORA_APPLICATION_EUI {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00} // set by library:lora #define MBED_CONF_LORA_APPLICATION_KEY {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00} // set by library:lora #define MBED_CONF_LORA_APPSKEY {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00} // set by library:lora #define MBED_CONF_LORA_AUTOMATIC_UPLINK_MESSAGE 1 // set by library:lora #define MBED_CONF_LORA_DEVICE_ADDRESS 0x00000000 // set by library:lora #define MBED_CONF_LORA_DEVICE_EUI {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00} // set by library:lora #define MBED_CONF_LORA_DUTY_CYCLE_ON 1 // set by library:lora #define MBED_CONF_LORA_LBT_ON 0 // set by library:lora #define MBED_CONF_LORA_NB_TRIALS 12 // set by library:lora #define MBED_CONF_LORA_NWKSKEY {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00} // set by library:lora #define MBED_CONF_LORA_OVER_THE_AIR_ACTIVATION 1 // set by library:lora #define MBED_CONF_LORA_PHY EU868 // set by library:lora #define MBED_CONF_LORA_PUBLIC_NETWORK 1 // set by library:lora #define MBED_CONF_LORA_TX_MAX_SIZE 64 // set by library:lora #define MBED_CONF_LWIP_ADDR_TIMEOUT 5 // set by library:lwip #define MBED_CONF_LWIP_ADDR_TIMEOUT_MODE 1 // set by library:lwip #define MBED_CONF_LWIP_DEBUG_ENABLED 0 // set by library:lwip #define MBED_CONF_LWIP_DEFAULT_THREAD_STACKSIZE 512 // set by library:lwip #define MBED_CONF_LWIP_ENABLE_PPP_TRACE 0 // set by library:lwip #define MBED_CONF_LWIP_ETHERNET_ENABLED 1 // set by library:lwip #define MBED_CONF_LWIP_IP_VER_PREF 4 // set by library:lwip #define MBED_CONF_LWIP_IPV4_ENABLED 1 // set by library:lwip #define MBED_CONF_LWIP_IPV6_ENABLED 0 // set by library:lwip #define MBED_CONF_LWIP_MEM_SIZE 36560 // set by library:lwip[Freescale] #define MBED_CONF_LWIP_PPP_THREAD_STACKSIZE 768 // set by library:lwip #define MBED_CONF_LWIP_SOCKET_MAX 4 // set by library:lwip #define MBED_CONF_LWIP_TCP_ENABLED 1 // set by library:lwip #define MBED_CONF_LWIP_TCP_SERVER_MAX 4 // set by library:lwip #define MBED_CONF_LWIP_TCP_SOCKET_MAX 4 // set by library:lwip #define MBED_CONF_LWIP_TCPIP_THREAD_STACKSIZE 1200 // set by library:lwip #define MBED_CONF_LWIP_UDP_SOCKET_MAX 4 // set by library:lwip #define MBED_CONF_LWIP_USE_MBED_TRACE 0 // set by library:lwip #define MBED_CONF_MBED_MESH_API_6LOWPAN_ND_CHANNEL 0 // set by library:mbed-mesh-api #define MBED_CONF_MBED_MESH_API_6LOWPAN_ND_CHANNEL_MASK 0x7fff800 // set by library:mbed-mesh-api #define MBED_CONF_MBED_MESH_API_6LOWPAN_ND_CHANNEL_PAGE 0 // set by library:mbed-mesh-api #define MBED_CONF_MBED_MESH_API_6LOWPAN_ND_DEVICE_TYPE NET_6LOWPAN_ROUTER // set by library:mbed-mesh-api #define MBED_CONF_MBED_MESH_API_6LOWPAN_ND_PANID_FILTER 0xffff // set by library:mbed-mesh-api #define MBED_CONF_MBED_MESH_API_6LOWPAN_ND_PSK_KEY {0xa0, 0xa1, 0xa2, 0xa3, 0xa4, 0xa5, 0xa6, 0xa7, 0xa8, 0xa9, 0xaa, 0xab, 0xac, 0xad, 0xae, 0xaf} // set by library:mbed-mesh-api #define MBED_CONF_MBED_MESH_API_6LOWPAN_ND_PSK_KEY_ID 1 // set by library:mbed-mesh-api #define MBED_CONF_MBED_MESH_API_6LOWPAN_ND_SEC_LEVEL 5 // set by library:mbed-mesh-api #define MBED_CONF_MBED_MESH_API_6LOWPAN_ND_SECURITY_MODE NONE // set by library:mbed-mesh-api #define MBED_CONF_MBED_MESH_API_HEAP_SIZE 32500 // set by library:mbed-mesh-api #define MBED_CONF_MBED_MESH_API_THREAD_CONFIG_CHANNEL 22 // set by library:mbed-mesh-api #define MBED_CONF_MBED_MESH_API_THREAD_CONFIG_CHANNEL_MASK 0x7fff800 // set by library:mbed-mesh-api #define MBED_CONF_MBED_MESH_API_THREAD_CONFIG_CHANNEL_PAGE 0 // set by library:mbed-mesh-api #define MBED_CONF_MBED_MESH_API_THREAD_CONFIG_COMMISSIONING_DATASET_TIMESTAMP 0x10000 // set by library:mbed-mesh-api #define MBED_CONF_MBED_MESH_API_THREAD_CONFIG_EXTENDED_PANID {0xf1, 0xb5, 0xa1, 0xb2,0xc4, 0xd5, 0xa1, 0xbd } // set by library:mbed-mesh-api #define MBED_CONF_MBED_MESH_API_THREAD_CONFIG_ML_PREFIX {0xfd, 0x0, 0x0d, 0xb8, 0x0, 0x0, 0x0, 0x0} // set by library:mbed-mesh-api #define MBED_CONF_MBED_MESH_API_THREAD_CONFIG_NETWORK_NAME "Thread Network" // set by library:mbed-mesh-api #define MBED_CONF_MBED_MESH_API_THREAD_CONFIG_PANID 0x0700 // set by library:mbed-mesh-api #define MBED_CONF_MBED_MESH_API_THREAD_CONFIG_PSKC {0xc8, 0xa6, 0x2e, 0xae, 0xf3, 0x68, 0xf3, 0x46, 0xa9, 0x9e, 0x57, 0x85, 0x98, 0x9d, 0x1c, 0xd0} // set by library:mbed-mesh-api #define MBED_CONF_MBED_MESH_API_THREAD_DEVICE_TYPE MESH_DEVICE_TYPE_THREAD_ROUTER // set by library:mbed-mesh-api #define MBED_CONF_MBED_MESH_API_THREAD_MASTER_KEY {0x10, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88, 0x99, 0xaa, 0xbb, 0xcc, 0xdd, 0xee, 0xff} // set by library:mbed-mesh-api #define MBED_CONF_MBED_MESH_API_THREAD_PSKD "ABCDEFGH" // set by library:mbed-mesh-api #define MBED_CONF_MBED_MESH_API_THREAD_SECURITY_POLICY 255 // set by library:mbed-mesh-api #define MBED_CONF_MBED_MESH_API_THREAD_USE_STATIC_LINK_CONFIG 1 // set by library:mbed-mesh-api #define MBED_CONF_MBED_MESH_API_USE_MALLOC_FOR_HEAP 0 // set by library:mbed-mesh-api #define MBED_CONF_NANOSTACK_CONFIGURATION nanostack_full // set by library:nanostack #define MBED_CONF_NANOSTACK_HAL_CRITICAL_SECTION_USABLE_FROM_INTERRUPT 0 // set by library:nanostack-hal #define MBED_CONF_NANOSTACK_HAL_EVENT_LOOP_DISPATCH_FROM_APPLICATION 0 // set by library:nanostack-hal #define MBED_CONF_NANOSTACK_HAL_EVENT_LOOP_THREAD_STACK_SIZE 6144 // set by library:nanostack-hal #define MBED_CONF_NANOSTACK_HAL_EVENT_LOOP_USE_MBED_EVENTS 0 // set by library:nanostack-hal #define MBED_CONF_NANOSTACK_HAL_NVM_CFSTORE 0 // set by library:nanostack-hal #define MBED_CONF_NSAPI_DEFAULT_MESH_TYPE THREAD // set by library:nsapi #define MBED_CONF_NSAPI_DEFAULT_STACK LWIP // set by library:nsapi #define MBED_CONF_NSAPI_DEFAULT_WIFI_SECURITY NONE // set by library:nsapi #define MBED_CONF_NSAPI_DNS_CACHE_SIZE 3 // set by library:nsapi #define MBED_CONF_NSAPI_DNS_RESPONSE_WAIT_TIME 5000 // set by library:nsapi #define MBED_CONF_NSAPI_DNS_RETRIES 0 // set by library:nsapi #define MBED_CONF_NSAPI_DNS_TOTAL_ATTEMPTS 3 // set by library:nsapi #define MBED_CONF_NSAPI_PRESENT 1 // set by library:nsapi #define MBED_CONF_PPP_CELL_IFACE_APN_LOOKUP 1 // set by library:ppp-cell-iface #define MBED_CONF_PPP_CELL_IFACE_AT_PARSER_BUFFER_SIZE 256 // set by library:ppp-cell-iface #define MBED_CONF_PPP_CELL_IFACE_AT_PARSER_TIMEOUT 8000 // set by library:ppp-cell-iface #define MBED_CONF_PPP_CELL_IFACE_BAUD_RATE 115200 // set by library:ppp-cell-iface #define MBED_CONF_TARGET_NETWORK_DEFAULT_INTERFACE_TYPE ETHERNET // set by target:K66F #define MBED_LFS_BLOCK_SIZE 512 // set by library:littlefs #define MBED_LFS_ENABLE_INFO 0 // set by library:littlefs #define MBED_LFS_INTRINSICS 1 // set by library:littlefs #define MBED_LFS_LOOKAHEAD 512 // set by library:littlefs #define MBED_LFS_PROG_SIZE 64 // set by library:littlefs #define MBED_LFS_READ_SIZE 64 // set by library:littlefs #define NSAPI_PPP_AVAILABLE 0 // set by library:lwip #define NSAPI_PPP_IPV4_AVAILABLE 1 // set by library:lwip #define NSAPI_PPP_IPV6_AVAILABLE 0 // set by library:lwip #define NVSTORE_ENABLED 1 // set by library:nvstore #define NVSTORE_MAX_KEYS 16 // set by library:nvstore // Macros #define _RTE_ // defined by library:rtos #define NS_USE_EXTERNAL_MBED_TLS // defined by library:nanostack #define UNITY_INCLUDE_CONFIG_H // defined by library:utest #endif
The top-level API in Mbed is written in C ++ , so this language must also be used in application code. But there are nuances that you need to know.
Using C ++ for RTOS in small embedded systems is a comparative rarity. The problem here is that successful RTOS projects tend to be multiplatform, and C ++ places increased demands on the management of platform resources compared to C. The reason is the desire to hide from the user details of low-level resource management. This is primarily about memory resources. Constructors, destructors, threads, exceptions with automatic destruction, patterns of objects of data structures, etc. use implicit operations with dynamic memory. But the resource of RAM in small systems is very limited. RAM is the most scarce resource in such systems and especially in RTOS . In RTOS, each task is allocated a stack, the developer cannot predict its exact size and therefore chooses with a margin. Thus, the presence of RTOS with a dozen tasks immediately causes the need for RAM ranging in size from 10 to 30 kB. A lot of memory is needed for various parsers and protocols (HTTP, HTML ...) and file systems. If a display is used, then the requirements for free RAM increase even more.
IAR type development environment libraries are equipped with quite good dynamic memory managers, but they are designed for single-threaded execution environments. For them to start working in RTOS, you need to write additional code. This process is called retargeting .
In RTOS written in C, retargeting is usually not performed. Since there are no implicit operations with dynamic memory at the language level, all operations are performed explicitly by calling their own thread-safe versions of the malloc and free functions. The programmer has full control over operations with dynamic memory and can easily apply all possible measures to save it.
In the case of C ++, if we want to use all the features of this language, we will have to do retargeting . But retargeting in each development environment is a purely individual process. This makes life difficult for RTOS developers.
The figure below is an example of the structure of calls with retargeting. The __write , __lseek , __read functions can be user-defined and not implemented, but then their functionality is left to the discretion of the IDE . And certainly printf and scanf will not be multi-threaded.
Mbed is one of the few, if not the only, RTOS that provides source code with already done retargeting for the triad of known development tools: GCC , IAR , Keil
Despite all the above, you can find articles on porting RTOS to C ++ without performing retargeting, for example, solving a problem by simply replacing some common standard functions with your own. This can work, but the programmer then needs to remember about various implicit and undocumented restrictions when using C ++ constructs in IAR (only static constructors, check all templates for new , reject exceptions, etc.). It will already be difficult to call C ++ . Mbed as a user-friendly system removes many such restrictions, approaching the simplicity of the Arduino .
In addition, in recent versions of IAR there are difficulties in switching to C11 and C ++ 14, which is written here - https://www.iar.com/support/resources/articles/exploring-c11-and-c14/
Oddly enough, but finding a class or a function or something suitable for organizing interrupt service in the Mbed API will fail. You can only find the InterruptIn class, which is meant only for external ports.
Answers to such questions should be sought in the CMSIS-RTOS , namely in the CMSIS Cortex-M4 Core Peripheral Access Layer . There are defined macros:
Here is how the SysTick timer interrupt organization is initialized:
NVIC_SetVector(mbed_get_m0_tick_irqn(), (uint32_t)SysTick_Handler); // mbed_get_m0_tick_irqn SysTick. // SysTick_IRQn MKE18F16.h // SysTick_Handler . NVIC_SetPriority(mbed_get_m0_tick_irqn(), 0xFF); // 0xFF . . NVIC MKE18F16 16 . .. 4- . NVIC_EnableIRQ(mbed_get_m0_tick_irqn()); // .
The priorities of Mbed tasks and interrupt priorities should not be confused.
If no priority is assigned, then by default it is set to maximum.
From the interrupt handlers assigned in this way, you can call any RTOS services that do not raise expectations. Those. transmit flags, semaphores, messages, mailboxes, and so on. Services are called, however, not from the ISR itself, but by calling a software interrupt by setting the PENDSVSET bit in the Interrupt Control and State Register ( ICSR ) register of the Cortex-M core control block ( SCB ). Those. after the current interrupt handler is completed, if there are no other priority interrupts, the PendSV vector system handler will be called where the service will be performed.
Dynamic memory or heap or otherwise heap is a required component when programming in C ++ . In our Mbed project , under IAR , the size of this memory area is determined in the configuration file of the linker MKE18F512xxx16_flash.icf by writing to the variable __size_heap__ . The size is set so that it takes up all the remaining free memory. How much free memory is left to know from the .map file after compilation, i.e. determining the size of the heap is an iterative process.
An important issue when using C ++ is where and how the constructors of global objects are called. Even in serious RTOS , for example, MAX , this is overlooked, i.e. let loose. There, designers are engaged in a standard single-threaded development environment library with the usual single-threaded memory allocation mechanism. But after the start, the common RTOSs create their own dynamic memory management mechanism, while the memory occupied by global objects remains forgotten. This is a hole in our efforts to save memory and control everything.
In Mbed , this issue was approached much more seriously. There for each development environment has its own approach. In IAR, this is done like this:
Mbed uses IAR library adapters for multi-thread mode.
About adapting IAR for multithreading can be found here - http://supp.iar.com/FilesPublic/UPDINFO/005691/arm/doc/infocenter/DLIBThreadSupport.html
Mbed has adapted both system locks ( System locks ) and stream locks ( File stream locks ) of the IAR library. They are implemented in the mbed_boot.c file and use OS mutexes .
In the __iar_program_start function , executed in the very first lines of the startup_MKE18F16.s file, the stack is initialized and the OS dynamic memory by calling mbed_set_stack_heap
Cutting tasks down to a minimum is the most attractive option for saving RAM .
For tasks to require less stack, different techniques are applied. For example, the stack is strongly influenced by library functions for outputting and formatting printf , sprintf , scanf, and so on lines. They have the ability to allocate large temporary storage areas on the stack. If we refuse to use these functions in a task, we will be able to reduce the task stack to some good few hundred bytes.
Mbed OS at start immediately creates three tasks with the names: "main_thread" , "timer_thread" , "idle_thread" . The default stack size for them was determined by macros in the header file mbed_rtx_conf.h . We moved the declarations of these stacks to the mbed_config.h configuration file and reduced the size of the stacks. Now the definitions look like this:
Dynamic memory as well as a stack are resources that require constant attention. To see how much dynamic memory is used and what is the intensity of requests to it, how much stack is left for each task and what was the peak load of the stacks in Mbed there are special counters. By default, they are disabled by the conditional compilation directive; to enable them, you must declare define MBED_ALL_STATS_ENABLED . When define is declared, you need to write your procedure to display information to the user. We wrote a special procedure for outputting statistics to the VT100 terminal emulator, which will be discussed later.
In addition to the tools provided by the OS, the IAR development environment in the latest versions adds a new feature - stack canaries . Read about them here . General issues of stack overflow protection are discussed here and here .
A truly profound study of the work of Mbed on the new platform is only possible using the JTAG / SWD debugger.
Mbed sources are rich in multi-level macros and conditional compilation instructions. Just looking at the source you can not say which functions work and which do not, where the program goes and where it does not go. The only way out is to connect the debugger and analyze the execution path of the program step by step. Already at the porting stage it is almost impossible to do without step-by-step debugging.
I would recommend the Segger debuggers from J-Link Pro and J-Link Ultra . They are distinguished by high throughput, several times higher than that of common cheap models. For debugging systems with a hard real time is important. When tracing fast events, these debuggers are less prone to overflows and require less debugging iterations. In addition to step-by-step debugging, they are able to perform an interrupt log, keep statistics on interrupts, including their execution duration, support RTT and ITM debugging technologies, intercept hardware exceptions and other functions.
Below is a view of the IAR debugger window when working through a J-Link adapter.
You should not save, 90% of development time is spent on debugging. Although the more expensive JS -Trace traders from Segger no longer offer much advantage, since the MKE18F series does not have a special trace interface.
The second debugging tool, of course, is I / O via UART . Mbed has implemented at least four different technologies for accessing the serial data exchange channel via UART ,
It:
A rather unusual variety. All four can be used simultaneously for output to the same port. Some of them are more functional, some less, some are documented, and some are not. In the future, in our project we will use RawSerial , as the least resource- intensive class.
To flash the LED, the wait function from the Mbed OS API was used. In the last article was told about the problems of its porting. But this is not all, except that Mbed keeps a counter of its work (it can be read with the function mbed_stats_cpu_get ) and there is a timer API . These services use low-level functions from the lp_ticker.c file. In this file, an LPTMR timer from the Kinetis peripheral set is used to organize the time count . In the process of porting, this file was edited to match the clocking methods applied in the microcontroller MKE18F512VLL16 .
Thus, the Mbed port completely captures two counter modules - PIT and LPTMR and the SysTick core timer . This must be remembered when planning resources for an application.
The chips of the MKE18F family have built-in ROM with boot loader via serial interfaces: UART, CAN, SPI, I2C . But we plan to use our secure bootloader on our board, so the work of a regular bootloader is undesirable.
In this case, the Kinetis chips should pay attention to the contents of the Program Flash area at 0x040D . There is stored a constant defining the order of the initial load. In our case, the constant 0x7B should be written there , indicating the start from the Flash memory, not from the ROM and disabling the NMI function on the external output. If this constant is different, the program may hang in the built-in loader accidentally called from ROM.
It is also important to remember that writing to the controller's Flash memory is possible only at a core frequency of 120 MHz and not higher, i.e. in HRUN mode , writing to Flash is not possible.
The board of our controller is designed for industrial use, and therefore you cannot do without Watchdog .
Initially, the DISABLE_WDOG macro in the system_MKE18F16.h file was set to disable the watchdog . To remedy the situation, this macro was erased and its WDOG initialization was implemented.
Watchdog initialization is done in the SystemInit function. The watchdog counter update is done in the IDLE task.
This approach requires that higher-priority tasks not to capture the processor exclusively for more than 100 ms . But this can easily happen, for example, when large data dumps are output to the terminal. Therefore, everywhere we break up lengthy procedures in tasks with a priority greater than that of IDLE into short fragments interspersed with pauses using the wait function.
SDK drivers have the fsl prefix located in the NXP_MKE18F_drivers directory and are a kind of peripheral abstraction layer. They, in theory, should facilitate the programming of difficult-to-learn peripherals, but unfortunately are minimally documented. Rather, their documentation is limited to comments in the function headers. There is confusion for whom they are then written, and how they can free us from studying the manuals on the periphery of the microcontroller. My answer is no way. Drivers just help easier to transfer programs to different microcontrollers within the same family. But in order to use them effectively you need to very well deal with the documentation on the periphery. Thus, the SDK drivers solve a rather private problem of the developers of the drivers themselves, far from the needs of users beginning to learn Kinetis .
Drivers are also designed to work on all chips of the family i. to be universal and therefore saturated with conditional macros and checks that do not carry any useful function for each specific chip.
Drivers in some other ways can help to better understand how to handle the periphery, but after the arrival of driver understanding, you can safely ignore.
In connection with the above, it should not be surprising that in this project, access to the periphery of the port not affected by Mbed goes directly past the drivers.
However, there may be concerns about the dependencies of the work of one or another peripheral on the presence of SDK drivers. Here it is necessary to investigate the source code of the drivers. The main danger of dependencies comes from the separation of functions by DMA drivers. To prevent this from happening, you need to track down and prohibit Mbed’s standard services from using DMA when working with peripherals. If the DMA remains untouched by the SDK drivers, then practically everything that does not apply to the 2 mentioned timer modules ( PIT and LPTMR ) and the debug UART can be thrown out or ignored from the NXP_MKE18F_drivers directory.
A lesser danger, but also significant, may come from the assignment of priorities to the peripherals involved in the SDK driver. For example, you need to know what priority is assigned to the SysTick interrupt, the debug UART, and the timers. In a situation where their priority is equal to or higher than the priority of the periphery used in real-time control, this may lead to degradation of the quality of management.
Remember that the port Mbed for MKE18F initiates interrupts for UART and timers without prioritization, i.e. they get the maximum level by default.
Source: https://habr.com/ru/post/422413/
All Articles