Merge remote-tracking branch 'upstream/master' into omega-dev

This commit is contained in:
Quentin Guidée
2019-12-15 14:18:36 +01:00
8 changed files with 125 additions and 44 deletions

View File

@@ -245,7 +245,12 @@ bool AppsContainer::switchTo(App::Snapshot * snapshot) {
}
void AppsContainer::run() {
window()->setFrame(KDRect(0, 0, Ion::Display::Width, Ion::Display::Height));
KDRect screenRect = KDRect(0, 0, Ion::Display::Width, Ion::Display::Height);
window()->setFrame(screenRect);
/* We push a white screen here, because fetching the exam mode takes some time
* and it is visible when reflashing a N0100 (there is some noise on the
* screen before the logo appears). */
Ion::Display::pushRectUniform(screenRect, KDColorWhite);
if (GlobalPreferences::sharedGlobalPreferences()->examMode()) {
activateExamMode();
}

View File

@@ -0,0 +1,32 @@
#ifndef ION_DEVICE_N0100_CONFIG_EXAM_MODE_H
#define ION_DEVICE_N0100_CONFIG_EXAM_MODE_H
namespace Ion {
namespace ExamMode {
namespace Config {
// TODO: factorize the macro with equivalent macro on N110
#define byte4 0xFF, 0xFF, 0xFF, 0xFF
#define byte8 byte4, byte4
#define byte16 byte8, byte8
#define byte32 byte16, byte16
#define byte64 byte32, byte32
#define byte128 byte64, byte64
#define byte256 byte128, byte128
#define byte512 byte256, byte256
#define byte1K byte512, byte512
#define byte2K byte1K, byte1K
#define byte4K byte2K, byte2K
#define byte8K byte4K, byte4K
#define byte16K byte8K, byte8K
#define EXAM_BUFFER_CONTENT byte16K
constexpr static int ExamModeBufferSize = 16*1024;
}
}
}
#endif

View File

@@ -9,16 +9,16 @@
* This will let us use shortcuts such as ">FLASH" to ask for a given section to
* be stored in Flash. */
MEMORY {
FLASH_FIRST_SECTOR (rx) : ORIGIN = 0x08000000, LENGTH = 16K
FLASH_SECOND_SECTOR (rx) : ORIGIN = (0x08000000 + 16K), LENGTH = 16K
FLASH_LAST_SECTORS (rx) : ORIGIN = (0x08000000 + 32K), LENGTH = (1024K - 32K)
FLASH (rx) : ORIGIN = 0x08000000, LENGTH = 1024K
SRAM (rw) : ORIGIN = 0x20000000, LENGTH = 256K
}
STACK_SIZE = 32K;
FLASH_SECOND_SECTOR_OFFSET = 16K;
FLASH_SECOND_SECTOR_SIZE = 16K;
SECTIONS {
.isr_vector_table ORIGIN(FLASH_FIRST_SECTOR) : {
.isr_vector_table ORIGIN(FLASH) : {
/* When booting, the STM32F412 fetches the content of address 0x0, and
* extracts from it various key infos: the initial value of the PC register
* (program counter), the initial value of the stack pointer, and various
@@ -33,37 +33,39 @@ SECTIONS {
* convenient: using function pointers, we can easily point to the service
* routine for each interrupt. */
KEEP(*(.isr_vector_table))
} >FLASH_FIRST_SECTOR
} >FLASH
.header : {
KEEP(*(.header))
} >FLASH_FIRST_SECTOR
ASSERT ((. < ORIGIN(FLASH) + FLASH_SECOND_SECTOR_OFFSET), "Error: ISR table or HEADER overflows in the flash sector reserved for the exam mode");
} >FLASH
.exam_mode_persistence ORIGIN(FLASH_SECOND_SECTOR): {
_exam_mode_persistence_start = .;
.exam_mode_buffer ORIGIN(FLASH) + FLASH_SECOND_SECTOR_OFFSET : {
_exam_mode_buffer_start = .;
KEEP(*(.exam_mode_buffer))
/* Note: We don't increment "." here, we set it. */
. = (ORIGIN(FLASH_SECOND_SECTOR) + LENGTH(FLASH_SECOND_SECTOR));
_exam_mode_persistence_end = .;
} >FLASH_SECOND_SECTOR
. = ORIGIN(FLASH) + FLASH_SECOND_SECTOR_OFFSET + FLASH_SECOND_SECTOR_SIZE;
_exam_mode_buffer_end = .;
} >FLASH
.text : {
. = ALIGN(4);
*(.text)
*(.text.*)
} >FLASH_LAST_SECTORS
} >FLASH
.init_array : {
. = ALIGN(4);
_init_array_start = .;
KEEP (*(.init_array*))
_init_array_end = .;
} >FLASH_LAST_SECTORS
} >FLASH
.rodata : {
. = ALIGN(4);
*(.rodata)
*(.rodata.*)
} >FLASH_LAST_SECTORS
} >FLASH
.data : {
/* The data section is written to Flash but linked as if it were in RAM.
@@ -84,7 +86,7 @@ SECTIONS {
*(.data)
*(.data.*)
_data_section_end_ram = .;
} >SRAM AT> FLASH_LAST_SECTORS
} >SRAM AT> FLASH
.bss : {
/* The bss section contains data for all uninitialized variables

View File

@@ -41,6 +41,7 @@ void privateCleanInvalidateDisableDCache(bool clean, bool invalidate, bool disab
dcisw.setWAY(w);
CORTEX.DCISW()->set(dcisw);
}
__asm volatile("nop");
} while (w-- != 0);
} while (sets-- != 0);

View File

@@ -0,0 +1,30 @@
#ifndef ION_DEVICE_N0110_CONFIG_EXAM_MODE_H
#define ION_DEVICE_N0110_CONFIG_EXAM_MODE_H
namespace Ion {
namespace ExamMode {
namespace Config {
// TODO: factorize the macro with equivalent macro on N100
#define byte4 0xFF, 0xFF, 0xFF, 0xFF
#define byte8 byte4, byte4
#define byte16 byte8, byte8
#define byte32 byte16, byte16
#define byte64 byte32, byte32
#define byte128 byte64, byte64
#define byte256 byte128, byte128
#define byte512 byte256, byte256
#define byte1K byte512, byte512
#define byte2K byte1K, byte1K
#define byte4K byte2K, byte2K
#define EXAM_BUFFER_CONTENT byte4K
constexpr static int ExamModeBufferSize = 4*1024;
}
}
}
#endif

View File

@@ -12,8 +12,7 @@
MEMORY {
INTERNAL_FLASH (rx) : ORIGIN = 0x00200000, LENGTH = 64K
SRAM (rw) : ORIGIN = 0x20000000, LENGTH = 256K
EXTERNAL_FLASH_FIRST_SECTOR (rx) : ORIGIN = 0x90000000, LENGTH = 4K
EXTERNAL_FLASH_NEXT_SECTORS (rx) : ORIGIN = (0x90000000 + 4K), LENGTH = (8M - 4K)
EXTERNAL_FLASH (rx) : ORIGIN = 0x90000000, LENGTH = 8M
/*
ITCM (rwx) : ORIGIN = 0x00000000, LENGTH = 16K
DTCM (rwx) : ORIGIN = 0x20000000, LENGTH = 64K
@@ -23,6 +22,7 @@ MEMORY {
}
STACK_SIZE = 32K;
FIRST_EXTERNAL_FLASH_SECTOR_SIZE = 4K;
SECTIONS {
.isr_vector_table ORIGIN(INTERNAL_FLASH) : {
@@ -56,13 +56,6 @@ SECTIONS {
*(.text._ZL22jump_to_external_flashv)
} >INTERNAL_FLASH
.exam_mode_persistence ORIGIN(EXTERNAL_FLASH_FIRST_SECTOR): {
_exam_mode_persistence_start = .;
/* Note: We don't increment "." here, we set it. */
. = (ORIGIN(EXTERNAL_FLASH_FIRST_SECTOR) + LENGTH(EXTERNAL_FLASH_FIRST_SECTOR));
_exam_mode_persistence_end = .;
} >EXTERNAL_FLASH_FIRST_SECTOR
/* Use boot routine and required dependencies */
/* We're relying on symbols being in their own sub-section. On GCC, this is
* done with -fdata-sections -ffunction-sections */
@@ -123,17 +116,25 @@ SECTIONS {
*(.rodata._ZN3Ion6Device5Board4initEv.str1.4)
} >INTERNAL_FLASH
.exam_mode_buffer ORIGIN(EXTERNAL_FLASH) : {
_exam_mode_buffer_start = .;
KEEP(*(.exam_mode_buffer))
/* Note: We don't increment "." here, we set it. */
. = ORIGIN(EXTERNAL_FLASH) + FIRST_EXTERNAL_FLASH_SECTOR_SIZE;
_exam_mode_buffer_end = .;
} >EXTERNAL_FLASH
/* External flash memory */
.text.external : {
. = ALIGN(4);
*(.text)
*(.text.*)
} >EXTERNAL_FLASH_NEXT_SECTORS
} >EXTERNAL_FLASH
.rodata.external : {
*(.rodata)
*(.rodata.*)
} >EXTERNAL_FLASH_NEXT_SECTORS
} >EXTERNAL_FLASH
.init_array : {
. = ALIGN(4);
@@ -211,7 +212,7 @@ NOCROSSREFS_TO(.rodata.external .isr_vector_table);
NOCROSSREFS_TO(.text.external .header);
NOCROSSREFS_TO(.rodata.external .header);
NOCROSSREFS_TO(.exam_mode_persistence .text.internal);
NOCROSSREFS_TO(.exam_mode_persistence .rodata.internal);
NOCROSSREFS_TO(.exam_mode_persistence .isr_vector_table);
NOCROSSREFS_TO(.exam_mode_persistence .header);
NOCROSSREFS_TO(.exam_mode_buffer .text.internal);
NOCROSSREFS_TO(.exam_mode_buffer .rodata.internal);
NOCROSSREFS_TO(.exam_mode_buffer .isr_vector_table);
NOCROSSREFS_TO(.exam_mode_buffer .header);

View File

@@ -1,4 +1,5 @@
#include <ion/exam_mode.h>
#include <drivers/config/exam_mode.h>
#include "flash.h"
#include <assert.h>
@@ -6,10 +7,15 @@ namespace Ion {
namespace ExamMode {
extern "C" {
extern char _exam_mode_persistence_start;
extern char _exam_mode_persistence_end;
extern char _exam_mode_buffer_start;
extern char _exam_mode_buffer_end;
}
char ones[Config::ExamModeBufferSize]
__attribute__((section(".exam_mode_buffer")))
__attribute__((used))
= {EXAM_BUFFER_CONTENT};
/* The exam mode is written in flash so that it is resilient to resets.
* We erase the dedicated flash sector (all bits written to 1) and, upon
* activating or deactivating the exam mode we write one bit to 0. To determine
@@ -22,16 +28,16 @@ extern "C" {
* sector. */
uint32_t * SignificantExamModeAddress() {
uint32_t * persitence_start = (uint32_t *)&_exam_mode_persistence_start;
uint32_t * persitence_end = (uint32_t *)&_exam_mode_persistence_end;
uint32_t * persitence_start = (uint32_t *)&_exam_mode_buffer_start;
uint32_t * persitence_end = (uint32_t *)&_exam_mode_buffer_end;
while (persitence_start < persitence_end && *persitence_start == 0x0) {
// Skip even number of zero bits
persitence_start++;
}
if (persitence_start == persitence_end) {
assert(Ion::Device::Flash::SectorAtAddress((uint32_t)&_exam_mode_persistence_start) >= 0);
Ion::Device::Flash::EraseSector(Ion::Device::Flash::SectorAtAddress((uint32_t)&_exam_mode_persistence_start));
return (uint32_t *)&_exam_mode_persistence_start;
assert(Ion::Device::Flash::SectorAtAddress((uint32_t)&_exam_mode_buffer_start) >= 0);
Ion::Device::Flash::EraseSector(Ion::Device::Flash::SectorAtAddress((uint32_t)&_exam_mode_buffer_start));
return (uint32_t *)&_exam_mode_buffer_start;
}
return persitence_start;
}

View File

@@ -74,9 +74,15 @@ mp_obj_t modkandinsky_draw_string(size_t n_args, const mp_obj_t * args) {
KDColor backgroundColor = (n_args >= 5) ? ColorForTuple(args[4]) : KDColorWhite;
MicroPython::ExecutionEnvironment::currentExecutionEnvironment()->displaySandbox();
KDIonContext::sharedContext()->drawString(text, point, KDFont::LargeFont, textColor, backgroundColor);
/* drawString function might take some time to execute so we add an extra check
* for user interruption (to avoid freezing in an infinite loop calling
* 'drawString' for instance). */
/* Before and after execution of "modkandinsky_draw_string",
* "micropython_port_vm_hook_loop" is called by "mp_execute_bytecode" and will
* call "micropython_port_interrupt_if_needed" every 20000 calls.
* However, "drawString" function might take some time to execute leading to
* drastically decrease the frequency of calls to
* "micropython_port_vm_hook_loop" and thus to
* "micropython_port_interrupt_if_needed". So we add an extra
* check for user interruption here. This way the user can still interrupt an
* infinite loop calling 'drawString' for instance. */
micropython_port_interrupt_if_needed();
return mp_const_none;
}
@@ -91,9 +97,7 @@ mp_obj_t modkandinsky_fill_rect(size_t n_args, const mp_obj_t * args) {
KDColor color = ColorForTuple(args[4]);
MicroPython::ExecutionEnvironment::currentExecutionEnvironment()->displaySandbox();
KDIonContext::sharedContext()->fillRect(rect, color);
/* fillRect function might take some time to execute so we add an extra check
* for user interruption (to avoid freezing in an infinite loop calling
* 'fillRect' for instance). */
// Cf comment on modkandinsky_draw_string
micropython_port_interrupt_if_needed();
return mp_const_none;
}