[Системное программирование, Реверс-инжиниринг, Программирование микроконтроллеров, Интернет вещей, DIY или Сделай сам] Hello NXP JN5169 World

Автор Сообщение
news_bot ®

Стаж: 6 лет 3 месяца
Сообщений: 27286

Создавать темы news_bot ® написал(а)
16-Мар-2021 23:30


Есть у меня одна идейка - написать альтернативную прошивку для некоторых ZigBee устройств Xiaomi. Но есть проблема: я никогда не работал с микроконтроллерами NXP JN5169, которые используются в устройствах Xiaomi. NXP предоставляет IDE, несколько тысяч страниц документации, девелоперскую борду за $650, и несколько мегабайт запутанного кода примеров. Но вот какого нибудь внятного пошагового туториала в интернете не нашлось.В этой статье восполним образовательный пробел, и попробуем написать небольшой Hello World для микроконтроллера NXP JN5169. Поехали.МотивацияКак я уже сказал, NXP предоставляет готовую платформу для разработки под свои устройства: 
  • BeyondStudio IDE на базе Eclipse, который включает в себя несколько плагинов по работе с JN5169, которые должны помочь в разработке ZigBee устройств
  • SDK с реализацией функций по работе с периферией, а также реализацию ZigBee стека
  • Все это подкреплено довольно подробной документацией, даташитами, API Reference, и многочисленными Application Notes
Вот только вся эта штуковина выглядит монстрообразно даже для профессионала, а новичок в этом вообще утонет и не сможет даже лампочкой поморгать. К своему стыду могу сказать, что даже следуя инструкции на компиляцию примера из SDK у меня ушло более чем полдня - BeyondStudio то никак не мог найти комплектный make, то компилятор, то библиотеки, то еще что нибудь. Все это зависит на многочисленные переменные окружения, настройки проекта, и черт его знает что еще. В общем, ниасилил, хотя по итогу что-то там скомпилировалось.Но это еще полбеды. Примеры ZigBee приложений занимают несколько мегабайт, код подпроектов сильно переплетается. Названия функций и переменных наполовину состоят из непонятных аббревиатур, используют венгерскую нотацию и в 2 раза длиннее, чем могли бы. Сам код представляет собой лапшу из дефайнов и сотен строк Makefile’ов. Высокоуровневый код перемежается с побайтной сборкой пакетов MAC уровня сети, все это построено на системе обратных вызовов, а с чего начинается программа вообще сходу не разберешься. В общем кровь из глаз, и без поллитры не разберешься (если что, речь идет о примере JN-AN-1219-Zigbee-3-0-Controller-and-Switch)Я уверен, что разобраться в этом всем со временем возможно, но скорее всего к этому времени мой интерес угаснет. Тут нужен какой-то другой подход. Обычно, если я хочу разобраться в новой технологии, я пробую сделать что нибудь простое. Мегабайты примеров и тысячи страниц документации - это прекрасно, но как по мне лучше начать со светодиодной моргалки. В общем, я решил написать с нуля небольшой примерчик, чтобы шаг за шагом постигать глубины глубин JN5169.ЖелезоТратить $650 на официальную плату разработки, чтобы просто помигать светодиодом - слишком жирно. Благо компания EBYTE выпускает копеечный модуль E75-2G4M10S (на КДПВ). На нем и будем экспериментировать. Для экспериментов соберем небольшую схему
В схеме у нас будет одна пользовательская кнопка и один светодиод. Пины GPIO выбраны наобум. Прошивать модуль можно через UART. Для этого нужно прижать пин SPI_MISO к земле во время ресета, для чего служат 2 дополнительные кнопки. Сборка на соплях макетной плате
С железом все, пора переходить к программной части.Toolchain file Для сборки я буду использовать CMake. Готового файла тулчейна в интернете не нашлось, но его несложно написать самостоятельно. Нужно только выставить некоторые переменные, которые задают путь к исполняемым файлам компилятора, а также многочисленные флаги.Компилятор будем использовать тот, который идет вместе с BeyondStudio (не знаю можно ли его скачать отдельно). На деле это обычный gcc кросс компилятор.
SET(CMAKE_SYSTEM_NAME Generic)
IF(NOT TOOLCHAIN_PREFIX)
     MESSAGE(STATUS "No TOOLCHAIN_PREFIX specified")
ENDIF()
IF (WIN32)
    SET(TOOL_EXECUTABLE_SUFFIX ".exe")
ELSE()
    SET(TOOL_EXECUTABLE_SUFFIX "")
ENDIF()
SET(TARGET_PREFIX "ba-elf")
SET(TOOLCHAIN_BIN_DIR ${TOOLCHAIN_PREFIX}/bin)
SET(TOOLCHAIN_INC_DIR ${TOOLCHAIN_PREFIX}/include)
SET(TOOLCHAIN_LIB_DIR ${TOOLCHAIN_PREFIX}/lib)
SET(CMAKE_C_COMPILER ${TOOLCHAIN_BIN_DIR}/${TARGET_PREFIX}-gcc${TOOL_EXECUTABLE_SUFFIX})
SET(CMAKE_CXX_COMPILER ${TOOLCHAIN_BIN_DIR}/${TARGET_PREFIX}-g++${TOOL_EXECUTABLE_SUFFIX})
SET(CMAKE_OBJCOPY ${TOOLCHAIN_BIN_DIR}/${TARGET_PREFIX}-objcopy${TOOL_EXECUTABLE_SUFFIX} CACHE INTERNAL "objcopy tool")
SET(CMAKE_OBJDUMP ${TOOLCHAIN_BIN_DIR}/${TARGET_PREFIX}-objdump${TOOL_EXECUTABLE_SUFFIX} CACHE INTERNAL "objdump tool")
SET(CMAKE_SIZE ${TOOLCHAIN_BIN_DIR}/${TARGET_PREFIX}-size${TOOL_EXECUTABLE_SUFFIX} CACHE INTERNAL "size tool")
SET(CMAKE_DEBUGER ${TOOLCHAIN_BIN_DIR}/${TARGET_PREFIX}-gdb${TOOL_EXECUTABLE_SUFFIX} CACHE INTERNAL "debuger")
SET(CMAKE_CPPFILT ${TOOLCHAIN_BIN_DIR}/${TARGET_PREFIX}-c++filt${TOOL_EXECUTABLE_SUFFIX} CACHE INTERNAL "C++filt")
SET(CMAKE_C_FLAGS_DEBUG "-Og -g" CACHE INTERNAL "c compiler flags debug")
SET(CMAKE_CXX_FLAGS_DEBUG "-Og -g" CACHE INTERNAL "cxx compiler flags debug")
SET(CMAKE_ASM_FLAGS_DEBUG "-g" CACHE INTERNAL "asm compiler flags debug")
SET(CMAKE_EXE_LINKER_FLAGS_DEBUG "" CACHE INTERNAL "linker flags debug")
SET(CMAKE_C_FLAGS_RELEASE "-Os -g" CACHE INTERNAL "c compiler flags release")
SET(CMAKE_CXX_FLAGS_RELEASE "-Os -g" CACHE INTERNAL "cxx compiler flags release")
SET(CMAKE_ASM_FLAGS_RELEASE "-g" CACHE INTERNAL "asm compiler flags release")
SET(CMAKE_EXE_LINKER_FLAGS_RELEASE "" CACHE INTERNAL "linker flags release")
SET(CMAKE_C_FLAGS "" CACHE INTERNAL "c compiler flags")
SET(CMAKE_CXX_FLAGS "" CACHE INTERNAL "cxx compiler flags")
SET(CMAKE_ASM_FLAGS "" CACHE INTERNAL "asm compiler flags")
SET(CMAKE_EXE_LINKER_FLAGS "" CACHE INTERNAL "executable linker flags")
SET(CMAKE_MODULE_LINKER_FLAGS "" CACHE INTERNAL "module linker flags")
SET(CMAKE_SHARED_LINKER_FLAGS "" CACHE INTERNAL "shared linker flags")
SET(CMAKE_FIND_ROOT_PATH ${TOOLCHAIN_PREFIX} ${EXTRA_FIND_PATH})
SET(CMAKE_FIND_ROOT_PATH_MODE_PROGRAM NEVER)
SET(CMAKE_FIND_ROOT_PATH_MODE_LIBRARY ONLY)
SET(CMAKE_FIND_ROOT_PATH_MODE_INCLUDE ONLY)
На первый взгляд это может показаться сложным, но тут на самом деле все просто. Этот скрипт ожидает на вход переменную TOOLCHAIN_PREFIX (в моем случае она указывает на C:/NXP/bstudio_nxp/sdk/Tools/ba-elf-ba2-r36379 - путь где лежит тулчейн), и выводит из этой переменной остальные пути - компилятор, objdump, objcopy, и прочие GNUсные штуки. Также тут задаются ключи компилятора и линковщика (пока оставим их пустыми - это всего лишь заготовка). Создадим небольшой тестовый проект 
SET(CMAKE_BUILD_TYPE Release)
SET(CMAKE_TOOLCHAIN_FILE JN5169.cmake)
PROJECT(GPSLogger)
CMAKE_MINIMUM_REQUIRED(VERSION 3.8)
ENABLE_LANGUAGE(CXX)
ADD_EXECUTABLE(Test Test.c)
#include <stdio.h>
#include <stdlib.h>
int main(void)
{
  return EXIT_SUCCESS;
}
Загружать в железку это пока бессмысленно, но во всяком случае оно компилируетсяВыглядит примерно так
D:\Projects\NXP\HelloJN5169World\build>cmake -G "MinGW Makefiles" -DTOOLCHAIN_PREFIX=C:/NXP/bstudio_nxp/sdk/Tools/ba-elf-ba2-r36379 ..
-- ======================
-- Toolchain paths
-- TOOLCHAIN_BIN_DIR = C:/NXP/bstudio_nxp/sdk/Tools/ba-elf-ba2-r36379/bin
-- TOOLCHAIN_INC_DIR = C:/NXP/bstudio_nxp/sdk/Tools/ba-elf-ba2-r36379/include
-- TOOLCHAIN_LIB_DIR = C:/NXP/bstudio_nxp/sdk/Tools/ba-elf-ba2-r36379/lib
-- CMAKE_C_COMPILER = C:/NXP/bstudio_nxp/sdk/Tools/ba-elf-ba2-r36379/bin/ba-elf-gcc.exe
-- CMAKE_CXX_COMPILER = C:/NXP/bstudio_nxp/sdk/Tools/ba-elf-ba2-r36379/bin/ba-elf-g++.exe
-- CMAKE_OBJCOPY = C:/NXP/bstudio_nxp/sdk/Tools/ba-elf-ba2-r36379/bin/ba-elf-objcopy.exe
-- CMAKE_OBJDUMP = C:/NXP/bstudio_nxp/sdk/Tools/ba-elf-ba2-r36379/bin/ba-elf-objdump.exe
-- CMAKE_SIZE = C:/NXP/bstudio_nxp/sdk/Tools/ba-elf-ba2-r36379/bin/ba-elf-size.exe
-- CMAKE_DEBUGER = C:/NXP/bstudio_nxp/sdk/Tools/ba-elf-ba2-r36379/bin/ba-elf-gdb.exe
-- CMAKE_CPPFILT = C:/NXP/bstudio_nxp/sdk/Tools/ba-elf-ba2-r36379/bin/ba-elf-c++filt.exe
-- ======================
-- Compiler flags
-- CMAKE_C_FLAGS =
-- CMAKE_CXX_FLAGS =
-- CMAKE_ASM_FLAGS =
-- CMAKE_EXE_LINKER_FLAGS =
-- CMAKE_MODULE_LINKER_FLAGS =
-- CMAKE_SHARED_LINKER_FLAGS =
-- CMAKE_C_FLAGS_DEBUG = -Og -g
-- CMAKE_CXX_FLAGS_DEBUG = -Og -g
-- CMAKE_ASM_FLAGS_DEBUG = -g
-- CMAKE_EXE_LINKER_FLAGS_DEBUG =
-- CMAKE_C_FLAGS_RELEASE = -Os -g
-- CMAKE_CXX_FLAGS_RELEASE = -Os -g
-- CMAKE_ASM_FLAGS_RELEASE = -g
-- CMAKE_EXE_LINKER_FLAGS_RELEASE =
-- Configuring done
-- Generating done
-- Build files have been written to: D:/Projects/NXP/HelloJN5169World/build
D:\Projects\NXP\HelloJN5169World\build>mingw32-make
[ 50%] Building C object CMakeFiles/Test.dir/Test.c.obj
[100%] Linking C executable Test
[100%] Built target Test
Hello World по железячному. Попытка №1 Попробуем в эти бездушные буковки вдохнуть немного жизни. По традиции будем мигать светодиодом. Код по управлению GPIO (и другой периферией) нам предоставляет SDK. Компания NXP также предоставляет 416-страничный документ, который описывает железячное API (JN-UG-3087 JN516x Integrated Peripherals API User Guide).Попробуем написать код следующего содержания. Пока пусть просто включит светодиод, подключенный к DIO17.
#include <stdio.h>
#include <stdlib.h>
#include "AppHardwareApi.h"
#define BOARD_LED_BIT               (17)
#define BOARD_LED_PIN               (1UL << BOARD_LED_BIT)
#define BOARD_LED_CTRL_MASK         (BOARD_LED_PIN)
int main(void)
{
  // Initialize hardware
  vAHI_DioSetDirection(0, BOARD_LED_CTRL_MASK);
  vAHI_DioSetOutput(0, BOARD_LED_PIN);
  return EXIT_SUCCESS;
}
Мы собираемся использовать несколько функций из API микроконтроллера, а значит нужно подключить соответствующие библиотеки
IF(NOT SDK_PREFIX)
     MESSAGE(FATAL_ERROR "No SDK_PREFIX specified")
ENDIF()
INCLUDE_DIRECTORIES(
  ${SDK_PREFIX}/Components/Common/Include
  ${SDK_PREFIX}/Components/HardwareAPI/Include
)
LINK_DIRECTORIES(
  ${SDK_PREFIX}/Components/Library
)
ADD_DEFINITIONS(
  -DJENNIC_CHIP_NAME=_JN5169
  -DJENNIC_CHIP_FAMILY_NAME=_JN516x
)
ADD_EXECUTABLE(HelloWorld HelloWorld.cpp)
TARGET_LINK_LIBRARIES(HelloWorld
  HardwareApi_JN5169
)
Пришлось, правда, добавить еще один параметр конфигурации Cmake - SDK_PREFIX, который должен указывать на корень SDK.Прошивальщик отказывается потреблять elf файл, который производит линковщик, поэтому из другого проекта я слямзил еще и функцию конвертации
FUNCTION(STM32_ADD_HEX_BIN_TARGETS TARGET)
    IF(EXECUTABLE_OUTPUT_PATH)
      SET(FILENAME "${EXECUTABLE_OUTPUT_PATH}/${TARGET}")
    ELSE()
      SET(FILENAME "${TARGET}")
    ENDIF()
    ADD_CUSTOM_TARGET(${TARGET}.hex DEPENDS ${TARGET} COMMAND ${CMAKE_OBJCOPY} -Oihex ${FILENAME} ${FILENAME}.hex)
    ADD_CUSTOM_TARGET(${TARGET}.bin DEPENDS ${TARGET} COMMAND ${CMAKE_OBJCOPY} -Obinary ${FILENAME} ${FILENAME}.bin)
ENDFUNCTION()
Компилируется эта штука без проблем. Попробуем залить прошивку в микроконтроллер. Я пока не разобрался как это делается из командной строки, поэтому воспользуюсь BeyondStudio. Для этого нужно перевести микроконтроллер в состояние программирования (зажать кнопку BOOT, и не отпуская нажать RESET), после чего зайти в Devices->Program Device. Вот только окошко подтверждения намекает на то, что что-то не так
Hello World по железячному. Попытка №2 Самое время посмотреть а как же сам BeyondStudio компилирует прошивки под наш микроконтроллер. А оказывается параметров в компилятор передается мама не горюй. Я даже в спойлер это затолкаю, чтобы статья не лопнула.Ключики с которыми компилирует BeyondStudio (мотайте вправо)
Compiling /d/Projects/NXP/JN5169-for-xiaomi-wireless-switch/sdk/JN-SW-4170/Components/BDB/Source/FindAndBind/bdb_fb_initiator.c ...
/d/Projects/NXP/JN5169-for-xiaomi-wireless-switch/sdk/Tools/ba-elf-ba2-r36379/bin/ba-elf-gcc -c -o /d/Projects/NXP/JN5169-for-xiaomi-wireless-switch/Application/JN-AN-1219-Zigbee-3-0-Controller-and-Switch/DimmerSwitch/Build/bdb_fb_initiator.o -DCONFIG_MANUFACTURER_CODE=0x1037 -DCONFIG_APP_SW_VERSION=7                                                                      -DCONFIG_HW_VERSION=1                             -DCONFIG_MANUFACTURER_NAME="NXP" -DCONFIG_MODEL_ID="DIMMER_SW"                               -DCONFIG_DATE_CODE="10-31-2014"               -DSINGLE_CHANNEL=0 -DKEEP_ALIVETIME=1 -DSLEEP_ENABLE -DDEEP_SLEEP_ENABLE -DDR1199 -DDimmerSwitch -DBUTTON_MAP_DR1199 -DSLEEPY_ZED -DEZ_MODE_INITIATOR -DEZ_ENABLE_GROUP -DDBG_ENABLE -DDEBUG_APP_BUTTON -DDEBUG_APP -DDEBUG_START_UP -DDEBUG_SWITCH_STATE -DDEBUG_SWITCH_TASK -DDEBUG_SWITCH_NODE -DDimmerSwitch -DPDM_USER_SUPPLIED_ID -DJN516x=5160 -DJN5169=5169 -DJENNIC_CHIP_NAME=_JN5169 -DJENNIC_CHIP_FAMILY_NAME=_JN516x -march=ba2 -mcpu=jn51xx -mredzone-size=4 -mbranch-cost=3 -fomit-frame-pointer -Os -fshort-enums -Wall  -Wpacked -Wcast-align -fdata-sections -ffunction-sections -DWATCHDOG_ENABLED -DJENNIC_HW_BBC_RXINCCA=1 -DJENNIC_HW_BBC_DMA=1 -DJENNIC_HW_BBC_ISA=0 -DJENNIC_SW_EXTERNAL_FLASH=0 -DJN516X_DMA_UART_BACKWARDS_COMPATIBLE_API=1 -DUART_BACKWARDS_COMPATIBLE_API=1 -DRXPOWERADJUST_SUPPORT -DJENNIC_CHIP=JN5169 -DJENNIC_CHIP_JN5169 -DJENNIC_CHIP_FAMILY=JN516x -DJENNIC_CHIP_FAMILY_JN516x -DJENNIC_STACK_ZCL -DJENNIC_MAC_MiniMacShim -Wall -Wunreachable-code -DEMBEDDED -I/d/Projects/NXP/JN5169-for-xiaomi-wireless-switch/sdk/JN-SW-4170/Platform/Common/Include -DJENNIC_PCB=DEVKIT4 -DJENNIC_PCB_DEVKIT4 -I/d/Projects/NXP/JN5169-for-xiaomi-wireless-switch/sdk/JN-SW-4170/Platform/DK4/Include -I/d/Projects/NXP/JN5169-for-xiaomi-wireless-switch/sdk/JN-SW-4170/Components/Common/Include -DPDM_USER_SUPPLIED_ID -DPDM_NO_RTOS -DPDM_EEPROM -DDBG_ENABLE -DZPS_APL_OPT_SINGLE_INSTANCE -DOTA_NO_CERTIFICATE -DPLME_SAP -DZBPRO_DEVICE_TYPE_ZED -DBDB_SUPPORT_NWK_STEERING -DBDB_SUPPORT_FIND_AND_BIND_INITIATOR -I/d/Projects/NXP/JN5169-for-xiaomi-wireless-switch/Application/JN-AN-1219-Zigbee-3-0-Controller-and-Switch/Common_Switch/Source -I/d/Projects/NXP/JN5169-for-xiaomi-wireless-switch/Application/JN-AN-1219-Zigbee-3-0-Controller-and-Switch/Common_Switch/Source/.. -I/d/Projects/NXP/JN5169-for-xiaomi-wireless-switch/Application/JN-AN-1219-Zigbee-3-0-Controller-and-Switch/DimmerSwitch/Source -I/d/Projects/NXP/JN5169-for-xiaomi-wireless-switch/Application/JN-AN-1219-Zigbee-3-0-Controller-and-Switch/Common/Source -I/d/Projects/NXP/JN5169-for-xiaomi-wireless-switch/sdk/JN-SW-4170/Components/ZigbeeCommon/Include -I/d/Projects/NXP/JN5169-for-xiaomi-wireless-switch/sdk/JN-SW-4170/Components/ZCL/Include -I/d/Projects/NXP/JN5169-for-xiaomi-wireless-switch/sdk/JN-SW-4170/Components/ZCIF/Include -I/d/Projects/NXP/JN5169-for-xiaomi-wireless-switch/sdk/JN-SW-4170/Components/Xcv/Include/ -I/d/Projects/NXP/JN5169-for-xiaomi-wireless-switch/sdk/JN-SW-4170/Components/Recal/Include/ -I/d/Projects/NXP/JN5169-for-xiaomi-wireless-switch/sdk/JN-SW-4170/Components/MicroSpecific/Include  -I/d/Projects/NXP/JN5169-for-xiaomi-wireless-switch/sdk/JN-SW-4170/Components/HardwareAPI/Include -I/d/Projects/NXP/JN5169-for-xiaomi-wireless-switch/sdk/JN-SW-4170/Components/AppApi/Include -I/d/Projects/NXP/JN5169-for-xiaomi-wireless-switch/sdk/JN-SW-4170/Components/MAC/Include -I/d/Projects/NXP/JN5169-for-xiaomi-wireless-switch/sdk/JN-SW-4170/Components/MiniMac/Include -I/d/Projects/NXP/JN5169-for-xiaomi-wireless-switch/sdk/JN-SW-4170/Components/MMAC/Include -I/d/Projects/NXP/JN5169-for-xiaomi-wireless-switch/sdk/JN-SW-4170/Components/HardwareAPI/Include -I/d/Projects/NXP/JN5169-for-xiaomi-wireless-switch/sdk/JN-SW-4170/Components/Aes/Include -I/d/Projects/NXP/JN5169-for-xiaomi-wireless-switch/sdk/JN-SW-4170/Components/DBG/Include -I/d/Projects/NXP/JN5169-for-xiaomi-wireless-switch/sdk/JN-SW-4170/Components/Mac/Include -I/d/Projects/NXP/JN5169-for-xiaomi-wireless-switch/sdk/JN-SW-4170/Components/MicroSpecific/Include -I/d/Projects/NXP/JN5169-for-xiaomi-wireless-switch/sdk/JN-SW-4170/Components/MiniMAC/Include -I/d/Projects/NXP/JN5169-for-xiaomi-wireless-switch/sdk/JN-SW-4170/Components/MMAC/Include -I/d/Projects/NXP/JN5169-for-xiaomi-wireless-switch/sdk/JN-SW-4170/Components/TimerServer/Include -I/d/Projects/NXP/JN5169-for-xiaomi-wireless-switch/sdk/JN-SW-4170/Components/Random/Include -I/d/Projects/NXP/JN5169-for-xiaomi-wireless-switch/sdk/JN-SW-4170/Components/ZigbeeCommon/Include -I/d/Projects/NXP/JN5169-for-xiaomi-wireless-switch/sdk/JN-SW-4170/Components/ZPSMAC_Mini_SOC/Include -I/d/Projects/NXP/JN5169-for-xiaomi-wireless-switch/sdk/JN-SW-4170/Components/PWRM/Include -I/d/Projects/NXP/JN5169-for-xiaomi-wireless-switch/sdk/JN-SW-4170/Components/ZPSTSV/Include -I/d/Projects/NXP/JN5169-for-xiaomi-wireless-switch/sdk/JN-SW-4170/Components/AES_SW/Include -I/d/Projects/NXP/JN5169-for-xiaomi-wireless-switch/sdk/JN-SW-4170/Components/PDUM/Include -I/d/Projects/NXP/JN5169-for-xiaomi-wireless-switch/sdk/JN-SW-4170/Components/ZPSAPL/Include -I/d/Projects/NXP/JN5169-for-xiaomi-wireless-switch/sdk/JN-SW-4170/Components/Random/Include -I/d/Projects/NXP/JN5169-for-xiaomi-wireless-switch/sdk/JN-SW-4170/Components/PDM_EEPROM_NO_RTOS/Include -I/d/Projects/NXP/JN5169-for-xiaomi-wireless-switch/sdk/JN-SW-4170/Components/DBG/Include -I/d/Projects/NXP/JN5169-for-xiaomi-wireless-switch/sdk/JN-SW-4170/Components/ZPSNWK_ZED/Include -I/d/Projects/NXP/JN5169-for-xiaomi-wireless-switch/sdk/JN-SW-4170/Components/PDM/Include -I/d/Projects/NXP/JN5169-for-xiaomi-wireless-switch/sdk/JN-SW-4170/Components/ZPSMAC/Include -I/d/Projects/NXP/JN5169-for-xiaomi-wireless-switch/sdk/JN-SW-4170/Components/ZPSNWK/Include -I/d/Projects/NXP/JN5169-for-xiaomi-wireless-switch/sdk/JN-SW-4170/Components/ZigbeeCommon/Include -I/d/Projects/NXP/JN5169-for-xiaomi-wireless-switch/sdk/JN-SW-4170/Components/ZCIF/Source -I/d/Projects/NXP/JN5169-for-xiaomi-wireless-switch/sdk/JN-SW-4170/Components/ZCIF/Include -I/d/Projects/NXP/JN5169-for-xiaomi-wireless-switch/sdk/JN-SW-4170/Components/ZCL/Clusters/General/Include -I/d/Projects/NXP/JN5169-for-xiaomi-wireless-switch/sdk/JN-SW-4170/Components/ZCL/Clusters/General/Source -I/d/Projects/NXP/JN5169-for-xiaomi-wireless-switch/sdk/JN-SW-4170/Components/ZCL/Clusters/MeasurementAndSensing/Include -I/d/Projects/NXP/JN5169-for-xiaomi-wireless-switch/sdk/JN-SW-4170/Components/ZCL/Clusters/Lighting/Include -I/d/Projects/NXP/JN5169-for-xiaomi-wireless-switch/sdk/JN-SW-4170/Components/ZCL/Clusters/HVAC/Include -I/d/Projects/NXP/JN5169-for-xiaomi-wireless-switch/sdk/JN-SW-4170/Components/ZCL/Clusters/Closures/Include -I/d/Projects/NXP/JN5169-for-xiaomi-wireless-switch/sdk/JN-SW-4170/Components/ZCL/Clusters/SecurityAndSafety/Include -I/d/Projects/NXP/JN5169-for-xiaomi-wireless-switch/sdk/JN-SW-4170/Components/ZCL/Clusters/SmartEnergy/Include -I/d/Projects/NXP/JN5169-for-xiaomi-wireless-switch/sdk/JN-SW-4170/Components/ZCL/Clusters/OTA/Include -I/d/Projects/NXP/JN5169-for-xiaomi-wireless-switch/sdk/JN-SW-4170/Components/ZCL/Clusters/Commissioning/Include -I/d/Projects/NXP/JN5169-for-xiaomi-wireless-switch/sdk/JN-SW-4170/Components/ZCL/Clusters/ApplianceManagement/Include -I/d/Projects/NXP/JN5169-for-xiaomi-wireless-switch/sdk/JN-SW-4170/Components/ZCL/Clusters/GreenPower/Include -I/d/Projects/NXP/JN5169-for-xiaomi-wireless-switch/sdk/JN-SW-4170/Components/ZCL/Clusters/Private/Include -I/d/Projects/NXP/JN5169-for-xiaomi-wireless-switch/sdk/JN-SW-4170/Components/ZCL/Devices/ZHA/Generic/Include -I/d/Projects/NXP/JN5169-for-xiaomi-wireless-switch/sdk/JN-SW-4170/Components/ZCL/Devices/ZLO/Include -I/d/Projects/NXP/JN5169-for-xiaomi-wireless-switch/sdk/JN-SW-4170/Components/BDB/Include -I/d/Projects/NXP/JN5169-for-xiaomi-wireless-switch/sdk/JN-SW-4170/Components/BDB/Source/Common -I/d/Projects/NXP/JN5169-for-xiaomi-wireless-switch/sdk/JN-SW-4170/Components/BDB/Source/NwkSteering -I/d/Projects/NXP/JN5169-for-xiaomi-wireless-switch/sdk/JN-SW-4170/Components/BDB/Source/FindAndBind /d/Projects/NXP/JN5169-for-xiaomi-wireless-switch/sdk/JN-SW-4170/Components/BDB/Source/FindAndBind/bdb_fb_initiator.c -MD -MF /d/Projects/NXP/JN5169-for-xiaomi-wireless-switch/Application/JN-AN-1219-Zigbee-3-0-Controller-and-Switch/DimmerSwitch/Build/bdb_fb_initiator.d -MP
Linking /d/Projects/NXP/JN5169-for-xiaomi-wireless-switch/Application/JN-AN-1219-Zigbee-3-0-Controller-and-Switch/DimmerSwitch/Build/DimmerSwitch_JN5169_DR1199.elf ...
/d/Projects/NXP/JN5169-for-xiaomi-wireless-switch/sdk/Tools/ba-elf-ba2-r36379/bin/ba-elf-gcc -Wl,--gc-sections -Wl,-u_AppColdStart -Wl,-u_AppWarmStart -march=ba2 -mcpu=jn51xx -mredzone-size=4 -mbranch-cost=3 -fomit-frame-pointer -Os -fshort-enums -nostartfiles -L/d/Projects/NXP/JN5169-for-xiaomi-wireless-switch/sdk/JN-SW-4170/Chip/JN5169/Build -L/d/Projects/NXP/JN5169-for-xiaomi-wireless-switch/sdk/JN-SW-4170/Chip/JN5169/Library -L/d/Projects/NXP/JN5169-for-xiaomi-wireless-switch/sdk/JN-SW-4170/Platform/DK4/Library -L/d/Projects/NXP/JN5169-for-xiaomi-wireless-switch/sdk/JN-SW-4170/Components/Library -Wl,--gc-sections -L/d/Projects/NXP/JN5169-for-xiaomi-wireless-switch/sdk/JN-SW-4170/Stack/ZBPro/Build -Wl,--defsym=__stack_size=5000 -Wl,--defsym,__minimum_heap_size=2000 -TAppBuildZBPro.ld -L /d/Projects/NXP/JN5169-for-xiaomi-wireless-switch/sdk/JN-SW-4170/Stack/ZCL/Build/ -o /d/Projects/NXP/JN5169-for-xiaomi-wireless-switch/Application/JN-AN-1219-Zigbee-3-0-Controller-and-Switch/DimmerSwitch/Build/DimmerSwitch_JN5169_DR1199.elf -Wl,--start-group /d/Projects/NXP/JN5169-for-xiaomi-wireless-switch/Application/JN-AN-1219-Zigbee-3-0-Controller-and-Switch/DimmerSwitch/Build/irq_JN516x.o /d/Projects/NXP/JN5169-for-xiaomi-wireless-switch/Application/JN-AN-1219-Zigbee-3-0-Controller-and-Switch/DimmerSwitch/Build/portasm_JN516x.o /d/Projects/NXP/JN5169-for-xiaomi-wireless-switch/Application/JN-AN-1219-Zigbee-3-0-Controller-and-Switch/DimmerSwitch/Build/port_JN516x.o /d/Projects/NXP/JN5169-for-xiaomi-wireless-switch/Application/JN-AN-1219-Zigbee-3-0-Controller-and-Switch/DimmerSwitch/Build/pdum_gen.o /d/Projects/NXP/JN5169-for-xiaomi-wireless-switch/Application/JN-AN-1219-Zigbee-3-0-Controller-and-Switch/DimmerSwitch/Build/pdum_apdu.o /d/Projects/NXP/JN5169-for-xiaomi-wireless-switch/Application/JN-AN-1219-Zigbee-3-0-Controller-and-Switch/DimmerSwitch/Build/zps_gen.o /d/Projects/NXP/JN5169-for-xiaomi-wireless-switch/Application/JN-AN-1219-Zigbee-3-0-Controller-and-Switch/DimmerSwitch/Build/app_pdm.o /d/Projects/NXP/JN5169-for-xiaomi-wireless-switch/Application/JN-AN-1219-Zigbee-3-0-Controller-and-Switch/DimmerSwitch/Build/app_main.o /d/Projects/NXP/JN5169-for-xiaomi-wireless-switch/Application/JN-AN-1219-Zigbee-3-0-Controller-and-Switch/DimmerSwitch/Build/app_start_switch.o /d/Projects/NXP/JN5169-for-xiaomi-wireless-switch/Application/JN-AN-1219-Zigbee-3-0-Controller-and-Switch/DimmerSwitch/Build/App_DimmerSwitch.o /d/Projects/NXP/JN5169-for-xiaomi-wireless-switch/Application/JN-AN-1219-Zigbee-3-0-Controller-and-Switch/DimmerSwitch/Build/app_zlo_switch_node.o /d/Projects/NXP/JN5169-for-xiaomi-wireless-switch/Application/JN-AN-1219-Zigbee-3-0-Controller-and-Switch/DimmerSwitch/Build/app_zcl_switch_task.o /d/Projects/NXP/JN5169-for-xiaomi-wireless-switch/Application/JN-AN-1219-Zigbee-3-0-Controller-and-Switch/DimmerSwitch/Build/app_buttons.o /d/Projects/NXP/JN5169-for-xiaomi-wireless-switch/Application/JN-AN-1219-Zigbee-3-0-Controller-and-Switch/DimmerSwitch/Build/app_switch_state_machine.o /d/Projects/NXP/JN5169-for-xiaomi-wireless-switch/Application/JN-AN-1219-Zigbee-3-0-Controller-and-Switch/DimmerSwitch/Build/app_pdm_convert.o /d/Projects/NXP/JN5169-for-xiaomi-wireless-switch/Application/JN-AN-1219-Zigbee-3-0-Controller-and-Switch/DimmerSwitch/Build/ZQueue.o /d/Projects/NXP/JN5169-for-xiaomi-wireless-switch/Application/JN-AN-1219-Zigbee-3-0-Controller-and-Switch/DimmerSwitch/Build/ZTimer.o /d/Projects/NXP/JN5169-for-xiaomi-wireless-switch/Application/JN-AN-1219-Zigbee-3-0-Controller-and-Switch/DimmerSwitch/Build/app_zps_link_keys.o /d/Projects/NXP/JN5169-for-xiaomi-wireless-switch/Application/JN-AN-1219-Zigbee-3-0-Controller-and-Switch/DimmerSwitch/Build/Alarms.o /d/Projects/NXP/JN5169-for-xiaomi-wireless-switch/Application/JN-AN-1219-Zigbee-3-0-Controller-and-Switch/DimmerSwitch/Build/AlarmsClientCommands.o /d/Projects/NXP/JN5169-for-xiaomi-wireless-switch/Application/JN-AN-1219-Zigbee-3-0-Controller-and-Switch/DimmerSwitch/Build/AlarmsCommandHandler.o /d/Projects/NXP/JN5169-for-xiaomi-wireless-switch/Application/JN-AN-1219-Zigbee-3-0-Controller-and-Switch/DimmerSwitch/Build/AlarmsServerCommands.o /d/Projects/NXP/JN5169-for-xiaomi-wireless-switch/Application/JN-AN-1219-Zigbee-3-0-Controller-and-Switch/DimmerSwitch/Build/AlarmsTableManager.o /d/Projects/NXP/JN5169-for-xiaomi-wireless-switch/Application/JN-AN-1219-Zigbee-3-0-Controller-and-Switch/DimmerSwitch/Build/AnalogInputBasic.o /d/Projects/NXP/JN5169-for-xiaomi-wireless-switch/Application/JN-AN-1219-Zigbee-3-0-Controller-and-Switch/DimmerSwitch/Build/AnalogOutputBasic.o /d/Projects/NXP/JN5169-for-xiaomi-wireless-switch/Application/JN-AN-1219-Zigbee-3-0-Controller-and-Switch/DimmerSwitch/Build/Basic.o /d/Projects/NXP/JN5169-for-xiaomi-wireless-switch/Application/JN-AN-1219-Zigbee-3-0-Controller-and-Switch/DimmerSwitch/Build/BasicClientCommands.o /d/Projects/NXP/JN5169-for-xiaomi-wireless-switch/Application/JN-AN-1219-Zigbee-3-0-Controller-and-Switch/DimmerSwitch/Build/BasicCommandHandler.o /d/Projects/NXP/JN5169-for-xiaomi-wireless-switch/Application/JN-AN-1219-Zigbee-3-0-Controller-and-Switch/DimmerSwitch/Build/BinaryInputBasic.o /d/Projects/NXP/JN5169-for-xiaomi-wireless-switch/Application/JN-AN-1219-Zigbee-3-0-Controller-and-Switch/DimmerSwitch/Build/BinaryOutputBasic.o /d/Projects/NXP/JN5169-for-xiaomi-wireless-switch/Application/JN-AN-1219-Zigbee-3-0-Controller-and-Switch/DimmerSwitch/Build/DeviceTemperatureConfiguration.o /d/Projects/NXP/JN5169-for-xiaomi-wireless-switch/Application/JN-AN-1219-Zigbee-3-0-Controller-and-Switch/DimmerSwitch/Build/Diagnostics.o /d/Projects/NXP/JN5169-for-xiaomi-wireless-switch/Application/JN-AN-1219-Zigbee-3-0-Controller-and-Switch/DimmerSwitch/Build/Groups.o /d/Projects/NXP/JN5169-for-xiaomi-wireless-switch/Application/JN-AN-1219-Zigbee-3-0-Controller-and-Switch/DimmerSwitch/Build/GroupsClientCommands.o /d/Projects/NXP/JN5169-for-xiaomi-wireless-switch/Application/JN-AN-1219-Zigbee-3-0-Controller-and-Switch/DimmerSwitch/Build/GroupsCommandHandler.o /d/Projects/NXP/JN5169-for-xiaomi-wireless-switch/Application/JN-AN-1219-Zigbee-3-0-Controller-and-Switch/DimmerSwitch/Build/GroupsServerCommands.o /d/Projects/NXP/JN5169-for-xiaomi-wireless-switch/Application/JN-AN-1219-Zigbee-3-0-Controller-and-Switch/DimmerSwitch/Build/GroupsTableManager.o /d/Projects/NXP/JN5169-for-xiaomi-wireless-switch/Application/JN-AN-1219-Zigbee-3-0-Controller-and-Switch/DimmerSwitch/Build/Identify.o /d/Projects/NXP/JN5169-for-xiaomi-wireless-switch/Application/JN-AN-1219-Zigbee-3-0-Controller-and-Switch/DimmerSwitch/Build/IdentifyClientCommands.o /d/Projects/NXP/JN5169-for-xiaomi-wireless-switch/Application/JN-AN-1219-Zigbee-3-0-Controller-and-Switch/DimmerSwitch/Build/IdentifyCommandHandler.o /d/Projects/NXP/JN5169-for-xiaomi-wireless-switch/Application/JN-AN-1219-Zigbee-3-0-Controller-and-Switch/DimmerSwitch/Build/IdentifyServerCommands.o /d/Projects/NXP/JN5169-for-xiaomi-wireless-switch/Application/JN-AN-1219-Zigbee-3-0-Controller-and-Switch/DimmerSwitch/Build/LevelControl.o /d/Projects/NXP/JN5169-for-xiaomi-wireless-switch/Application/JN-AN-1219-Zigbee-3-0-Controller-and-Switch/DimmerSwitch/Build/LevelControlClientCommands.o /d/Projects/NXP/JN5169-for-xiaomi-wireless-switch/Application/JN-AN-1219-Zigbee-3-0-Controller-and-Switch/DimmerSwitch/Build/LevelControlCommandHandler.o /d/Projects/NXP/JN5169-for-xiaomi-wireless-switch/Application/JN-AN-1219-Zigbee-3-0-Controller-and-Switch/DimmerSwitch/Build/MultistateInputBasic.o /d/Projects/NXP/JN5169-for-xiaomi-wireless-switch/Application/JN-AN-1219-Zigbee-3-0-Controller-and-Switch/DimmerSwitch/Build/MultistateOutputBasic.o /d/Projects/NXP/JN5169-for-xiaomi-wireless-switch/Application/JN-AN-1219-Zigbee-3-0-Controller-and-Switch/DimmerSwitch/Build/OOSC.o /d/Projects/NXP/JN5169-for-xiaomi-wireless-switch/Application/JN-AN-1219-Zigbee-3-0-Controller-and-Switch/DimmerSwitch/Build/OnOff.o /d/Projects/NXP/JN5169-for-xiaomi-wireless-switch/Application/JN-AN-1219-Zigbee-3-0-Controller-and-Switch/DimmerSwitch/Build/OnOffCommandHandler.o /d/Projects/NXP/JN5169-for-xiaomi-wireless-switch/Application/JN-AN-1219-Zigbee-3-0-Controller-and-Switch/DimmerSwitch/Build/OnOffCommands.o /d/Projects/NXP/JN5169-for-xiaomi-wireless-switch/Application/JN-AN-1219-Zigbee-3-0-Controller-and-Switch/DimmerSwitch/Build/PollControl.o /d/Projects/NXP/JN5169-for-xiaomi-wireless-switch/Application/JN-AN-1219-Zigbee-3-0-Controller-and-Switch/DimmerSwitch/Build/PollControlClientCommands.o /d/Projects/NXP/JN5169-for-xiaomi-wireless-switch/Application/JN-AN-1219-Zigbee-3-0-Controller-and-Switch/DimmerSwitch/Build/PollControlCommandHandler.o /d/Projects/NXP/JN5169-for-xiaomi-wireless-switch/Application/JN-AN-1219-Zigbee-3-0-Controller-and-Switch/DimmerSwitch/Build/PollControlServerCommands.o /d/Projects/NXP/JN5169-for-xiaomi-wireless-switch/Application/JN-AN-1219-Zigbee-3-0-Controller-and-Switch/DimmerSwitch/Build/PowerConfiguration.o /d/Projects/NXP/JN5169-for-xiaomi-wireless-switch/Application/JN-AN-1219-Zigbee-3-0-Controller-and-Switch/DimmerSwitch/Build/PowerProfile.o /d/Projects/NXP/JN5169-for-xiaomi-wireless-switch/Application/JN-AN-1219-Zigbee-3-0-Controller-and-Switch/DimmerSwitch/Build/PowerProfileClientCommands.o /d/Projects/NXP/JN5169-for-xiaomi-wireless-switch/Application/JN-AN-1219-Zigbee-3-0-Controller-and-Switch/DimmerSwitch/Build/PowerProfileCommandHandler.o /d/Projects/NXP/JN5169-for-xiaomi-wireless-switch/Application/JN-AN-1219-Zigbee-3-0-Controller-and-Switch/DimmerSwitch/Build/PowerProfileServerCommands.o /d/Projects/NXP/JN5169-for-xiaomi-wireless-switch/Application/JN-AN-1219-Zigbee-3-0-Controller-and-Switch/DimmerSwitch/Build/Scenes.o /d/Projects/NXP/JN5169-for-xiaomi-wireless-switch/Application/JN-AN-1219-Zigbee-3-0-Controller-and-Switch/DimmerSwitch/Build/ScenesClientCommands.o /d/Projects/NXP/JN5169-for-xiaomi-wireless-switch/Application/JN-AN-1219-Zigbee-3-0-Controller-and-Switch/DimmerSwitch/Build/ScenesClusterManagement.o /d/Projects/NXP/JN5169-for-xiaomi-wireless-switch/Application/JN-AN-1219-Zigbee-3-0-Controller-and-Switch/DimmerSwitch/Build/ScenesCommandHandler.o /d/Projects/NXP/JN5169-for-xiaomi-wireless-switch/Application/JN-AN-1219-Zigbee-3-0-Controller-and-Switch/DimmerSwitch/Build/ScenesServerCommands.o /d/Projects/NXP/JN5169-for-xiaomi-wireless-switch/Application/JN-AN-1219-Zigbee-3-0-Controller-and-Switch/DimmerSwitch/Build/ScenesTableManager.o /d/Projects/NXP/JN5169-for-xiaomi-wireless-switch/Application/JN-AN-1219-Zigbee-3-0-Controller-and-Switch/DimmerSwitch/Build/TC.o /d/Projects/NXP/JN5169-for-xiaomi-wireless-switch/Application/JN-AN-1219-Zigbee-3-0-Controller-and-Switch/DimmerSwitch/Build/Time.o /d/Projects/NXP/JN5169-for-xiaomi-wireless-switch/Application/JN-AN-1219-Zigbee-3-0-Controller-and-Switch/DimmerSwitch/Build/base_device.o /d/Projects/NXP/JN5169-for-xiaomi-wireless-switch/Application/JN-AN-1219-Zigbee-3-0-Controller-and-Switch/DimmerSwitch/Build/mains_power_outlet.o /d/Projects/NXP/JN5169-for-xiaomi-wireless-switch/Application/JN-AN-1219-Zigbee-3-0-Controller-and-Switch/DimmerSwitch/Build/on_off_output.o /d/Projects/NXP/JN5169-for-xiaomi-wireless-switch/Application/JN-AN-1219-Zigbee-3-0-Controller-and-Switch/DimmerSwitch/Build/plug_control.o /d/Projects/NXP/JN5169-for-xiaomi-wireless-switch/Application/JN-AN-1219-Zigbee-3-0-Controller-and-Switch/DimmerSwitch/Build/remote_control.o /d/Projects/NXP/JN5169-for-xiaomi-wireless-switch/Application/JN-AN-1219-Zigbee-3-0-Controller-and-Switch/DimmerSwitch/Build/simple_sensor.o /d/Projects/NXP/JN5169-for-xiaomi-wireless-switch/Application/JN-AN-1219-Zigbee-3-0-Controller-and-Switch/DimmerSwitch/Build/BallastConfiguration.o /d/Projects/NXP/JN5169-for-xiaomi-wireless-switch/Application/JN-AN-1219-Zigbee-3-0-Controller-and-Switch/DimmerSwitch/Build/ColourControl.o /d/Projects/NXP/JN5169-for-xiaomi-wireless-switch/Application/JN-AN-1219-Zigbee-3-0-Controller-and-Switch/DimmerSwitch/Build/ColourControlClientCommands.o /d/Projects/NXP/JN5169-for-xiaomi-wireless-switch/Application/JN-AN-1219-Zigbee-3-0-Controller-and-Switch/DimmerSwitch/Build/ColourControlCommandHandler.o /d/Projects/NXP/JN5169-for-xiaomi-wireless-switch/Application/JN-AN-1219-Zigbee-3-0-Controller-and-Switch/DimmerSwitch/Build/ColourControlConversions.o /d/Projects/NXP/JN5169-for-xiaomi-wireless-switch/Application/JN-AN-1219-Zigbee-3-0-Controller-and-Switch/DimmerSwitch/Build/colour_controller.o /d/Projects/NXP/JN5169-for-xiaomi-wireless-switch/Application/JN-AN-1219-Zigbee-3-0-Controller-and-Switch/DimmerSwitch/Build/colour_dimmable_light.o /d/Projects/NXP/JN5169-for-xiaomi-wireless-switch/Application/JN-AN-1219-Zigbee-3-0-Controller-and-Switch/DimmerSwitch/Build/colour_dimmer_switch.o /d/Projects/NXP/JN5169-for-xiaomi-wireless-switch/Application/JN-AN-1219-Zigbee-3-0-Controller-and-Switch/DimmerSwitch/Build/colour_scene_controller.o /d/Projects/NXP/JN5169-for-xiaomi-wireless-switch/Application/JN-AN-1219-Zigbee-3-0-Controller-and-Switch/DimmerSwitch/Build/colour_temperature_light.o /d/Projects/NXP/JN5169-for-xiaomi-wireless-switch/Application/JN-AN-1219-Zigbee-3-0-Controller-and-Switch/DimmerSwitch/Build/commission_endpoint.o /d/Projects/NXP/JN5169-for-xiaomi-wireless-switch/Application/JN-AN-1219-Zigbee-3-0-Controller-and-Switch/DimmerSwitch/Build/control_bridge.o /d/Projects/NXP/JN5169-for-xiaomi-wireless-switch/Application/JN-AN-1219-Zigbee-3-0-Controller-and-Switch/DimmerSwitch/Build/dimmable_ballast.o /d/Projects/NXP/JN5169-for-xiaomi-wireless-switch/Application/JN-AN-1219-Zigbee-3-0-Controller-and-Switch/DimmerSwitch/Build/dimmable_light.o /d/Projects/NXP/JN5169-for-xiaomi-wireless-switch/Application/JN-AN-1219-Zigbee-3-0-Controller-and-Switch/DimmerSwitch/Build/dimmable_plug.o /d/Projects/NXP/JN5169-for-xiaomi-wireless-switch/Application/JN-AN-1219-Zigbee-3-0-Controller-and-Switch/DimmerSwitch/Build/dimmer_switch.o /d/Projects/NXP/JN5169-for-xiaomi-wireless-switch/Application/JN-AN-1219-Zigbee-3-0-Controller-and-Switch/DimmerSwitch/Build/extended_colour_light.o /d/Projects/NXP/JN5169-for-xiaomi-wireless-switch/Application/JN-AN-1219-Zigbee-3-0-Controller-and-Switch/DimmerSwitch/Build/light_level_sensor.o /d/Projects/NXP/JN5169-for-xiaomi-wireless-switch/Application/JN-AN-1219-Zigbee-3-0-Controller-and-Switch/DimmerSwitch/Build/light_sensor.o /d/Projects/NXP/JN5169-for-xiaomi-wireless-switch/Application/JN-AN-1219-Zigbee-3-0-Controller-and-Switch/DimmerSwitch/Build/non_colour_controller.o /d/Projects/NXP/JN5169-for-xiaomi-wireless-switch/Application/JN-AN-1219-Zigbee-3-0-Controller-and-Switch/DimmerSwitch/Build/non_colour_scene_controller.o /d/Projects/NXP/JN5169-for-xiaomi-wireless-switch/Application/JN-AN-1219-Zigbee-3-0-Controller-and-Switch/DimmerSwitch/Build/occupancy_sensor.o /d/Projects/NXP/JN5169-for-xiaomi-wireless-switch/Application/JN-AN-1219-Zigbee-3-0-Controller-and-Switch/DimmerSwitch/Build/on_off_ballast.o /d/Projects/NXP/JN5169-for-xiaomi-wireless-switch/Application/JN-AN-1219-Zigbee-3-0-Controller-and-Switch/DimmerSwitch/Build/on_off_light.o /d/Projects/NXP/JN5169-for-xiaomi-wireless-switch/Application/JN-AN-1219-Zigbee-3-0-Controller-and-Switch/DimmerSwitch/Build/on_off_light_switch.o /d/Projects/NXP/JN5169-for-xiaomi-wireless-switch/Application/JN-AN-1219-Zigbee-3-0-Controller-and-Switch/DimmerSwitch/Build/on_off_plug.o /d/Projects/NXP/JN5169-for-xiaomi-wireless-switch/Application/JN-AN-1219-Zigbee-3-0-Controller-and-Switch/DimmerSwitch/Build/on_off_sensor.o /d/Projects/NXP/JN5169-for-xiaomi-wireless-switch/Application/JN-AN-1219-Zigbee-3-0-Controller-and-Switch/DimmerSwitch/Build/privateCluster.o /d/Projects/NXP/JN5169-for-xiaomi-wireless-switch/Application/JN-AN-1219-Zigbee-3-0-Controller-and-Switch/DimmerSwitch/Build/dlist.o /d/Projects/NXP/JN5169-for-xiaomi-wireless-switch/Application/JN-AN-1219-Zigbee-3-0-Controller-and-Switch/DimmerSwitch/Build/zcl.o /d/Projects/NXP/JN5169-for-xiaomi-wireless-switch/Application/JN-AN-1219-Zigbee-3-0-Controller-and-Switch/DimmerSwitch/Build/zcl_CustomCommandReceive.o /d/Projects/NXP/JN5169-for-xiaomi-wireless-switch/Application/JN-AN-1219-Zigbee-3-0-Controller-and-Switch/DimmerSwitch/Build/zcl_CustomCommandSend.o /d/Projects/NXP/JN5169-for-xiaomi-wireless-switch/Application/JN-AN-1219-Zigbee-3-0-Controller-and-Switch/DimmerSwitch/Build/zcl_PDUbufferReadWrite.o /d/Projects/NXP/JN5169-for-xiaomi-wireless-switch/Application/JN-AN-1219-Zigbee-3-0-Controller-and-Switch/DimmerSwitch/Build/zcl_PDUbufferReadWriteString.o /d/Projects/NXP/JN5169-for-xiaomi-wireless-switch/Application/JN-AN-1219-Zigbee-3-0-Controller-and-Switch/DimmerSwitch/Build/zcl_WriteAttributesRequestHandle.o /d/Projects/NXP/JN5169-for-xiaomi-wireless-switch/Application/JN-AN-1219-Zigbee-3-0-Controller-and-Switch/DimmerSwitch/Build/zcl_WriteAttributesRequestSend.o /d/Projects/NXP/JN5169-for-xiaomi-wireless-switch/Application/JN-AN-1219-Zigbee-3-0-Controller-and-Switch/DimmerSwitch/Build/zcl_WriteAttributesResponseHandle.o /d/Projects/NXP/JN5169-for-xiaomi-wireless-switch/Application/JN-AN-1219-Zigbee-3-0-Controller-and-Switch/DimmerSwitch/Build/zcl_attribute.o /d/Projects/NXP/JN5169-for-xiaomi-wireless-switch/Application/JN-AN-1219-Zigbee-3-0-Controller-and-Switch/DimmerSwitch/Build/zcl_buffer.o /d/Projects/NXP/JN5169-for-xiaomi-wireless-switch/Application/JN-AN-1219-Zigbee-3-0-Controller-and-Switch/DimmerSwitch/Build/zcl_clusterCommand.o /d/Projects/NXP/JN5169-for-xiaomi-wireless-switch/Application/JN-AN-1219-Zigbee-3-0-Controller-and-Switch/DimmerSwitch/Build/zcl_command.o /d/Projects/NXP/JN5169-for-xiaomi-wireless-switch/Application/JN-AN-1219-Zigbee-3-0-Controller-and-Switch/DimmerSwitch/Build/zcl_common.o /d/Projects/NXP/JN5169-for-xiaomi-wireless-switch/Application/JN-AN-1219-Zigbee-3-0-Controller-and-Switch/DimmerSwitch/Build/zcl_configureReportingCommandHandle.o /d/Projects/NXP/JN5169-for-xiaomi-wireless-switch/Application/JN-AN-1219-Zigbee-3-0-Controller-and-Switch/DimmerSwitch/Build/zcl_configureReportingCommandSend.o /d/Projects/NXP/JN5169-for-xiaomi-wireless-switch/Application/JN-AN-1219-Zigbee-3-0-Controller-and-Switch/DimmerSwitch/Build/zcl_configureReportingResponseHandle.o /d/Projects/NXP/JN5169-for-xiaomi-wireless-switch/Application/JN-AN-1219-Zigbee-3-0-Controller-and-Switch/DimmerSwitch/Build/zcl_defaultResponse.o /d/Projects/NXP/JN5169-for-xiaomi-wireless-switch/Application/JN-AN-1219-Zigbee-3-0-Controller-and-Switch/DimmerSwitch/Build/zcl_discoverAttributesExtendedRequestHandle.o /d/Projects/NXP/JN5169-for-xiaomi-wireless-switch/Application/JN-AN-1219-Zigbee-3-0-Controller-and-Switch/DimmerSwitch/Build/zcl_discoverAttributesExtendedRequestSend.o /d/Projects/NXP/JN5169-for-xiaomi-wireless-switch/Application/JN-AN-1219-Zigbee-3-0-Controller-and-Switch/DimmerSwitch/Build/zcl_discoverAttributesExtendedResponseHandle.o /d/Projects/NXP/JN5169-for-xiaomi-wireless-switch/Application/JN-AN-1219-Zigbee-3-0-Controller-and-Switch/DimmerSwitch/Build/zcl_discoverAttributesRequestHandle.o /d/Projects/NXP/JN5169-for-xiaomi-wireless-switch/Application/JN-AN-1219-Zigbee-3-0-Controller-and-Switch/DimmerSwitch/Build/zcl_discoverAttributesRequestSend.o /d/Projects/NXP/JN5169-for-xiaomi-wireless-switch/Application/JN-AN-1219-Zigbee-3-0-Controller-and-Switch/DimmerSwitch/Build/zcl_discoverAttributesResponseHandle.o /d/Projects/NXP/JN5169-for-xiaomi-wireless-switch/Application/JN-AN-1219-Zigbee-3-0-Controller-and-Switch/DimmerSwitch/Build/zcl_discoverCommandsRequestHandle.o /d/Projects/NXP/JN5169-for-xiaomi-wireless-switch/Application/JN-AN-1219-Zigbee-3-0-Controller-and-Switch/DimmerSwitch/Build/zcl_discoverCommandsRequestSend.o /d/Projects/NXP/JN5169-for-xiaomi-wireless-switch/Application/JN-AN-1219-Zigbee-3-0-Controller-and-Switch/DimmerSwitch/Build/zcl_discoverCommandsResponseHandle.o /d/Projects/NXP/JN5169-for-xiaomi-wireless-switch/Application/JN-AN-1219-Zigbee-3-0-Controller-and-Switch/DimmerSwitch/Build/zcl_event.o /d/Projects/NXP/JN5169-for-xiaomi-wireless-switch/Application/JN-AN-1219-Zigbee-3-0-Controller-and-Switch/DimmerSwitch/Build/zcl_heap.o /d/Projects/NXP/JN5169-for-xiaomi-wireless-switch/Application/JN-AN-1219-Zigbee-3-0-Controller-and-Switch/DimmerSwitch/Build/zcl_library_options.o /d/Projects/NXP/JN5169-for-xiaomi-wireless-switch/Application/JN-AN-1219-Zigbee-3-0-Controller-and-Switch/DimmerSwitch/Build/zcl_readAttributesRequestHandle.o /d/Projects/NXP/JN5169-for-xiaomi-wireless-switch/Application/JN-AN-1219-Zigbee-3-0-Controller-and-Switch/DimmerSwitch/Build/zcl_readAttributesRequestSend.o /d/Projects/NXP/JN5169-for-xiaomi-wireless-switch/Application/JN-AN-1219-Zigbee-3-0-Controller-and-Switch/DimmerSwitch/Build/zcl_readAttributesResponseHandle.o /d/Projects/NXP/JN5169-for-xiaomi-wireless-switch/Application/JN-AN-1219-Zigbee-3-0-Controller-and-Switch/DimmerSwitch/Build/zcl_readReportingConfigurationCommandHandle.o /d/Projects/NXP/JN5169-for-xiaomi-wireless-switch/Application/JN-AN-1219-Zigbee-3-0-Controller-and-Switch/DimmerSwitch/Build/zcl_readReportingConfigurationCommandSend.o /d/Projects/NXP/JN5169-for-xiaomi-wireless-switch/Application/JN-AN-1219-Zigbee-3-0-Controller-and-Switch/DimmerSwitch/Build/zcl_readReportingConfigurationResponseHandle.o /d/Projects/NXP/JN5169-for-xiaomi-wireless-switch/Application/JN-AN-1219-Zigbee-3-0-Controller-and-Switch/DimmerSwitch/Build/zcl_reportManager.o /d/Projects/NXP/JN5169-for-xiaomi-wireless-switch/Application/JN-AN-1219-Zigbee-3-0-Controller-and-Switch/DimmerSwitch/Build/zcl_reportMaths.o /d/Projects/NXP/JN5169-for-xiaomi-wireless-switch/Application/JN-AN-1219-Zigbee-3-0-Controller-and-Switch/DimmerSwitch/Build/zcl_reportScheduler.o /d/Projects/NXP/JN5169-for-xiaomi-wireless-switch/Application/JN-AN-1219-Zigbee-3-0-Controller-and-Switch/DimmerSwitch/Build/zcl_reportStringHandling.o /d/Projects/NXP/JN5169-for-xiaomi-wireless-switch/Application/JN-AN-1219-Zigbee-3-0-Controller-and-Switch/DimmerSwitch/Build/zcl_reportStructure.o /d/Projects/NXP/JN5169-for-xiaomi-wireless-switch/Application/JN-AN-1219-Zigbee-3-0-Controller-and-Switch/DimmerSwitch/Build/zcl_search.o /d/Projects/NXP/JN5169-for-xiaomi-wireless-switch/Application/JN-AN-1219-Zigbee-3-0-Controller-and-Switch/DimmerSwitch/Build/zcl_timer.o /d/Projects/NXP/JN5169-for-xiaomi-wireless-switch/Application/JN-AN-1219-Zigbee-3-0-Controller-and-Switch/DimmerSwitch/Build/zcl_transmit.o /d/Projects/NXP/JN5169-for-xiaomi-wireless-switch/Application/JN-AN-1219-Zigbee-3-0-Controller-and-Switch/DimmerSwitch/Build/bdb_fr.o /d/Projects/NXP/JN5169-for-xiaomi-wireless-switch/Application/JN-AN-1219-Zigbee-3-0-Controller-and-Switch/DimmerSwitch/Build/bdb_start.o /d/Projects/NXP/JN5169-for-xiaomi-wireless-switch/Application/JN-AN-1219-Zigbee-3-0-Controller-and-Switch/DimmerSwitch/Build/bdb_state_machine.o /d/Projects/NXP/JN5169-for-xiaomi-wireless-switch/Application/JN-AN-1219-Zigbee-3-0-Controller-and-Switch/DimmerSwitch/Build/appZpsBeaconHandler.o /d/Projects/NXP/JN5169-for-xiaomi-wireless-switch/Application/JN-AN-1219-Zigbee-3-0-Controller-and-Switch/DimmerSwitch/Build/appZdpExtraction.o /d/Projects/NXP/JN5169-for-xiaomi-wireless-switch/Application/JN-AN-1219-Zigbee-3-0-Controller-and-Switch/DimmerSwitch/Build/bdb_ns.o /d/Projects/NXP/JN5169-for-xiaomi-wireless-switch/Application/JN-AN-1219-Zigbee-3-0-Controller-and-Switch/DimmerSwitch/Build/bdb_fb_common.o /d/Projects/NXP/JN5169-for-xiaomi-wireless-switch/Application/JN-AN-1219-Zigbee-3-0-Controller-and-Switch/DimmerSwitch/Build/bdb_fb_initiator.o -lZPSMAC_Mini_SOC_JN516x -lPWRM_JN516x -lZPSTSV_JN516x -lAES_SW_JN516x -lPDUM_JN516x -lZPSAPL_JN516x -lRandom_JN516x -lPDM_EEPROM_NO_RTOS_JN516x -lDBG_JN516x -lZPSNWK_ZED_JN516x -lRecal_JN516x -lJPT_JN5169 -lMiniMac_JN5169 -lMiniMacShim_JN516x -lMMAC_JN5169 -lJPT_JN5169 -lAes_JN516x -lHardwareApi_JN5169 -lMicroSpecific_JN516x -lBoot_JN516x -lBoardLib_JN516x -lm -Wl,--end-group -Wl,-Map,/d/Projects/NXP/JN5169-for-xiaomi-wireless-switch/Application/JN-AN-1219-Zigbee-3-0-Controller-and-Switch/DimmerSwitch/Build/DimmerSwitch_JN5169_DR1199.map
/d/Projects/NXP/JN5169-for-xiaomi-wireless-switch/sdk/Tools/ba-elf-ba2-r36379/bin/ba-elf-size /d/Projects/NXP/JN5169-for-xiaomi-wireless-switch/Application/JN-AN-1219-Zigbee-3-0-Controller-and-Switch/DimmerSwitch/Build/DimmerSwitch_JN5169_DR1199.elf
   text    data     bss     dec     hex filename
139470    1624   23149  164243   28193 d:/Projects/NXP/JN5169-for-xiaomi-wireless-switch/Application/JN-AN-1219-Zigbee-3-0-Controller-and-Switch/DimmerSwitch/Build/DimmerSwitch_JN5169_DR1199.elf
date +%c >> /d/Projects/NXP/JN5169-for-xiaomi-wireless-switch/Application/JN-AN-1219-Zigbee-3-0-Controller-and-Switch/Doc/size.txt
/d/Projects/NXP/JN5169-for-xiaomi-wireless-switch/sdk/Tools/ba-elf-ba2-r36379/bin/ba-elf-size /d/Projects/NXP/JN5169-for-xiaomi-wireless-switch/Application/JN-AN-1219-Zigbee-3-0-Controller-and-Switch/DimmerSwitch/Build/DimmerSwitch_JN5169_DR1199.elf >> /d/Projects/NXP/JN5169-for-xiaomi-wireless-switch/Application/JN-AN-1219-Zigbee-3-0-Controller-and-Switch/Doc/size.txt
Generating binary ...
/d/Projects/NXP/JN5169-for-xiaomi-wireless-switch/sdk/Tools/ba-elf-ba2-r36379/bin/ba-elf-objcopy -j .version -j .bir -j .flashheader -j .vsr_table -j .vsr_handlers  -j .rodata -j .text -j .data -j .bss -j .heap -j .stack -S -O binary /d/Projects/NXP/JN5169-for-xiaomi-wireless-switch/Application/JN-AN-1219-Zigbee-3-0-Controller-and-Switch/DimmerSwitch/Build/DimmerSwitch_JN5169_DR1199.elf /d/Projects/NXP/JN5169-for-xiaomi-wireless-switch/Application/JN-AN-1219-Zigbee-3-0-Controller-and-Switch/DimmerSwitch/Build/DimmerSwitch_JN5169_DR1199.bin
Очевидно, что некоторые параметры тут важны (например указание процессора и платформы), тогда как другие относятся к примеру, который компилировался и нерелевантны к настройкам, собственно, компилятора. Попробуем забрать себе только самые нужные
SET(CMAKE_C_FLAGS "-march=ba2 -mcpu=jn51xx -mredzone-size=4 -mbranch-cost=3 -fomit-frame-pointer -fshort-enums -Wall -Wpacked -Wcast-align -fdata-sections -ffunction-sections" CACHE INTERNAL "c compiler flags")
SET(CMAKE_CXX_FLAGS "-march=ba2 -mcpu=jn51xx -mredzone-size=4 -mbranch-cost=3 -fomit-frame-pointer -fshort-enums -Wall -Wpacked -Wcast-align -fdata-sections -ffunction-sections" CACHE INTERNAL "cxx compiler flags")
SET(CMAKE_ASM_FLAGS "-march=ba2 -mcpu=jn51xx -mredzone-size=4 -mbranch-cost=3 -fomit-frame-pointer -fshort-enums -Wall -Wpacked -Wcast-align -fdata-sections -ffunction-sections" CACHE INTERNAL "asm compiler flags")
SET(CMAKE_EXE_LINKER_FLAGS "-Wl,--gc-sections -Wl,-u_AppColdStart -Wl,-u_AppWarmStart -march=ba2 -mcpu=jn51xx -mredzone-size=4 -mbranch-cost=3 -fomit-frame-pointer -Os -fshort-enums -nostartfiles -Wl,--gc-sections -Wl,--defsym=__stack_size=5000 -Wl,--defsym,__minimum_heap_size=2000 " CACHE INTERNAL "executable linker flags")
Также в вызове objcopy параметров явно больше чем у меня - также заберем их к себе (хотя как выяснилось, они мало на что влияют)
ADD_CUSTOM_TARGET(${TARGET}.bin DEPENDS ${TARGET} COMMAND ${CMAKE_OBJCOPY} -j .version -j .bir -j .flashheader -j .vsr_table -j .vsr_handlers  -j .rodata -j .text -j .data -j .bss -j .heap -j .stack -S -O binary ${FILENAME} ${FILENAME}.bin)
Вот только вся эта штука все равно не заработала. Нужно копать дальше. Hello World по железячному. Попытка №3 Еще разок смотрим внимательно на параметры линковщика и видим ключик -TAppBuildZBPro.ld. Ну и конечно же, я забыл скрипт линковщика! Когда мы пишем программу, пускай даже самую простую, вроде Hello World, нам нужен компилятор. Он превратит программу в машинный код. Но этого мало - этот код нужно правильно разместить в памяти, чтобы микроконтроллер его смог выполнить. В этом нам помогает линковщик. А делает он это согласно скрипту, в котором сказано по каким адресам в памяти должен располагаться программный код, где стек, где вектора прерываний, где статические переменные, где константы. Кстати, там же описывается и формат бинаря, который нужно сделать: скрипт описывает какие магические константы где разложить, по каким смещениям раскладывать разные секции кода и данных, и как их описать в заголовке. Именно на это, похоже, и ругался прошивальщик.Подключим этот скрипт к себе в проект, добавив ключик -TAppBuildZBPro.ld в CMAKE_EXE_LINKER_FLAGS
c:/nxp/bstudio_nxp/sdk/tools/ba-elf-ba2-r36379/bin/../lib/gcc/ba-elf/4.7.4/../../../../ba-elf/bin/ld.exe: invalid data statement
collect2.exe: error: ld returned 1 exit status
Ни тебе внятной ошибки, ни номера строчки, которая ему не понравилась.Я попробовал покурить скрипты линковщика, но там я не очень силен. В общем, делать нечего. Я просто начал копировать из рабочей команды ключики в надежде найти нужный, который спасет ситуацию, попутно пытаясь понять за что они отвечают. Я так и не разобрался что именно ему мешало, но через несколько часов мне удалось собрать эту штуку. Дело вот в чем.Помимо всего прочего в этом скрипте линковщика указана точка входа. Дело в том, что до классического main() микроконтроллер должен выполнить еще кое какую начальную инициализацию - начальную настройку CPU, очистить память, установить указатели стека и кучи. Как правило это делает специальная функция, вроде _start() или с подобным названием. Скрипт от NXP ссылается на 2 функции AppColdStart и AppWarmStart, которые реализованы в библиотеке libPWRM_JN516x.a (исходники от нее вместе с SDK не поставляются). Подключив эту библиотеку видим
pwrm_cold_start.c:(.text.AppColdStart+0xc): undefined reference to `vAppRegisterPWRMCallbacks'
pwrm_cold_start.c:(.text.AppColdStart+0xc): relocation truncated to fit: R_BA_18_PCREL against undefined symbol `vAppRegisterPWRMCallbacks'
pwrm_cold_start.c:(.text.AppColdStart+0x1b): undefined reference to `vAppMain'
pwrm_cold_start.c:(.text.AppColdStart+0x1b): relocation truncated to fit: R_BA_10_PCREL against undefined symbol `vAppMain'
Описание этих функций нашлось в документе JN-UG-3116 JN51xx Core Utilities User Guide. Суть в том, что в библиотеке libPWRM_JN516x.a как раз и реализован функционал начальной инициализации, только вместо классического main() эта библиотека вызывает vAppMain(). Ну переименовать функцию нам не сложно.
PUBLIC void vAppMain(void)
{
  int i;
  // Initialize hardware
  vAHI_DioSetDirection(0, BOARD_LED_CTRL_MASK);
  while(1)
  {
    vAHI_DioSetOutput(0, BOARD_LED_PIN);
    for(i=0; i<200000; i++)
            vAHI_DioSetOutput(0, BOARD_LED_PIN);
    vAHI_DioSetOutput(BOARD_LED_PIN, 0);
    for(i=0; i<1000000; i++)
            vAHI_DioSetOutput(BOARD_LED_PIN, 0);
  }
}
В самой функции vAppMain() я уже реализовал классическую моргалку. Пока функции задержки еще не реализованы, пришлось просто вызывать vAHI_DioSetOutput() в цикле. Пустой for, похоже, соптимизировался (или я количество итераций неверно подобрал) и светодиод просто светился.Кстати, интересная особенность функции vAHI_DioSetOutput состоит в том, что она одновременно и включает биты на портах (те, которые указаны в первом параметре) и выключает (второй параметр). Поэтому функции включения и выключения светодиода выглядят очень похоже, только порядок параметров разный).Еще нужна vAppRegisterPWRMCallbacks() - она обслуживает настройку всяких засыпаний/просыпаний. Но нам пока это не нужно, поэтому функцию объявим пустой.На этот раз прошивальщик удовлетворился форматом бинарника, а светодиод на макетке радостно заморгал.Hello Debug UART Наверное, самый сложный этап позади. Но мы же не будем останавливаться на достигнутом, верно? Давайте добавим еще что нибудь полезное в этот проект. Например UART для отладочной информации. Для отладки будем использовать тот же UART, который используется для прошивки. Просто чтобы не цеплять дополнительные провода и USB-UART переходник.Проинициализируем модуль отладочной информации и UART0 на скорость 115200 (можно и быстрее, но там еще кое какие телодвижения нужны - поищите vAppMain в примерах). После этого можно добавлять вызовы DBG_vPrintf в код и печатать что нам требуется.
PUBLIC void vAppMain(void)
{
    int i;
    int iteration = 0;
    // Initialize UART
    DBG_vUartInit(DBG_E_UART_0, DBG_E_UART_BAUD_RATE_115200);
    // Initialize hardware
    vAHI_DioSetDirection(0, BOARD_LED_CTRL_MASK);
    while(1)
    {
        DBG_vPrintf(TRUE, "Blink iteration %d\n", iteration++);
        vAHI_DioSetOutput(0, BOARD_LED_PIN);
        for(i=0; i<1000000; i++)
            vAHI_DioSetOutput(0, BOARD_LED_PIN);
        vAHI_DioSetOutput(BOARD_LED_PIN, 0);
        for(i=0; i<1000000; i++)
            vAHI_DioSetOutput(BOARD_LED_PIN, 0);
    }
}
Первым параметром в DBG_vPrintf можно управлять включением/выключением печати отладочной информации, причем прямо в рантайме. Это прикольно.Компилируем.... и размер бинаря практически не меняется. Заглянув в dbg.h становится понятно, что весь дебажный код просто отключается дефайном DBG_ENABLE. Нужно его включить в настройках проекта, а также подключить целую пачку библиотек.
TARGET_LINK_LIBRARIES(HelloWorld
            -Wl,--start-group
            PWRM_JN516x
            HardwareApi_JN5169
            DBG_JN516x
            Boot_JN516x
            -Wl,--end-group
)
Обратите внимание, что системные библиотеки пришлось затолкать в группу. Дело в том, что линкер работает последовательно, выбирая из библиотек нужные символы (а остальные отбрасывает). Более того к уже подключенным библиотекам линкер не возвращается. Поскольку библиотека DBG_JN516x использует функции UART из HardwareApi_JN5169, которая уже была обработана, возникают unresolved externals функций UART. Ключиками -Wl,--start-group/-Wl,--end-group мы говорим линкеру, чтобы не спешил отбрасывать уже пройденные библиотеки, а вместо этого интерпретировал все библиотеки в группе как одну большую библиотеку. Тогда все нужные символы находятся.Размер бинаря заметно увеличился, и в консоли теперь можно увидеть заветные строчки.
Hello Watchdog Вот только не находите странным, что микроконтроллер умеет считать только до 7?На самом деле тут просто срабатывает сторожевой таймер. По умолчанию сторожевой таймер запускается при инициализации микроконтроллера и срабатывает примерно через 16 секунд. Все что нам нужно сделать это на каждой итерации перезапускать сторожевой таймер функцией vAHI_WatchdogRestart().Кстати говоря, функцией bAHI_WatchdogResetEvent() можно узнать причину перезагрузки микроконтроллера - было это по сработке таймера, или по какой-то другой причине.
PUBLIC void vAppMain(void)
{
    int i;
    int iteration = 0;
    int debugEnabled = 1;
    // Initialize UART
    DBG_vUartInit(DBG_E_UART_0, DBG_E_UART_BAUD_RATE_115200);
    // Initialize hardware
    vAHI_DioSetDirection(0, BOARD_LED_CTRL_MASK);
    if (bAHI_WatchdogResetEvent())
    {
        DBG_vPrintf(TRUE, "APP: Watchdog timer has reset device!\n");
        DBG_vDumpStack();
    }
    while(1)
    {
        DBG_vPrintf(debugEnabled, "Blink iteration %d\n", iteration++);
        vAHI_DioSetOutput(0, BOARD_LED_PIN);
        for(i=0; i<1000000; i++)
            vAHI_DioSetOutput(0, BOARD_LED_PIN);
        vAHI_DioSetOutput(BOARD_LED_PIN, 0);
        for(i=0; i<1000000; i++)
           vAHI_DioSetOutput(BOARD_LED_PIN, 0);
        vAHI_WatchdogRestart();
    }
}
Hello software timers Аналогичным образом подключается и другая периферия микроконтроллера - таймеры, ШИМ, SPI, АЦП, и что там еще есть у JN5169. Не буду сейчас тратить на это время. Вместо этого мне бы хотелось покопать другие штуки, которые часто используются в примерах от NXP. В частности программные таймеры.Таймеры идут в комплекте с реализацией ZigBee стека от NXP, и описаны в документе JN-UG-3113 ZigBee 3.0 Stack User Guide. Попробуем переписать нашу моргалку на таймерах.
ZTIMER_tsTimer timers[1];
uint8 blinkTimerHandle;
PUBLIC void vAppMain(void)
{
  // Initialize UART
  DBG_vUartInit(DBG_E_UART_0, DBG_E_UART_BAUD_RATE_115200);
  // Initialize hardware
  vAHI_DioSetDirection(0, BOARD_LED_CTRL_MASK);
  // Init and start timers
  ZTIMER_eInit(timers, sizeof(timers) / sizeof(ZTIMER_tsTimer));
  ZTIMER_eOpen(&blinkTimerHandle, blinkFunc, NULL, ZTIMER_FLAG_PREVENT_SLEEP);
  ZTIMER_eStart(blinkTimerHandle, ZTIMER_TIME_MSEC(1000));
  while(1)
  {
    ZTIMER_vTask();
    vAHI_WatchdogRestart();
  }
}
В функции vAppMain() объявим, инициализируем, и запустим наш таймер. Таймеров в приложении может быть довольно много, и все они живут в массиве timers. В основном цикле программы нужно запускать функцию ZTIMER_vTask(), которая обслуживает все программные таймеры и вызывает когда нужно обратные вызовы. Кстати об обратных вызовах. Нужно же, собственно, моргульку реализовать.
PUBLIC void blinkFunc(void *pvParam)
{
  static int iteration = 0;
  DBG_vPrintf(TRUE, "Blink iteration %d\n", iteration++);
  uint32 currentState = u32AHI_DioReadInput();
  vAHI_DioSetOutput(currentState^BOARD_LED_PIN, currentState&BOARD_LED_PIN);
}
Тут, кстати, пришлось немного повозиться с битовой магией функции vAHI_DioSetOutput(), чтобы правильно реализовать переключение состояния светодиода.Библиотека ZigBee поставляется в исходниках, а потому ее нужно явно скомпилировать. В своем CMakeLists.txt я выделил ее в отдельную статическую библиотеку.
################################
# Common settings
ADD_DEFINITIONS(
  -DJENNIC_CHIP_NAME=_JN5169
  -DJENNIC_CHIP_FAMILY_NAME=_JN516x
  -DJENNIC_CHIP_FAMILY_JN516x
  -DJENNIC_CHIP_FAMILY=JN516x
  -DJN516x=5160
  -DDBG_ENABLE
  -DEMBEDDED
)
################################
# Zigbee Library
SET(ZIGBEE_SRC
  ${SDK_PREFIX}/Components/ZigbeeCommon/Source/ZTimer.c
)
ADD_LIBRARY(ZigBee STATIC ${ZIGBEE_SRC})
TARGET_INCLUDE_DIRECTORIES(ZigBee PRIVATE
  ${SDK_PREFIX}/Components/PWRM/Include
)
Кстати, обратите внимание на то сколько дефайнов со словом JN5169 пришлось объявить - без них не собирается. Подозреваю, что это еще не все, и список будет пополняться.Запускаем код, иииии... Как вы уже догадались, ничего не работает. После тщательного изучения библиотеки таймеров (благо есть исходники), выясняется, что таймеры работают через прерывания tick timer’а (есть такой специальный вид аппаратного таймера в JN5169). Вот только вскрытие бинаря прошивки показало, что код прерывания в прошивку почему-то не попал. Как интересно.Лезем в код примеров, и после некоторых поисков находим файлик irq_JN516x.S, в котором описана таблица векторов прерываний микроконтроллера. Вот только как она попадает в прошивку? Скомпилировать то этот файл мы можем, но поскольку никто на эту таблицу не ссылается линкер ее просто выбрасывает из прошивки. Но есть зацепка: в том же ассемблерном файле рядом есть еще одна таблица, которая описывает приоритеты прерываний - PIC_ChannelPriorities, и ссылка на эту таблицу нежно завернута в кусок ассемблерного кода внутри макроса TARGET_INITIALISE(). Название звучит достаточно обнадеживающе, тем более, что этот макрос вызывается из vAppMain() в коде примеров. Цепочка зависимостей также включает в себя файл portasm_JN516x.S, где как раз и обнаружилась связь между TARGET_INITIALIZE() и таблицей прерываний.Короче говоря, в моем vAppMain() нехватало вот такого кусочка инициализации
// Initialize the hardware
        TARGET_INITIALISE();
        SET_IPL(0);
        portENABLE_INTERRUPTS();
В общем, насколько я понял из чтения форума community.nxp.com правка файла irq_JN516x.S - это какой-то общепринятый подход по управлению прерываниями и их приоритетами. Вот только я не нашел где это описано в документации. Интересно то, что в примерах рядом есть код для JN5179. Так вот там управление прерываниями происходит прямо в коде вызовом соответствующих функций.Теперь можно заливать прошивку и запускать. Светодиод моргнул один раз и застыл. В чем проблема? Опять лезем в код программных таймеров и в коде функции ZTIMER_vTask() видим, что таймеры умеют срабатывать только один раз - там попросту нет кода, который бы запускал следующий цикл таймера. И хотя реализовать это не составит труда, потенциально это может сломать код ZigBee стека, который также использует таймеры и не ожидает такого поведения. Проще перезапустить таймер в нашем обработчике.
PUBLIC void blinkFunc(void *pvParam)
{
  static int iteration = 0;
  DBG_vPrintf(TRUE, "Blink iteration %d\n", iteration++);
  uint32 currentState = u32AHI_DioReadInput();
  vAHI_DioSetOutput(currentState^BOARD_LED_PIN, currentState&BOARD_LED_PIN);
  ZTIMER_eStart(blinkTimerHandle, ZTIMER_TIME_MSEC(1000));
}
Hello queues Следующее на очереди с чем бы хотелось сегодня разобраться это очереди (извините за тавтологию) сообщений. Разные компоненты прошивки могут между собой обмениваться сообщениями через очереди. Для примера, пускай короткое нажатие на пользовательскую кнопку будет менять частоту моргания светодиода, а длинное нажатие - будет включать/выключать моргание целиком. И сделаем мы это через очереди.Для этого запустим 2 периодические задачи - одна будет обслуживать кнопку, а другая - светодиод. Для начала инициализация в vAppMain(). Тут добавилась инициализация пина кнопки, включение pull-up резистора для нее, а также запуск еще одного таймера. Ну и самое важное для этого раздела - инициализация очереди. Думаю длины очереди в 3 элемента более чем достаточно.
// Initialize hardware
  vAHI_DioSetDirection(BOARD_BTN_PIN, BOARD_LED_PIN);
  vAHI_DioSetPullup(BOARD_BTN_PIN, 0);
  // Init and start timers
  ZTIMER_eInit(timers, sizeof(timers) / sizeof(ZTIMER_tsTimer));
  ZTIMER_eOpen(&blinkTimerHandle, blinkFunc, NULL, ZTIMER_FLAG_PREVENT_SLEEP);
  ZTIMER_eStart(blinkTimerHandle, ZTIMER_TIME_MSEC(1000));
  ZTIMER_eOpen(&buttonScanTimerHandle, buttonScanFunc, NULL, ZTIMER_FLAG_PREVENT_SLEEP);
  ZTIMER_eStart(buttonScanTimerHandle, ZTIMER_TIME_MSEC(10));
  // Initialize queue
  ZQ_vQueueCreate(&queueHandle, 3, sizeof(ButtonPressType), (uint8*)queue);
Подпрограмма обслуживания кнопки будет вызываться раз в 10мс, и считать длительность нажатия. Совсем короткие срабатывания (меньше 50мс) будем отбрасывать, считая это дребезгом контактов. Также будем различать короткое и длинное (>2c) нажатия, и отправлять соответствующие сообщения в очередь.
typedef enum
{
  BUTTON_SHORT_PRESS,
  BUTTON_LONG_PRESS
} ButtonPressType;
PUBLIC void buttonScanFunc(void *pvParam)
{
  static int duration = 0;
  uint32 input = u32AHI_DioReadInput();
  bool btnState = (input & BOARD_BTN_PIN) == 0;
  if(btnState)
  {
    duration++;
  }
  else
  {
    // detect long press
    if(duration > 200)
    {
      DBG_vPrintf(TRUE, "Button released. Long press detected\n");
      ButtonPressType value = BUTTON_LONG_PRESS;
      ZQ_bQueueSend(&queueHandle, (uint8*)&value);
    }
    // detect short press
    else if(duration > 5)
    {
      DBG_vPrintf(TRUE, "Button released. Short press detected\n");
      ButtonPressType value = BUTTON_SHORT_PRESS;
      ZQ_bQueueSend(&queueHandle, &value);
    }
    duration = 0;
  }
  ZTIMER_eStart(buttonScanTimerHandle, ZTIMER_TIME_MSEC(10));
}
Теперь функция моргания. В зависимости от принятого сообщения из очереди меняются параметры моргания - быстро/медленно, включено/выключено. Ну и если включено, то моргаем с необходимой скоростью.
PUBLIC void blinkFunc(void *pvParam)
{
  static uint8 fastBlink = TRUE;
  static uint8 enabled = TRUE;
  ButtonPressType value;
  if(ZQ_bQueueReceive(&queueHandle, (uint8*)&value))
  {
    if(value == BUTTON_SHORT_PRESS)
      fastBlink = fastBlink ? FALSE : TRUE;
    if(value == BUTTON_LONG_PRESS)
      enabled = enabled ? FALSE : TRUE;
  }
  if(enabled)
  {
    uint32 currentState = u32AHI_DioReadInput();
    vAHI_DioSetOutput(currentState^BOARD_LED_PIN, currentState&BOARD_LED_PIN);
  }
  ZTIMER_eStart(blinkTimerHandle, fastBlink? ZTIMER_TIME_MSEC(200) : ZTIMER_TIME_MSEC(1000));
}
В этот раз все сработало как надо, и обошлось без существенной возни с конфигурацией. Hello DIO Interrupts Опрос кнопок в цикле это, конечно, круто и просто, но энергозатратно. Для батарейных устройств это может быть неприемлемо. Попробуем отойти от постоянного опроса кнопки, а вместо этого воспользоваться прерыванием по спадающему фронту на соответствующем пине.Вот так теперь будет выглядеть инициализация.
// Initialize hardware
  vAHI_DioSetDirection(BOARD_BTN_PIN, BOARD_LED_PIN);
  vAHI_DioSetPullup(BOARD_BTN_PIN, 0);
  vAHI_DioInterruptEdge(0, BOARD_BTN_PIN);
  vAHI_DioInterruptEnable(BOARD_BTN_PIN, 0);
  // Init and start timers
  ZTIMER_eInit(timers, sizeof(timers) / sizeof(ZTIMER_tsTimer));
  ZTIMER_eOpen(&blinkTimerHandle, blinkFunc, NULL, ZTIMER_FLAG_PREVENT_SLEEP);
  ZTIMER_eStart(blinkTimerHandle, ZTIMER_TIME_MSEC(1000));
  ZTIMER_eOpen(&buttonScanTimerHandle, buttonScanFunc, NULL, ZTIMER_FLAG_PREVENT_SLEEP);
  //ZTIMER_eStart(buttonScanTimerHandle, ZTIMER_TIME_MSEC(10));
Прерывание по фронту включается функциями vAHI_DioInterruptEdge() и vAHI_DioInterruptEnable(). Обратите внимание, что я закомментировал старт таймера опроса кнопок (но функция инициализации таймера ZTIMER_eOpen() по прежнему нужна)В отличии от ATMega или STM32, в JN5169 множество событий приходят на одно и то же прерывание - vISR_SystemController(). Тут и прерывания от компаратора, и в случае изменения состояния пина, и изменение напряжение питания, и просыпание по таймеру, и что-то там еще. Выяснить что же именно случилось можно вызовом соответствующих функций.
PUBLIC void vISR_SystemController(void)
{
    DBG_vPrintf(TRUE, "In vISR_SystemController\n");
    if(u32AHI_DioInterruptStatus() & BOARD_BTN_PIN)
    {
        DBG_vPrintf(TRUE, "Button interrupt\n");
        ZTIMER_eStart(buttonScanTimerHandle, ZTIMER_TIME_MSEC(10));
    }
}
Нам пока интересно событие DIO Interrupt. Событие это произойдет по нажатию на кнопку. В этот момент уже можно смело запускать таймер опроса, который будет опрашивать пин пока кнопку не отпустят.Опрос кнопок изменился лишь незначительно. Теперь таймер перезапускается не всегда, а только пока нажата кнопка.
PUBLIC void buttonScanFunc(void *pvParam)
{
  static int duration = 0;
  uint32 input = u32AHI_DioReadInput();
  bool btnState = (input & BOARD_BTN_PIN) == 0;
  if(btnState)
  {
    duration++;
    DBG_vPrintf(TRUE, "Button still pressed for %d ticks\n", duration);
    ZTIMER_eStart(buttonScanTimerHandle, ZTIMER_TIME_MSEC(10));
  }
  else
  {
    // detect long press
    if(duration > 200)
    {
      DBG_vPrintf(TRUE, "Button released. Long press detected\n");
      ButtonPressType value = BUTTON_LONG_PRESS;
      ZQ_bQueueSend(&queueHandle, (uint8*)&value);
    }
    // detect short press
    else if(duration > 10)
    {
      DBG_vPrintf(TRUE, "Button released. Short press detected\n");
      ButtonPressType value = BUTTON_SHORT_PRESS;
      ZQ_bQueueSend(&queueHandle, &value);
    }
    duration = 0;
  }
}
Как и в случае с прерываниями от Tick Timer’а, функцию vISR_SystemController() нужно прописать в таблице векторов прерываний в файле irq_JN516x.S.Стоило ли так сильно заморачиваться с таймерами? Не факт, но мне важно было пощупать DIO Interrupt, когда какие-то процессы (опрос кнопок) начинают происходить по событию на пине.Hello sleep/wake Следующее, что я бы хотел сегодня попробовать это функциональность засыпания микроконтроллера. Скажу что тут пришлось изрядно повозиться. Не потому, что это сложно, а потому что пришлось перекроить структуру почти всей прошивки. Теперь я начинаю понимать почему в примерах так все запутанно - у меня начинает быть также :)Функциональность, связанная с засыпанием/просыпанием находится в модуль PWRM (надо полагать Power Management). Фреймворк позволяет зарегистрировать 2 обратных вызова, которые будут выполняться перед входом в режим сна, а также после выхода.
static PWRM_DECLARE_CALLBACK_DESCRIPTOR(PreSleep);
static PWRM_DECLARE_CALLBACK_DESCRIPTOR(Wakeup);
PWRM_CALLBACK(PreSleep)
{
    DBG_vPrintf(TRUE, "Going to sleep..\n\n");
    DBG_vUartFlush();
    ZTIMER_vSleep();
    // Disable UART (if enabled)
    vAHI_UartDisable(E_AHI_UART_0);
    // clear interrupts
    u32AHI_DioWakeStatus();
    // Set the wake condition on falling edge of the button pin
    vAHI_DioWakeEdge(0, BOARD_BTN_PIN);
    vAHI_DioWakeEnable(BOARD_BTN_PIN, 0);
}
PWRM_CALLBACK(Wakeup)
{
    // Stabilise the oscillator
    while (bAHI_GetClkSource() == TRUE);
    // Now we are running on the XTAL, optimise the flash memory wait states
    vAHI_OptimiseWaitStates();
    // Re-initialize Debug UART
    DBG_vUartInit(DBG_E_UART_0, DBG_E_UART_BAUD_RATE_115200);
    DBG_vPrintf(TRUE, "\nWaking..\n");
    DBG_vUartFlush();
    // Re-initialize hardware and interrupts
    TARGET_INITIALISE();
    SET_IPL(0);
    portENABLE_INTERRUPTS();
    // Wake the timers
    ZTIMER_vWake();
}
void vAppRegisterPWRMCallbacks(void)
{
    PWRM_vRegisterPreSleepCallback(PreSleep);
    PWRM_vRegisterWakeupCallback(Wakeup);
}
Функция PreSleep() занимается остановкой всех активных процессов - усыпляет таймеры, выключает UART и, если нужно, GPIO. Самое последнее, что делает функция это настраивает просыпание микроконтроллера по нажатию кнопки.Функция Wakeup() выполняет обратную процедуру - запускает тактирование, настраивает отладочный UART, настраивает другую периферию, будит таймеры. По сути эта функция делает практически всю такую же настройку железа как и vAppMain(), разве что таймеры не инициализирует.Функция моргания слегка изменилась (для простоты структуры пришлось вернуться к варианту из раздела про очереди).
uint8 enabled = TRUE;
PUBLIC void blinkFunc(void *pvParam)
{
  static uint8 fastBlink = TRUE;
  ButtonPressType value;
  if(ZQ_bQueueReceive(&queueHandle, (uint8*)&value))
  {
    DBG_vPrintf(TRUE, "Processing message in blink task\n");
    if(value == BUTTON_SHORT_PRESS)
      fastBlink = fastBlink ? FALSE : TRUE;
    if(value == BUTTON_LONG_PRESS)
    {
      DBG_vPrintf(TRUE, "Stop Blinking\n");
      vAHI_DioSetOutput(BOARD_LED_PIN, 0);
      enabled = FALSE;
    }
  }
  if(enabled)
  {
    uint32 currentState = u32AHI_DioReadInput();
    vAHI_DioSetOutput(currentState^BOARD_LED_PIN, currentState&BOARD_LED_PIN);
  }
  ZTIMER_eStart(blinkTimerHandle, fastBlink? ZTIMER_TIME_MSEC(200) : ZTIMER_TIME_MSEC(1000));
}
Флажок enabled теперь переехал в глобальную область видимости, т.к. именно этот флаг будет управлять засыпанием. Все остальное осталось практически таким же.Функция опроса кнопки не изменилась. И хотя в принципе заснуть можно было прямо в ней как только обнаружено длинное нажатие, я решил, что все таки будет правильнее отправить сообщение в функцию моргания, чтобы дать той возможность закончить свои дела и выключить светодиод.
PUBLIC void buttonScanFunc(void *pvParam)
{
  static int duration = 0;
  uint32 input = u32AHI_DioReadInput();
  bool btnState = (input & BOARD_BTN_PIN) == 0;
  if(btnState)
  {
    duration++;
    DBG_vPrintf(TRUE, "Button still pressed for %d ticks\n", duration);
  }
  else
  {
    // detect long press
    if(duration > 200)
    {
      DBG_vPrintf(TRUE, "Button released. Long press detected\n");
      ButtonPressType value = BUTTON_LONG_PRESS;
      ZQ_bQueueSend(&queueHandle, (uint8*)&value);
    }
    // detect short press
    else if(duration > 5)
    {
      DBG_vPrintf(TRUE, "Button released. Short press detected\n");
      ButtonPressType value = BUTTON_SHORT_PRESS;
      ZQ_bQueueSend(&queueHandle, &value);
    }
    duration = 0;
  }
  ZTIMER_eStart(buttonScanTimerHandle, ZTIMER_TIME_MSEC(10));
}
Как же, собственно, организовано засыпание и просыпание? Взглянем на vAppMain(). Для начала обращу ваше внимание, что таймеры теперь запускаются с флагом ALLOW_SLEEP. Раньше мы их запускали с флагом PREVENT_SLEEP, что означает, что микроконтроллер не отправится спать, пока такие таймеры работают. Их нужно в явном виде остановить перед засыпанием. Я пробовал так делать, но это еще больше усложняет структуру кода. Пускай они просто тикают всегда, когда микроконтроллер не спит, и автоматически засыпают и просыпаются вместе с микроконтроллером.
// Init and start timers
  ZTIMER_eInit(timers, sizeof(timers) / sizeof(ZTIMER_tsTimer));
  ZTIMER_eOpen(&blinkTimerHandle, blinkFunc, NULL, ZTIMER_FLAG_ALLOW_SLEEP);
  ZTIMER_eStart(blinkTimerHandle, ZTIMER_TIME_MSEC(1000));
  ZTIMER_eOpen(&buttonScanTimerHandle, buttonScanFunc, NULL, ZTIMER_FLAG_ALLOW_SLEEP);
  ZTIMER_eStart(buttonScanTimerHandle, ZTIMER_TIME_MSEC(10));
Взглянем на главный цикл
PRIVATE uint8 keepAliveTime = 10;
PRIVATE pwrm_tsWakeTimerEvent wakeStruct;
PUBLIC void vAppMain(void)
{
...
  // Let the device go to sleep if there is nothing to do
  PWRM_vInit(E_AHI_SLEEP_OSCON_RAMON);
  while(1)
  {
    ZTIMER_vTask();
    vAHI_WatchdogRestart();
    if(enabled == FALSE)
    {
      DBG_vPrintf(TRUE, "Scheduling wake task\n");
      PWRM_eScheduleActivity(&wakeStruct, keepAliveTime * 32000, wakeCallBack);
    }
    PWRM_vManagePower();
  }
Для начала нужно инициализировать управление питанием (и засыпанием) вызовом PWRM_vInit(). Тут мы указываем степень засыпания микроконтроллера - E_AHI_SLEEP_OSCON_RAMON, что означает wake up timer не выключать, память не очищать. Про память это важно - нам нужно сохранить флажок enabled. Если память отключать, то тогда при просыпании микроконтроллер не будет помнить состояние этого флага. В принципе wake up таймер нам, может быть, и не нужен - будем просыпаться по кнопке, но мне нужно было эту функциональность попробовать для других задач связанных с ZigBee.Собственно засыпание производится функцией PWRM_vManagePower(). Но эта функция не так проста как кажется. Она сама решает может ли микроконтроллер сейчас спать или нет. В частности функция требует двух критериев. Во-первых не должно быть никаких активных задач (например таймеров с флаго PREVENT_SLEEP). А во-вторых должен быть запущен таймер просыпания, который взводится функцией PWRM_eScheduleActivity(), что делается в зависимости от флага enabled.Наконец, рассмотрим обработчик прерывания системного контроллера - в него будет прилетать сообщение о том, что процессор проснулся
PUBLIC void vISR_SystemController(void)
{
    // clear pending DIO changed bits by reading register
    uint8 u8WakeInt = u8AHI_WakeTimerFiredStatus();
    uint32 u32IOStatus = u32AHI_DioInterruptStatus();
    DBG_vPrintf(TRUE, "In vISR_SystemController\n");
    if(u32IOStatus & BOARD_BTN_PIN)
    {
        DBG_vPrintf(TRUE, "Button interrupt\n");
        enabled = TRUE;
        PWRM_vWakeInterruptCallback();
    }
    if(u8WakeInt & E_AHI_WAKE_TIMER_MASK_1)
    {
        /* wake timer interrupt got us here */
        DBG_vPrintf(TRUE, "APP: Wake Timer 1 Interrupt\n");
        PWRM_vWakeInterruptCallback();
    }
}
У нас есть 2 события, которые могут разбудить систему - по прерыванию от кнопки, а также от будильника. В случае кнопки взведем флаг enabled, который зупустит моргалку. В случае просыпания по таймеру просто отметимся и пойдем спать дальше. Фреймворк автоматически будет вызывать функции PreSleep() и Wakeup(), а также функцию, которая была указана при вызове PWRM_eScheduleActivity().
PUBLIC void wakeCallBack(void)
{
    DBG_vPrintf(TRUE, "wakeCallBack()\n");
}
Вот так выглядит засыпание устройства по длительному нажатию кнопки, периодическое просыпание по будильнику, и, наконец, просыпание по кнопке.
Hello Deep Sleep В предыдущем примере использовался не очень глубокий режим сна - работал wake up таймер, и память не отключалась. Возможно для некоторых батарейных устройств это не подходит, и нужно использовать более режимы более глубокого сна. Например так.
PUBLIC void vAppMain(void)
{
...
  // Let the device go to sleep if there is nothing to do
  PWRM_vInit(E_AHI_SLEEP_DEEP);
  while(1)
  {
    ZTIMER_vTask();
    vAHI_WatchdogRestart();
    if(enabled == FALSE)
    {
      DBG_vPrintf(TRUE, "Scheduling sleep\n");
      PWRM_vManagePower();
    }
  }
}
Ну можно еще убрать обработку wake up таймера в функции vISR_SystemController(), но это не обязательно. При таком подходе есть один неочевидный нюанс. Он заключается в том, что при каждом засыпании останавливаются все системы микроконтроллера, включая память. А это означает, что при просыпании микроконтроллер производит полный цикл инициализации (полная перезагрузка) - будет запускаться vAppMain() вместо Wakeup(). А это в свою очередь означает, что режим моргания не будет запоминаться, и всегда будет стартовать с медленного моргания. И хотя для светодиодной моргалки сохранение состояния это может быть очень не критично, в реальном устройстве скорее всего нужно будет сохранять некоторые данные между перезагрузками.Чтобы реализовать сохранение состояния можем воспользоваться EEPROM. И тут производитель предоставляет 2 подхода
  • низкоуровневое использование EEPROM - может читать и записывать в EEPROM сырые блоки байт
  • Persistent Data Manager (PDM) - предоставляет вариант key-value storage в EEPROM
Будем использовать второй подход, т.к. это согласуется с ZigBee фреймворком, который также использует PDM, чтобы сохранять свои параметры. В принципе ничего военного в этом нет. Просто напишем функции сохранения и загрузки значения.
#define PDM_ID_BLINK_MODE         0x2
#define BLINK_MODE_SLOW        0
#define BLINK_MODE_FAST        1
uint8 blinkMode = BLINK_MODE_SLOW;
void storeBlinkMode(uint8 mode)
{
  blinkMode = mode;
  PDM_teStatus status = PDM_eSaveRecordData(PDM_ID_BLINK_MODE, &blinkMode, sizeof(blinkMode));
  DBG_vPrintf(TRUE, "Storing blink mode. Status %d, value %d\n", status, blinkMode);
}
void restoreBlinkMode()
{
  uint16 readBytes;
  PDM_teStatus status = PDM_eReadDataFromRecord(PDM_ID_BLINK_MODE, &blinkMode, sizeof(blinkMode), &readBytes);
  DBG_vPrintf(TRUE, "Reading blink mode. Status %d, size %d, value %d\n", status, readBytes, blinkMode);
}
Сохранять будем в функции blinkFunc(), которая уже обрабатывает это изменение по сообщению из очереди (не буду опять приводить код этой функции, там ничего кроме дополнительного вызова blinkFunc() не поменялось). Загружать будем в vAppMain() - именно эта функция будет инициализировать микроконтроллер при выходе из режима глубокого сна. Кстати, чтобы функции PDM работали нужно не забыть инициализировать этот компонент.
PUBLIC void vAppMain(void)
{
...
  // Restore blink mode from EEPROM
  PDM_eInitialise(0);
  restoreBlinkMode();
Заключение Начать работу с микроконтроллером JN5169 оказалось не очень сложно, хотя путь предложенный производителем мог бы быть и попроще. Мне удалось превратить нечто большое и непонятное в маленькое и понятное, где я понимаю суть (почти) каждой строчки. Конечно же это только HelloWorld - серия совсем базовых упражнений для нового для меня микроконтроллера. Мне по прежнему предстоит съесть слона под названием ZigBee. Но хотя бы кусочек этого слона удалось откусить, прожевать, и переварить.За кадром остался вопрос заливки прошивки из консоли, чтобы совсем не включать BeyondStudio. Как и отладка и сборка примеров из самой BeyondStudio. Будет круто, если знатоки Eclipse/BeyondStudio мне помогут правильно сделать проект под это, чтобы было также понятно как и в случае использования CMake.Буду благодарен за конструктивную критику в комментариях.Код примеров: https://github.com/grafalex82/hellojn5169worldИспользованная документация:https://www.nxp.com/docs/en/user-guide/JN-UG-3113.pdfhttps://www.nxp.com/docs/en/user-guide/JN-UG-3116.pdfhttps://www.nxp.com/docs/en/user-guide/JN-UG-3087.pdfhttps://www.rcscomponents.kiev.ua/datasheets/e75-2g4m10s_usermanual_en_v1_1.pdf
===========
Источник:
habr.com
===========

Похожие новости: Теги для поиска: #_sistemnoe_programmirovanie (Системное программирование), #_reversinzhiniring (Реверс-инжиниринг), #_programmirovanie_mikrokontrollerov (Программирование микроконтроллеров), #_internet_veschej (Интернет вещей), #_diy_ili_sdelaj_sam (DIY или Сделай сам), #_nxp, #_jn5169, #_hello_world, #_sistemnoe_programmirovanie (
Системное программирование
)
, #_reversinzhiniring (
Реверс-инжиниринг
)
, #_programmirovanie_mikrokontrollerov (
Программирование микроконтроллеров
)
, #_internet_veschej (
Интернет вещей
)
, #_diy_ili_sdelaj_sam (
DIY или Сделай сам
)
Профиль  ЛС 
Показать сообщения:     

Вы не можете начинать темы
Вы не можете отвечать на сообщения
Вы не можете редактировать свои сообщения
Вы не можете удалять свои сообщения
Вы не можете голосовать в опросах
Вы не можете прикреплять файлы к сообщениям
Вы не можете скачивать файлы

Текущее время: 13-Май 22:16
Часовой пояс: UTC + 5