Add bin2c : tool to convert a .bin file into a C array.
Add factory/image.h : the C array version of infiniTime-light (converted by bin2c). Add new 'factory' target : flashes the factory image into the spi flash.
This commit is contained in:
parent
2488777e27
commit
89783286da
13629
factory/image.h
Normal file
13629
factory/image.h
Normal file
File diff suppressed because it is too large
Load Diff
@ -404,6 +404,24 @@ list(APPEND GRAPHICS_SOURCE_FILES
|
|||||||
graphics.cpp
|
graphics.cpp
|
||||||
)
|
)
|
||||||
|
|
||||||
|
list(APPEND FACTORY_SOURCE_FILES
|
||||||
|
# FreeRTOS
|
||||||
|
FreeRTOS/port.c
|
||||||
|
FreeRTOS/port_cmsis_systick.c
|
||||||
|
FreeRTOS/port_cmsis.c
|
||||||
|
|
||||||
|
drivers/SpiNorFlash.cpp
|
||||||
|
drivers/SpiMaster.cpp
|
||||||
|
drivers/Spi.cpp
|
||||||
|
logging/NrfLogger.cpp
|
||||||
|
|
||||||
|
components/gfx/Gfx.cpp
|
||||||
|
drivers/St7789.cpp
|
||||||
|
components/brightness/BrightnessController.cpp
|
||||||
|
|
||||||
|
factory.cpp
|
||||||
|
)
|
||||||
|
|
||||||
set(INCLUDE_FILES
|
set(INCLUDE_FILES
|
||||||
BootloaderVersion.h
|
BootloaderVersion.h
|
||||||
logging/Logger.h
|
logging/Logger.h
|
||||||
@ -707,6 +725,35 @@ add_custom_command(TARGET ${EXECUTABLE_GRAPHICS_NAME}
|
|||||||
COMMENT "post build steps for ${EXECUTABLE_GRAPHICS_FILE_NAME}"
|
COMMENT "post build steps for ${EXECUTABLE_GRAPHICS_FILE_NAME}"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
# Build binary that writes the factory image
|
||||||
|
set(EXECUTABLE_FACTORY_NAME "pinetime-factory")
|
||||||
|
set(EXECUTABLE_FACTORY_FILE_NAME ${EXECUTABLE_FACTORY_NAME}-${pinetime_VERSION_MAJOR}.${pinetime_VERSION_MINOR}.${pinetime_VERSION_PATCH})
|
||||||
|
add_executable(${EXECUTABLE_FACTORY_NAME} ${FACTORY_SOURCE_FILES})
|
||||||
|
target_link_libraries(${EXECUTABLE_FACTORY_NAME} nrf-sdk)
|
||||||
|
set_target_properties(${EXECUTABLE_FACTORY_NAME} PROPERTIES OUTPUT_NAME ${EXECUTABLE_FACTORY_FILE_NAME})
|
||||||
|
target_compile_options(${EXECUTABLE_FACTORY_NAME} PUBLIC
|
||||||
|
$<$<AND:$<COMPILE_LANGUAGE:C>,$<CONFIG:DEBUG>>: ${COMMON_FLAGS} -O0 -g3>
|
||||||
|
$<$<AND:$<COMPILE_LANGUAGE:C>,$<CONFIG:RELEASE>>: ${COMMON_FLAGS} -O3>
|
||||||
|
$<$<AND:$<COMPILE_LANGUAGE:CXX>,$<CONFIG:DEBUG>>: ${COMMON_FLAGS} -O0 -g3>
|
||||||
|
$<$<AND:$<COMPILE_LANGUAGE:CXX>,$<CONFIG:RELEASE>>: ${COMMON_FLAGS} -O3>
|
||||||
|
$<$<COMPILE_LANGUAGE:ASM>: -MP -MD -std=c99 -x assembler-with-cpp>
|
||||||
|
)
|
||||||
|
|
||||||
|
set_target_properties(${EXECUTABLE_FACTORY_NAME} PROPERTIES
|
||||||
|
SUFFIX ".out"
|
||||||
|
LINK_FLAGS "-mthumb -mabi=aapcs -std=gnu++98 -std=c99 -L ${NRF5_SDK_PATH}/modules/nrfx/mdk -T${NRF5_LINKER_SCRIPT} -mcpu=cortex-m4 -mfloat-abi=hard -mfpu=fpv4-sp-d16 -Wl,--gc-sections --specs=nano.specs -lc -lnosys -lm -Wl,-Map=${EXECUTABLE_FACTORY_FILE_NAME}.map"
|
||||||
|
CXX_STANDARD 11
|
||||||
|
C_STANDARD 99
|
||||||
|
)
|
||||||
|
|
||||||
|
add_custom_command(TARGET ${EXECUTABLE_FACTORY_NAME}
|
||||||
|
POST_BUILD
|
||||||
|
COMMAND ${CMAKE_SIZE_UTIL} ${EXECUTABLE_FACTORY_FILE_NAME}.out
|
||||||
|
COMMAND ${CMAKE_OBJCOPY} -O binary ${EXECUTABLE_FACTORY_FILE_NAME}.out "${EXECUTABLE_FACTORY_FILE_NAME}.bin"
|
||||||
|
COMMAND ${CMAKE_OBJCOPY} -O ihex ${EXECUTABLE_FACTORY_FILE_NAME}.out "${EXECUTABLE_FACTORY_FILE_NAME}.hex"
|
||||||
|
COMMENT "post build steps for ${EXECUTABLE_FACTORY_FILE_NAME}"
|
||||||
|
)
|
||||||
|
|
||||||
# FLASH
|
# FLASH
|
||||||
if (USE_JLINK)
|
if (USE_JLINK)
|
||||||
add_custom_target(FLASH_ERASE
|
add_custom_target(FLASH_ERASE
|
||||||
|
143
src/factory.cpp
Normal file
143
src/factory.cpp
Normal file
@ -0,0 +1,143 @@
|
|||||||
|
#include <legacy/nrf_drv_clock.h>
|
||||||
|
#include <softdevice/common/nrf_sdh.h>
|
||||||
|
#include <drivers/SpiMaster.h>
|
||||||
|
#include <drivers/Spi.h>
|
||||||
|
#include <drivers/SpiNorFlash.h>
|
||||||
|
#include <libraries/log/nrf_log.h>
|
||||||
|
#include <FreeRTOS.h>
|
||||||
|
#include <task.h>
|
||||||
|
#include <legacy/nrf_drv_gpiote.h>
|
||||||
|
#include <libraries/gpiote/app_gpiote.h>
|
||||||
|
#include <hal/nrf_wdt.h>
|
||||||
|
#include <cstring>
|
||||||
|
#include <components/gfx/Gfx.h>
|
||||||
|
#include <drivers/St7789.h>
|
||||||
|
#include <components/brightness/BrightnessController.h>
|
||||||
|
#include "../factory/image.h"
|
||||||
|
|
||||||
|
#if NRF_LOG_ENABLED
|
||||||
|
#include "logging/NrfLogger.h"
|
||||||
|
Pinetime::Logging::NrfLogger logger;
|
||||||
|
#else
|
||||||
|
#include "logging/DummyLogger.h"
|
||||||
|
Pinetime::Logging::DummyLogger logger;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
static constexpr uint8_t pinSpiSck = 2;
|
||||||
|
static constexpr uint8_t pinSpiMosi = 3;
|
||||||
|
static constexpr uint8_t pinSpiMiso = 4;
|
||||||
|
static constexpr uint8_t pinSpiFlashCsn = 5;
|
||||||
|
static constexpr uint8_t pinLcdCsn = 25;
|
||||||
|
static constexpr uint8_t pinLcdDataCommand = 18;
|
||||||
|
|
||||||
|
Pinetime::Drivers::SpiMaster spi{Pinetime::Drivers::SpiMaster::SpiModule::SPI0, {
|
||||||
|
Pinetime::Drivers::SpiMaster::BitOrder::Msb_Lsb,
|
||||||
|
Pinetime::Drivers::SpiMaster::Modes::Mode3,
|
||||||
|
Pinetime::Drivers::SpiMaster::Frequencies::Freq8Mhz,
|
||||||
|
pinSpiSck,
|
||||||
|
pinSpiMosi,
|
||||||
|
pinSpiMiso
|
||||||
|
}
|
||||||
|
};
|
||||||
|
Pinetime::Drivers::Spi flashSpi{spi, pinSpiFlashCsn};
|
||||||
|
Pinetime::Drivers::SpiNorFlash spiNorFlash{flashSpi};
|
||||||
|
|
||||||
|
Pinetime::Drivers::Spi lcdSpi {spi, pinLcdCsn};
|
||||||
|
Pinetime::Drivers::St7789 lcd {lcdSpi, pinLcdDataCommand};
|
||||||
|
|
||||||
|
Pinetime::Components::Gfx gfx{lcd};
|
||||||
|
Pinetime::Controllers::BrightnessController brightnessController;
|
||||||
|
|
||||||
|
extern "C" {
|
||||||
|
void vApplicationIdleHook(void) {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
void SPIM0_SPIS0_TWIM0_TWIS0_SPI0_TWI0_IRQHandler(void) {
|
||||||
|
if(((NRF_SPIM0->INTENSET & (1<<6)) != 0) && NRF_SPIM0->EVENTS_END == 1) {
|
||||||
|
NRF_SPIM0->EVENTS_END = 0;
|
||||||
|
spi.OnEndEvent();
|
||||||
|
}
|
||||||
|
|
||||||
|
if(((NRF_SPIM0->INTENSET & (1<<19)) != 0) && NRF_SPIM0->EVENTS_STARTED == 1) {
|
||||||
|
NRF_SPIM0->EVENTS_STARTED = 0;
|
||||||
|
spi.OnStartedEvent();
|
||||||
|
}
|
||||||
|
|
||||||
|
if(((NRF_SPIM0->INTENSET & (1<<1)) != 0) && NRF_SPIM0->EVENTS_STOPPED == 1) {
|
||||||
|
NRF_SPIM0->EVENTS_STOPPED = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void Process(void* instance) {
|
||||||
|
// Wait before erasing the memory to let the time to the SWD debugger to flash a new firmware before running this one.
|
||||||
|
vTaskDelay(5000);
|
||||||
|
|
||||||
|
APP_GPIOTE_INIT(2);
|
||||||
|
|
||||||
|
NRF_LOG_INFO("Init...");
|
||||||
|
spi.Init();
|
||||||
|
spiNorFlash.Init();
|
||||||
|
spiNorFlash.Wakeup();
|
||||||
|
brightnessController.Init();
|
||||||
|
lcd.Init();
|
||||||
|
gfx.Init();
|
||||||
|
NRF_LOG_INFO("Init Done!")
|
||||||
|
|
||||||
|
for(int i = 0; i < 100; i++) {
|
||||||
|
for(int j = 0; j < 100; j++) {
|
||||||
|
gfx.pixel_draw(70+i, 70+j, 0x00AA);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
NRF_LOG_INFO("Erasing...");
|
||||||
|
for (uint32_t erased = 0; erased < sizeof(factoryImage); erased += 0x1000) {
|
||||||
|
spiNorFlash.SectorErase(erased);
|
||||||
|
}
|
||||||
|
NRF_LOG_INFO("Erase done!");
|
||||||
|
|
||||||
|
NRF_LOG_INFO("Writing graphic...");
|
||||||
|
for(int i = 0; i < 100; i++) {
|
||||||
|
for(int j = 0; j < 100; j++) {
|
||||||
|
gfx.pixel_draw(70+i, 70+j, 0xaa00);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static constexpr uint32_t memoryChunkSize = 200;
|
||||||
|
uint8_t writeBuffer[memoryChunkSize];
|
||||||
|
for(int offset = 0; offset < sizeof(factoryImage); offset+=memoryChunkSize) {
|
||||||
|
std::memcpy(writeBuffer, &factoryImage[offset], memoryChunkSize);
|
||||||
|
spiNorFlash.Write(offset, writeBuffer, memoryChunkSize);
|
||||||
|
}
|
||||||
|
NRF_LOG_INFO("Writing graphic done!");
|
||||||
|
|
||||||
|
for(int i = 0; i < 100; i++) {
|
||||||
|
for(int j = 0; j < 100; j++) {
|
||||||
|
gfx.pixel_draw(70+i, 70+j, 0xffff);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
NRF_LOG_INFO("Done!");
|
||||||
|
|
||||||
|
while(1) {
|
||||||
|
asm("nop" );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
int main(void) {
|
||||||
|
TaskHandle_t taskHandle;
|
||||||
|
|
||||||
|
logger.Init();
|
||||||
|
nrf_drv_clock_init();
|
||||||
|
|
||||||
|
if (pdPASS != xTaskCreate(Process, "MAIN", 512, nullptr, 0, &taskHandle))
|
||||||
|
APP_ERROR_HANDLER(NRF_ERROR_NO_MEM);
|
||||||
|
|
||||||
|
vTaskStartScheduler();
|
||||||
|
|
||||||
|
for (;;) {
|
||||||
|
APP_ERROR_HANDLER(NRF_ERROR_FORBIDDEN);
|
||||||
|
}
|
||||||
|
}
|
74
tools/bin2c.py
Executable file
74
tools/bin2c.py
Executable file
@ -0,0 +1,74 @@
|
|||||||
|
#!/usr/bin/env python
|
||||||
|
#-*- coding: utf-8 -*-
|
||||||
|
"""
|
||||||
|
bin2c
|
||||||
|
~~~~~
|
||||||
|
|
||||||
|
Simple tool for creating C array from a binary file.
|
||||||
|
|
||||||
|
:copyright: (c) 2016 by Dmitry Alimov.
|
||||||
|
:license: The MIT License (MIT), see LICENSE for more details.
|
||||||
|
"""
|
||||||
|
|
||||||
|
import argparse
|
||||||
|
import os
|
||||||
|
import re
|
||||||
|
import sys
|
||||||
|
|
||||||
|
PY3 = sys.version_info[0] == 3
|
||||||
|
|
||||||
|
|
||||||
|
def bin2c(filename, varname='data', linesize=80, indent=4):
|
||||||
|
""" Read binary data from file and return as a C array
|
||||||
|
|
||||||
|
:param filename: a filename of a file to read.
|
||||||
|
:param varname: a C array variable name.
|
||||||
|
:param linesize: a size of a line (min value is 40).
|
||||||
|
:param indent: an indent (number of spaces) that prepend each line.
|
||||||
|
"""
|
||||||
|
if not os.path.isfile(filename):
|
||||||
|
print('File "%s" is not found!' % filename)
|
||||||
|
return ''
|
||||||
|
if not re.match('[a-zA-Z_][a-zA-Z0-9_]*', varname):
|
||||||
|
print('Invalid variable name "%s"' % varname)
|
||||||
|
return
|
||||||
|
with open(filename, 'rb') as in_file:
|
||||||
|
data = in_file.read()
|
||||||
|
# limit the line length
|
||||||
|
if linesize < 40:
|
||||||
|
linesize = 40
|
||||||
|
byte_len = 6 # '0x00, '
|
||||||
|
out = 'const char %s[%d] = {\n' % (varname, len(data))
|
||||||
|
line = ''
|
||||||
|
for byte in data:
|
||||||
|
line += '0x%02x, ' % (byte if PY3 else ord(byte))
|
||||||
|
if len(line) + indent + byte_len >= linesize:
|
||||||
|
out += ' ' * indent + line + '\n'
|
||||||
|
line = ''
|
||||||
|
# add the last line
|
||||||
|
if len(line) + indent + byte_len < linesize:
|
||||||
|
out += ' ' * indent + line + '\n'
|
||||||
|
# strip the last comma
|
||||||
|
out = out.rstrip(', \n') + '\n'
|
||||||
|
out += '};'
|
||||||
|
return out
|
||||||
|
|
||||||
|
|
||||||
|
def main():
|
||||||
|
""" Main func """
|
||||||
|
parser = argparse.ArgumentParser()
|
||||||
|
parser.add_argument(
|
||||||
|
'filename', help='filename to convert to C array')
|
||||||
|
parser.add_argument(
|
||||||
|
'varname', nargs='?', help='variable name', default='data')
|
||||||
|
parser.add_argument(
|
||||||
|
'linesize', nargs='?', help='line length', default=80, type=int)
|
||||||
|
parser.add_argument(
|
||||||
|
'indent', nargs='?', help='indent size', default=4, type=int)
|
||||||
|
args = parser.parse_args()
|
||||||
|
# print out the data
|
||||||
|
print(bin2c(args.filename, args.varname, args.linesize, args.indent))
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == '__main__':
|
||||||
|
main()
|
Loading…
Reference in New Issue
Block a user