Spi (перевод из книги mastering stm32)

Содержание

Обзор продуктовых линеек

STM32L

Семейство STM32 имеет широкий ассортимент изделий, различающихся по объему памяти, производительности, потреблению энергии и другим характеристикам.

Серии STM32F-1, STM32F-2 и STM32L полностью совместимы. Каждая из серий имеет десятки микросхем, которые можно без труда поменять на другие изделия. STM32F-1 была первой линейкой, ее производительность была ограничена. Из-за этого по характеристикам контроллеры быстро догнали изделия семейства Stellaris и LPC17. Позднее была выпущена STM32F-2 с улучшенными характеристиками – тактовая частота достигала 120 МГц. Отличается высокой процессорной мощностью, которая достигнута благодаря новой технологии производства 90 нм. Линейка STM32L представлена моделями, которые изготовлены по специальному технологическому процессу. Утечки транзисторов минимальны, благодаря чему приборы показывают лучшие значения.

Важно отметить, что контроллеры линейки STM32W не имеют pin-to-pin совместимости с STM32F-1, STM32F-2 и STM32L. Причина заключается в том, что линейку разрабатывала компания, которая предоставила радиочастотную часть

Это наложило ограничения на разработку для компании ST.

STM32F100R4

Микросхема STM32F100R4 имеет минимальный набор функций. Объем флэш памяти составляет 16 Кбайт, ОЗУ – 4 Кбайт, тактовая частота составляет 12 МГц. Если требуется более быстрое устройство с увеличенным объемом флэш-памяти до 128 Кбайт, подойдет STM32F101RB. USB интерфейс имеется у изделия STM32F103RE. Существует аналогичное устройство, но с более низким потреблением – это STM32L151RB.

CPUのみを使う場合

  1. 不要ファイルの除外
    下記ファイルをコンパイル対象から除外する。
    (他の.cファイルをインクルードするだけのファイル。コンパイル対象とすると2重定義でエラーになる。)
    — Source/BasicMathFunctions/BasicMathFunctions.c
    — Source/CommonTables/CommonTables.c
    — Source/ComplexMathFunctions/ComplexMathFunctions.c
    — Source/ControllerFunctions/ControllerFunctions.c
    — Source/FastMathFunctions/FastMathFunctions.c
    — Source/FilteringFunctions/FilteringFunctions.c
    — Source/MatrixFunctions/MatrixFunctions.c
    — Source/StatisticsFunctions/StatisticsFunctions.c
    — Source/SupportFunctions/SupportFunctions.c
    — Source/TransformFunctions/TransformFunctions.c

Directory Structure

Directory Content
CMSIS/Core CMSIS-Core(M) related files (for release)
CMSIS/Core_A CMSIS-Core(A) related files (for release)
CMSIS/CoreValidation Validation for Core(M) and Core(A) (NOT part of release)
CMSIS/DAP CMSIS-DAP related files and examples
CMSIS/Driver CMSIS-Driver API headers and template files
CMSIS/DSP CMSIS-DSP related files
CMSIS/NN CMSIS-NN related files
CMSIS/RTOS RTOS v1 related files (for Cortex-M)
CMSIS/RTOS2 RTOS v2 related files (for Cortex-M & Armv8-M)
CMSIS/Pack CMSIS-Pack examples and tutorials
CMSIS/DoxyGen Source of the documentation
CMSIS/Utilities Utility programs

Contributions and Pull Requests

Contributions are accepted under Apache 2.0. Only submit contributions where you have authored all of the code.

Issues and Labels

Please feel free to raise an issue on GitHub
to report misbehavior (i.e. bugs) or start discussions about enhancements. This
is your best way to interact directly with the maintenance team and the community.
We encourage you to append implementation suggestions as this helps to decrease the
workload of the very limited maintenance team.

We will be monitoring and responding to issues as best we can.
Please attempt to avoid filing duplicates of open or closed items when possible.
In the spirit of openness we will be tagging issues with the following:

  • bug – We consider this issue to be a bug that will be investigated.

  • wontfix — We appreciate this issue but decided not to change the current behavior.

  • enhancement – Denotes something that will be implemented soon.

  • future — Denotes something not yet schedule for implementation.

  • out-of-scope — We consider this issue loosely related to CMSIS. It might by implemented outside of CMSIS. Let us know about your work.

  • question – We have further questions to this issue. Please review and provide feedback.

  • documentation — This issue is a documentation flaw that will be improved in future.

  • review — This issue is under review. Please be patient.

  • DONE — We consider this issue as resolved — please review and close it. In case of no further activity this issues will be closed after a week.

  • duplicate — This issue is already addressed elsewhere, see comment with provided references.

  • Important Information — We provide essential informations regarding planned or resolved major enhancements.

Pre-processor Macros

Each library project have differant pre-processor macros.

UNALIGNED_SUPPORT_DISABLE:

Define macro UNALIGNED_SUPPORT_DISABLE, If the silicon does not support unaligned memory access

ARM_MATH_BIG_ENDIAN:

Define macro ARM_MATH_BIG_ENDIAN to build the library for big endian targets. By default library builds for little endian targets.

ARM_MATH_MATRIX_CHECK:

Define macro ARM_MATH_MATRIX_CHECK for checking on the input and output sizes of matrices

ARM_MATH_ROUNDING:

Define macro ARM_MATH_ROUNDING for rounding on support functions

ARM_MATH_CMx:

Define macro ARM_MATH_CM4 for building the library on Cortex-M4 target, ARM_MATH_CM3 for building library on Cortex-M3 target and ARM_MATH_CM0 for building library on Cortex-M0 target, ARM_MATH_CM0PLUS for building library on Cortex-M0+ target, and ARM_MATH_CM7 for building the library on cortex-M7.

__FPU_PRESENT:

Initialize macro __FPU_PRESENT = 1 when building on FPU supported Targets. Enable this macro for M4bf and M4lf libraries

When using only CPU

  1. Exclude unnecessary files
    Exclude the following files from compilation.
    (Just include other .c files. Duplicate definitions result in an error at compile.)
    — Source/BasicMathFunctions/BasicMathFunctions.c
    — Source/CommonTables/CommonTables.c
    — Source/ComplexMathFunctions/ComplexMathFunctions.c
    — Source/ControllerFunctions/ControllerFunctions.c
    — Source/FastMathFunctions/FastMathFunctions.c
    — Source/FilteringFunctions/FilteringFunctions.c
    — Source/MatrixFunctions/MatrixFunctions.c
    — Source/StatisticsFunctions/StatisticsFunctions.c
    — Source/SupportFunctions/SupportFunctions.c
    — Source/TransformFunctions/TransformFunctions.c

Using the Library

The library installer contains prebuilt versions of the libraries in the folder.

  • arm_cortexM7lfdp_math.lib (Little endian and Double Precision Floating Point Unit on Cortex-M7)
  • arm_cortexM7bfdp_math.lib (Big endian and Double Precision Floating Point Unit on Cortex-M7)
  • arm_cortexM7lfsp_math.lib (Little endian and Single Precision Floating Point Unit on Cortex-M7)
  • arm_cortexM7bfsp_math.lib (Big endian and Single Precision Floating Point Unit on Cortex-M7)
  • arm_cortexM7l_math.lib (Little endian on Cortex-M7)
  • arm_cortexM7b_math.lib (Big endian on Cortex-M7)
  • arm_cortexM4lf_math.lib (Little endian and Floating Point Unit on Cortex-M4)
  • arm_cortexM4bf_math.lib (Big endian and Floating Point Unit on Cortex-M4)
  • arm_cortexM4l_math.lib (Little endian on Cortex-M4)
  • arm_cortexM4b_math.lib (Big endian on Cortex-M4)
  • arm_cortexM3l_math.lib (Little endian on Cortex-M3)
  • arm_cortexM3b_math.lib (Big endian on Cortex-M3)
  • arm_cortexM0l_math.lib (Little endian on Cortex-M0 / CortexM0+)
  • arm_cortexM0b_math.lib (Big endian on Cortex-M0 / CortexM0+)

The library functions are declared in the public file which is placed in the folder. Simply include this file and link the appropriate library in the application and begin calling the library functions. The Library supports single public header file for Cortex-M7/M4/M3/M0/M0+ with little endian and big endian. Same header file will be used for floating point unit(FPU) variants. Define the appropriate pre processor MACRO ARM_MATH_CM7 or ARM_MATH_CM4 or ARM_MATH_CM3 or ARM_MATH_CM0 or ARM_MATH_CM0PLUS depending on the target processor in the application.

Overview of CMSIS Components

The following is an list of all CMSIS components that are available.

CMSIS-… Target Processors Description
All Cortex-M, SecurCore Standardized API for the Cortex-M processor core and peripherals. Includes intrinsic functions for Cortex-M4/M7/M33/M35P SIMD instructions.
Cortex-A5/A7/A9 API and basic run-time system for the Cortex-A5/A7/A9 processor core and peripherals.
All Cortex-M, SecurCore Generic peripheral driver interfaces for middleware. Connects microcontroller peripherals with middleware that implements for example communication stacks, file systems, or graphic user interfaces.
All Cortex-M DSP library collection with over 60 Functions for various data types: fixed-point (fractional q7, q15, q31) and single precision floating-point (32-bit). Implementations optimized for the SIMD instruction set are available for Cortex-M4/M7/M33/M35P.
All Cortex-M Collection of efficient neural network kernels developed to maximize the performance and minimize the memory footprint on Cortex-M processor cores.
Cortex-M0/M0+/M3/M4/M7 Common API for real-time operating systems along with a reference implementation based on RTX. It enables software components that can work across multiple RTOS systems.
All Cortex-M, Cortex-A5/A7/A9 Extends CMSIS-RTOS v1 with Armv8-M support, dynamic object creation, provisions for multi-core systems, binary compatible interface.
All Cortex-M, SecurCore, Cortex-A5/A7/A9 Describes a delivery mechanism for software components, device parameters, and evaluation board support. It simplifies software re-use and product life-cycle management (PLM).
All Cortex-M, SecurCore Peripheral description of a device that can be used to create peripheral awareness in debuggers or CMSIS-Core header files.
All Cortex Firmware for a debug unit that interfaces to the CoreSight Debug Access Port.
All Cortex-M Defines methods to describe system resources and to partition these resources into multiple projects and execution areas.

GPIO.CPP

В конструкторе класса сохраняется ссылка на порт и тактируется выбранный порт.

В методе конфигурации сохраняем заданный режим в переменную pin_m. Это нужно для того, чтобы при использовании методов setPin()/resetPin() и заданном режиме альтернативной функции эти методы не управляли выводом, так как в данном случае управление должно осуществляться из модуля альтернативной функции.

Далее проверяем задан ли режим входа с подтяжкой. Если задан то меняем переменную pin_mode так как для обоих режимов входа с подтяжкой биты пина конфигурируются одинаково, а выбор подтяжки к питанию или земле осуществляется записью в регистр ODR 1 или 0.

В условии if ( pin_nomber < 8 ) и аналогичном if ( pin_nomber > 7 ) рассчитываем смещение относительно начала регистра CRL или CRH соответственно, учитывая, что на вывод отводится 4 бита, и кладем в переменную offset. Затем сначала затираем биты конфигурации маской GPIO BIT MASK, а затем записываем новые биты конфигурации вывода.

if ( pin_mode == INPUT_PULL_UP ) — проверяем, если задан режим подтяжки к питанию, то выставляем в регистре ODR единицу. Аналогично проверяем режим подтяжки к земле и скидываем бит, если условие верно.

В методе setPin() сначала проверяем не задана ли альтернативная функция. Если да, то выходим ничего не делая. Далее в регистре BSSR устанавливаем 1 на соответствующий вывод.

В методе resetPin() все аналогично предыдущему, за исключением того, что пишем в регистр BRR тем самым скидывая вывод.

В методе getPin() создаем маску для сравнения, сравниваем регистр IDR с маской. Если тру — возвращаем 1, иначе 0.

Применяется все это дело так :

Function Classification

The functions can be classified into two segments

  • Legacy functions supporting ARM’s internal symmetric quantization(8 bits).
  • Functions that support TensorFlow Lite framework with symmetric quantization(8 bits).

The legacy functions can be identified with their suffix of _q7 or _q15 and are no new development is done there. The article in describes in detail how to run a network using the legacy functions.

The functions supporting TensorFlow Lite framework is identified by the _s8 suffix and can be invoked from TFL micro. The functions are bit exact to TensorFlow Lite. Refer to the TensorFlow’s documentation in on how to run a TensorFlow Lite model using optimized CMSIS-NN kernels.

Build and Debug

With this, everything should be in place to compile, link and download without errors. But if I step into the CMSIS functions, I get a message from the debugger that it cannot find the source file:

Can’t find a source file

The reason is that I’m using the precompiled libraries from ARM, and obviously that person was using a different path to the CMSIS library.

To help the debugger to find the source, I’m going to add a path mapping. I press the ‘Edit Source Lookup Path’ button:

Edit Source Lookup Path

Then I select Path Mapping:

Add a container to the source lookup path

Then I specify that ‘c:\working\CMSIS_Setup\CMSIS shall be replace with the path on my machine:

Specified Path Mapping

Now it shows the source properly:

Showing CMSIS Source

On a side note: the debugger launch configuration has as well a panel to configure where the debugger is looking for source files:

Debugger Source File Mapping

GPIO.H

У выводов контроллера есть несколько режимов работы. Они задаются в регистрах GPIOx_CRL ( для выводов от 0 до 7 ) и GPIOx_CRH ( для выводов от 8 до 15 ). На каждый вывод в этих регистрах отводится по 4 бита, которые и задают режим работы. Чтобы не вспоминать каждый раз какие биты нужно прописать на каком месте для определенного режима, удобно переписать все возможные комбинации в макроопределения, что я и сделал. В последствии эти константы будут передаваться в методы для задания режима.

Далее по коду объявляем класс GPIO. Конструктор класса принимает ссылку на порт (GPIOA, GPIOB и т.д.) и сохраняет ее в приватной переменной GPIOx. Это нужно для того, чтобы при создании объекта и вызове его методов, методы знали с каким портом работать.

После конструктора следуют публичные методы класса, образующие интерфейс.

  • pinConf ( uint8_t pin_nomber, uint8_t pin_mode ) принимает номер вывода порта и режим работы, который задается макроопределениями в начале файла.

  • setPin( uint8_t pin_nomber ) устанавливает вывод в 1. Принимает номер пина порта.

  • resetPin( uint8_t pin_nomber ) сбрасывает вывод. Принимает номер вывода.

  • getPin ( uint8_t pin_nomber ) возвращает состояние вывода порта (читает регистр IDR)

GPIO.CPP

В конструкторе класса сохраняется ссылка на порт и тактируется выбранный порт.

В методе конфигурации сохраняем заданный режим в переменную pin_m. Это нужно для того, чтобы при использовании методов setPin()/resetPin() и заданном режиме альтернативной функции эти методы не управляли выводом, так как в данном случае управление должно осуществляться из модуля альтернативной функции.

Далее проверяем задан ли режим входа с подтяжкой. Если задан то меняем переменную pin_mode так как для обоих режимов входа с подтяжкой биты пина конфигурируются одинаково, а выбор подтяжки к питанию или земле осуществляется записью в регистр ODR 1 или 0.

В условии if ( pin_nomber < 8 ) и аналогичном if ( pin_nomber > 7 ) рассчитываем смещение относительно начала регистра CRL или CRH соответственно, учитывая, что на вывод отводится 4 бита, и кладем в переменную offset. Затем сначала затираем биты конфигурации маской GPIO BIT MASK, а затем записываем новые биты конфигурации вывода.

if ( pin_mode == INPUT_PULL_UP ) — проверяем, если задан режим подтяжки к питанию, то выставляем в регистре ODR единицу. Аналогично проверяем режим подтяжки к земле и скидываем бит, если условие верно.

В методе setPin() сначала проверяем не задана ли альтернативная функция. Если да, то выходим ничего не делая. Далее в регистре BSSR устанавливаем 1 на соответствующий вывод.

В методе resetPin() все аналогично предыдущему, за исключением того, что пишем в регистр BRR тем самым скидывая вывод.

В методе getPin() создаем маску для сравнения, сравниваем регистр IDR с маской. Если тру — возвращаем 1, иначе 0.

Применяется все это дело так :

Описание SPI

Serial Peripheral Interface (SPI) — это последовательный, синхронный, полнодуплексный протокол передачи данных между главным (master) контроллером (обычно микроконтроллером или другими устройством с программируемой функциональностью) и несколькими ведомыми (slave) устройствами. Как мы увидим далее, SPI позволяет передавать данные как в полнодуплексном, так и в полудуплексном режиме. Спецификация SPI стандарт в протоколах передачи данных и была разработана в конце 70-х компанией Motorola и на данный широко используется как протокол передачи данных для многих цифровых микросхем. В отличие от протокола I2C, SPI не задает жестких условий в протоколе передачи данных по шине, давая ведомым (slave) устройствам полную свободу в структуре сообщений обмена данными.

Рисунок 1: Архитектура типовой SPI шины.

Типовая шина SPI содержит 4 сигнала, как показано на рисунке 1, даже, если возможно управлять некоторыми SPI устройствами, используя лишь 3 сигнала (в таком случае мы говорим о 3-проводном SPI).

  • SCK: сигнал, используемый для генерации тактовой частоты синхронизации передачи данных по SPI. Генерируется master устройством и это означает, что каждая передача по шине SPI всегда начинается по инициативе master устройства. В отличие от I2C SPI более быстрый интерфейс передачи данных и тактовая частота обычно в районе нескольких мегагерц. В наше время вполне обычно найти SPI устройства со скоростью обмена данными от 100 МГц и выше. Более того, протокол SPI позволяет работать в одной шине на различных скоростях в одно и то же время.
  • MOSI: расшифровывается как Master Output Slave Input и используется для передачи данных от главного (master) устройства к ведомому (slave). В отличие от I2C, где для обмена между устройствами используется лишь один провод, в SPI предусмотрено две линии передачии данных.
  • MISO: расшифровывается как Master Input Slave Output и используется для передачи данных от ведомого (slave) устройства к главному (master).
  • SSn: Slave Select используется для адресации устройств в шине SPI, где „n“ — количество линий адресации. В отличие от I2C, SPI не использует адреса ведомых (slave) устройств, а использует физические линии адресации, которые устанавливаются в низкий логический уровень для выбора устройства. В типовой SPI шине только одно ведомое (slave) устройство может быть активно в одно время путем установки линии SS в низкий уровень. В этом причина того, что в одной и той же шине могут быть устройства с разной скоростью передачи данных.

Имея две раздельные шины данных, MOSI и MISO, SPI по сути является полнодуплексным интерфейсом передачи данных, таким образом ведомое (slave) устройство может отдавать данные главному (master) пока одновременно принимает данные от него же. В одноранговых шинах (когда одно главное (master) и одно ведомое (slave) устройства), сигнал SS может не использоваться, лишь достаточно его подтянуть к «земле» резистором на несколько килоом, линии MISO/MOSI соединяются в одно общую линию Slave In/Slave Out (SISO). В таком случае мы говорим о двухпроводном SPI, хотя по существу он конечно же трехпроводной.

Рисунок 2: Как передаются данные по шине SPI в полнодуплексном режиме

Каждая транзакция в шине начинается с подачи тактирования в линию SCK в соответствии с допустимой тактовой частотой ведомого (slave) устройства. В то же время главное (master) устройство устанавливает LOW уровень на линии SS и передача данных начинается. Обычно обмен данными подразумевает использование двух регистров (в основном 8-битные, хотя некоторые slave устройства поддерживают 16-битный размер слова), одного в главном (master) устройстве и один в ведомом (slave). Данные побитно сдвигаются в сдвиговом регистре, начиная со старшего бита, пока младший бит сдвигается в этот же самый регистр. В это же самое время, данные от ведомого (slave) устройства сдвигаются в младший бит регистра данных. Когда все биты регистра будут сдвинуты в одну и другую сторону обмен данными будет осуществлен. Если необходимо передать более одного слова данных, сдвиговые регистры обнуляются и процесс повторяется. Обмен данными может продолжаться сколько угодно большое количество циклов тактового генератора. Когда обмен завершен master выключает тактовый сигнал и линия SS возвращается в исходное состояние высокого логического уровня.
Рисунок 2 показывает процесс обмена данными в полнодуплексном режиме, рисунок 3 же демонстрирует процесс в полудуплексном режиме.

Рисунок 3: Как передаются данные по шине SPI в полудуплексном режиме

Mutex¶

The Mutex Management function group is used to synchronize the execution of threads. This is for example used to protect access to a shared resource, for example a shared memory image.

Mutex Management functions cannot be called from interrupt service routines (ISR).

Import programcmsis_rtos_mutex — main.cpp

00001 #include "mbed.h"
00002 #include "cmsis_os.h"
00003 
00004 osMutexId stdio_mutex;
00005 osMutexDef(stdio_mutex);
00006 
00007 void notify(const char* name, int state) {
00008     osMutexWait(stdio_mutex, osWaitForever);
00009     printf("%s: %d\n\r", name, state);
00010     osMutexRelease(stdio_mutex);
00011 }
00012 
00013 void test_thread(void const *args) {
00014     while (true) {
00015         notify((const char*)args, 0); osDelay(1000);
00016         notify((const char*)args, 1); osDelay(1000);
00017     }
00018 }
00019 
00020 void t2(void const *argument) {test_thread("Th 2");}
00021 osThreadDef(t2, osPriorityNormal, DEFAULT_STACK_SIZE);
00022 
00023 void t3(void const *argument) {test_thread("Th 3");}
00024 osThreadDef(t3, osPriorityNormal, DEFAULT_STACK_SIZE);
00025 
00026 int main() {
00027     stdio_mutex = osMutexCreate(osMutex(stdio_mutex));
00028     
00029     osThreadCreate(osThread(t2), NULL);
00030     osThreadCreate(osThread(t3), NULL);
00031     
00032     test_thread((void *)"Th 1");
00033 }

C standard library mutexes

The ARM C standard library has already mutexes in place to protect the access to stdio, therefore on the M3 mbed the above example is not necessary. On the contrary, ARM microlib (used on the M0 mbed) does not provide default stdio mutexes making the above example a necessity.

Результаты кода

Функция не может найти заголовок

Однако основной может найти точно такой же заголовок

И заголовок включен в параметры сборки -> каталоги

Просто проверил, что он также включен в « путь и символы », что он должен делать автоматически AFAIK после того, как вы включите его в параметры сборки:

Обновить

Since my OP I have made some progress, mostly via messing around with the includes, symbols and linker. I have now managed to defeat the original error (though unfortunately I have no idea how), but I have now incurred a large amount of additional errors for the startup_stm32 files.

These all appear to be bad instruction errors referring to the template files included in CMSIS (CMSIS / Device / ST / STM32F4xx / Source / Templates / ARM / …), which somehow cannot interpret the various commands listed in these templates.

Стандартная часть

Заголовочный файл предоставляет интерфейс к ядру. Для stm32f103c8 это , так как он работает на Cortex-M3. Для Cortex-M0+ это будет файл .

Под интерфейсом понимается удобный доступ к его регистрам. Например, в состав ядра входят еще две сущности: системный таймер и контроллер прерываний NVIC. Поэтому в этом файле содержатся вспомогательные функции для их быстрой настройки. Включить прерывание можно вызовом функции:

xxxxxxxxxx
static __INLINE void NVIC_EnableIRQ(IRQn_Type IRQn) {
    NVIC->ISER = (1 << ((uint32_t)(IRQn) & 0x1F));
}

Вам не нужно работать с регистрами ядра напрямую.

Другие файлы нам не столь интересны, но справедливости ради упомянем их. Например файл содержит обертки инструкций, а — обертки некоторых важных системных функций.

xxxxxxxxxx
__attribute__( ( always_inline ) ) static __INLINE uint32_t __get_PSP(void) {
  register uint32_t result;
  __ASM volatile ("MRS %0, psp\n"  : "=r" (result) );
  return(result);
}

Если вы не разрабатываете приложение на самом низком уровне, то заглядывать в эти файлы незачем. Тем не менее, подробное описание работы ядра можно найти в документе ARM — Cortex-M3 Devices Generic User Guide, и мы им даже воспользуемся при настройке системного таймера.

Mail Queue¶

Import programcmsis_rtos_mail — main.cpp

00001 #include "mbed.h"
00002 #include "cmsis_os.h"
00003 
00004 typedef struct {
00005   float    voltage; 
00006   float    current; 
00007   uint32_t counter; 
00008 } mail_t;
00009 
00010 osMailQDef(mail_box, 16, mail_t);
00011 osMailQId  mail_box;
00012 
00013 void send_thread (void const *args) {
00014     uint32_t i = 0;
00015     while (true) {
00016         i++; 
00017         mail_t *mail = (mail_t*)osMailAlloc(mail_box, osWaitForever);
00018         mail->voltage = (i * 0.1) * 33; 
00019         mail->current = (i * 0.1) * 11;
00020         mail->counter = i;
00021         osMailPut(mail_box, mail);
00022         osDelay(1000);
00023     }
00024 }
00025 
00026 osThreadDef(send_thread, osPriorityNormal, DEFAULT_STACK_SIZE);
00027 
00028 int main (void) {
00029     mail_box = osMailCreate(osMailQ(mail_box), NULL);
00030     osThreadCreate(osThread(send_thread), NULL);
00031     
00032     while (true) {
00033         osEvent evt = osMailGet(mail_box, osWaitForever);
00034         if (evt.status == osEventMail) {
00035             mail_t *mail = (mail_t*)evt.value.p;
00036             printf("\nVoltage: %.2f V\n\r"   , mail->voltage);
00037             printf("Current: %.2f A\n\r"     , mail->current);
00038             printf("Number of cycles: %u\n\r", mail->counter);
00039             
00040             osMailFree(mail_box, mail);
00041         }
00042     }
00043 }

[Repository ‘/users/mbed_official/code/rtx/docs/tip/structos__mailQ__def.html’ not found]