mirror of
https://github.com/UpsilonNumworks/Upsilon.git
synced 2026-01-19 00:37:25 +01:00
[ion/device] Sort files
This commit is contained in:
@@ -1,4 +1,4 @@
|
||||
TOOLCHAIN ?= arm-gcc-m4f
|
||||
MODEL ?= n0100
|
||||
USE_LIBA = 1
|
||||
EXE = elf
|
||||
EPSILON_BOOT_PROMPT = update
|
||||
@@ -7,3 +7,5 @@ EPSILON_DEVICE_BENCH ?= 1
|
||||
SFLAGS += -DEPSILON_DEVICE_BENCH=$(EPSILON_DEVICE_BENCH)
|
||||
|
||||
python/port/port.o: CXXFLAGS += -DMP_PORT_USE_STACK_SYMBOLS=1
|
||||
|
||||
include build/platform.device.$(MODEL).mak
|
||||
|
||||
1
build/platform.device.n0100.mak
Normal file
1
build/platform.device.n0100.mak
Normal file
@@ -0,0 +1 @@
|
||||
TOOLCHAIN ?= arm-gcc-m4f
|
||||
@@ -1,6 +1,6 @@
|
||||
include ion/src/device/boot/Makefile
|
||||
include ion/src/device/bench/Makefile
|
||||
include ion/src/device/usb/Makefile
|
||||
# Makefile belows should augment $(ion_device_objs)
|
||||
include ion/src/device/shared/Makefile
|
||||
include ion/src/device/$(MODEL)/Makefile
|
||||
|
||||
ion/src/shared/platform_info.o: SFLAGS += -DHEADER_SECTION="__attribute__((section(\".header\")))"
|
||||
|
||||
@@ -12,27 +12,10 @@ objs += $(addprefix ion/src/shared/, \
|
||||
|
||||
# If you need to profile execution, you can replace events_keyboard with
|
||||
# events_replay.o and dummy/events_modifier.o
|
||||
ION_DEVICE_SFLAGS = -Iion/src/device/$(MODEL) -Iion/src/device/shared
|
||||
|
||||
objs += $(addprefix ion/src/device/, \
|
||||
backlight.o \
|
||||
battery.o\
|
||||
base64.o\
|
||||
console.o \
|
||||
device.o\
|
||||
display.o\
|
||||
events.o\
|
||||
external_flash.o\
|
||||
flash.o\
|
||||
keyboard.o\
|
||||
led.o\
|
||||
power.o\
|
||||
sd_card.o\
|
||||
stack.o\
|
||||
swd.o \
|
||||
timing.o \
|
||||
usb.o \
|
||||
wakeup.o \
|
||||
)
|
||||
$(ion_device_objs): SFLAGS += $(ION_DEVICE_SFLAGS)
|
||||
objs += $(ion_device_objs)
|
||||
|
||||
# When using the register.h C++ file in production mode, we expect the compiler
|
||||
# to completely inline all bit manipulations. For some reason, if we build using
|
||||
|
||||
@@ -1,2 +0,0 @@
|
||||
objs += $(addprefix ion/src/device/boot/, isr.o rt0.o)
|
||||
LDSCRIPT = ion/src/device/boot/flash.ld
|
||||
@@ -1,36 +0,0 @@
|
||||
#ifndef ION_DEVICE_H
|
||||
#define ION_DEVICE_H
|
||||
|
||||
namespace Ion {
|
||||
namespace Device {
|
||||
|
||||
void init();
|
||||
void shutdown();
|
||||
|
||||
void initFPU();
|
||||
#if 0
|
||||
void initMPU();
|
||||
#endif
|
||||
|
||||
void initSysTick();
|
||||
void shutdownSysTick();
|
||||
|
||||
void coreReset();
|
||||
void jumpReset();
|
||||
|
||||
void initPeripherals();
|
||||
void shutdownPeripherals(bool keepLEDAwake = false);
|
||||
void initClocks();
|
||||
void shutdownClocks(bool keepLEDAwake = false);
|
||||
|
||||
/* The serial number is 96 bits long. That's equal to 16 digits in base 64. We
|
||||
* expose a convenient "copySerialNumber" routine which can be called without
|
||||
* using a static variable (and therefore without a .bss section). This is used
|
||||
* in the RAM'ed DFU bootloader. */
|
||||
constexpr static int SerialNumberLength = 16;
|
||||
void copySerialNumber(char * buffer);
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
5
ion/src/device/n0100/Makefile
Normal file
5
ion/src/device/n0100/Makefile
Normal file
@@ -0,0 +1,5 @@
|
||||
ion_device_objs += $(addprefix ion/src/device/n0100/drivers/, \
|
||||
board.o \
|
||||
)
|
||||
|
||||
LDSCRIPT ?= ion/src/device/n0100/flash.ld
|
||||
@@ -1,75 +1,9 @@
|
||||
#include "device.h"
|
||||
#include "regs/regs.h"
|
||||
extern "C" {
|
||||
#include <assert.h>
|
||||
}
|
||||
#include <drivers/board.h>
|
||||
#include <regs/regs.h>
|
||||
#include <ion.h>
|
||||
#include "led.h"
|
||||
#include "display.h"
|
||||
#include "keyboard.h"
|
||||
#include "battery.h"
|
||||
#include "sd_card.h"
|
||||
#include "backlight.h"
|
||||
#include "console.h"
|
||||
#include "swd.h"
|
||||
#include "usb.h"
|
||||
#include "bench/bench.h"
|
||||
#include "base64.h"
|
||||
#include "external_flash.h"
|
||||
|
||||
#define USE_SD_CARD 0
|
||||
|
||||
extern "C" {
|
||||
extern const void * _stack_end;
|
||||
}
|
||||
|
||||
// Public Ion methods
|
||||
|
||||
uint32_t Ion::crc32(const uint32_t * data, size_t length) {
|
||||
bool initialCRCEngineState = RCC.AHB1ENR()->getCRCEN();
|
||||
RCC.AHB1ENR()->setCRCEN(true);
|
||||
CRC.CR()->setRESET(true);
|
||||
|
||||
const uint32_t * end = data + length;
|
||||
while (data < end) {
|
||||
CRC.DR()->set(*data++);
|
||||
}
|
||||
|
||||
uint32_t result = CRC.DR()->get();
|
||||
RCC.AHB1ENR()->setCRCEN(initialCRCEngineState);
|
||||
return result;
|
||||
}
|
||||
|
||||
uint32_t Ion::random() {
|
||||
bool initialRNGEngineState = RCC.AHB2ENR()->getRNGEN();
|
||||
RCC.AHB2ENR()->setRNGEN(true);
|
||||
|
||||
RNG.CR()->setRNGEN(true);
|
||||
|
||||
while (RNG.SR()->getDRDY() == 0) {
|
||||
}
|
||||
uint32_t result = RNG.DR()->get();
|
||||
|
||||
RNG.CR()->setRNGEN(false);
|
||||
RCC.AHB2ENR()->setRNGEN(initialRNGEngineState);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
void Ion::Device::copySerialNumber(char * buffer) {
|
||||
const unsigned char * rawUniqueID = (const unsigned char *)0x1FFF7A10;
|
||||
Base64::encode(rawUniqueID, 12, buffer);
|
||||
buffer[SerialNumberLength] = 0;
|
||||
}
|
||||
|
||||
const char * Ion::serialNumber() {
|
||||
static char serialNumber[Device::SerialNumberLength + 1] = {0};
|
||||
if (serialNumber[0] == 0) {
|
||||
Device::copySerialNumber(serialNumber);
|
||||
}
|
||||
return serialNumber;
|
||||
}
|
||||
|
||||
const char * Ion::fccId() {
|
||||
return "2ALWP-N0100";
|
||||
}
|
||||
@@ -78,65 +12,7 @@ const char * Ion::fccId() {
|
||||
|
||||
namespace Ion {
|
||||
namespace Device {
|
||||
|
||||
void initFPU() {
|
||||
// http://infocenter.arm.com/help/index.jsp?topic=/com.arm.doc.dui0553a/BABDBFBJ.html
|
||||
CM4.CPACR()->setAccess(10, CM4::CPACR::Access::Full);
|
||||
CM4.CPACR()->setAccess(11, CM4::CPACR::Access::Full);
|
||||
// FIXME: The pipeline should be flushed at this point
|
||||
}
|
||||
|
||||
#if 0
|
||||
void initMPU() {
|
||||
/* Region 0 reprensents the last 128 bytes of the stack: accessing this
|
||||
* memory means we are really likely to overflow the stack very soon. */
|
||||
MPU.RNR()->setREGION(0x00);
|
||||
MPU.RBAR()->setADDR(&_stack_end);
|
||||
MPU.RASR()->setSIZE(MPU::RASR::RegionSize::Bytes128);
|
||||
MPU.RASR()->setENABLE(true);
|
||||
MPU.RASR()->setAP(0x000); // Forbid access
|
||||
MPU.CTRL()->setPRIVDEFENA(true);
|
||||
MPU.CTRL()->setENABLE(true);
|
||||
}
|
||||
#endif
|
||||
|
||||
void initSysTick() {
|
||||
// CPU clock is 96 MHz, and systick clock source is divided by 8
|
||||
// To get 1 ms systick overflow we need to reset it to
|
||||
// 96 000 000 (Hz) / 8 / 1 000 (ms/s) - 1 (because the counter resets *after* counting to 0)
|
||||
CM4.SYST_RVR()->setRELOAD(11999);
|
||||
CM4.SYST_CVR()->setCURRENT(0);
|
||||
CM4.SYST_CSR()->setCLKSOURCE(CM4::SYST_CSR::CLKSOURCE::AHB_DIV8);
|
||||
CM4.SYST_CSR()->setTICKINT(true);
|
||||
CM4.SYST_CSR()->setENABLE(true);
|
||||
}
|
||||
|
||||
void shutdownSysTick() {
|
||||
CM4.SYST_CSR()->setENABLE(false);
|
||||
CM4.SYST_CSR()->setTICKINT(false);
|
||||
}
|
||||
|
||||
void coreReset() {
|
||||
// Perform a full core reset
|
||||
CM4.AIRCR()->requestReset();
|
||||
}
|
||||
|
||||
void jumpReset() {
|
||||
uint32_t * stackPointerAddress = reinterpret_cast<uint32_t *>(0x08000000);
|
||||
uint32_t * resetHandlerAddress = reinterpret_cast<uint32_t *>(0x08000004);
|
||||
|
||||
/* Jump to the reset service routine after having reset the stack pointer.
|
||||
* Both addresses are fetched from the base of the Flash memory, just like a
|
||||
* real reset would. These operations should be made at once, otherwise the C
|
||||
* compiler might emit some instructions that modify the stack inbetween. */
|
||||
|
||||
asm volatile (
|
||||
"msr MSP, %[stackPointer] ; bx %[resetHandler]"
|
||||
: :
|
||||
[stackPointer] "r" (*stackPointerAddress),
|
||||
[resetHandler] "r" (*resetHandlerAddress)
|
||||
);
|
||||
}
|
||||
namespace Board {
|
||||
|
||||
void init() {
|
||||
initClocks();
|
||||
@@ -158,7 +34,7 @@ void init() {
|
||||
}
|
||||
|
||||
#if EPSILON_DEVICE_BENCH
|
||||
bool consolePeerConnectedOnBoot = Ion::Console::Device::peerConnected();
|
||||
bool consolePeerConnectedOnBoot = Console::peerConnected();
|
||||
#endif
|
||||
|
||||
initPeripherals();
|
||||
@@ -170,44 +46,6 @@ void init() {
|
||||
#endif
|
||||
}
|
||||
|
||||
void shutdown() {
|
||||
shutdownPeripherals();
|
||||
shutdownClocks();
|
||||
}
|
||||
|
||||
void initPeripherals() {
|
||||
Display::Device::init();
|
||||
Backlight::Device::init();
|
||||
Keyboard::Device::init();
|
||||
LED::Device::init();
|
||||
Battery::Device::init();
|
||||
USB::Device::init();
|
||||
#if USE_SD_CARD
|
||||
SDCard::Device::init();
|
||||
#endif
|
||||
Console::Device::init();
|
||||
SWD::Device::init();
|
||||
initSysTick();
|
||||
ExternalFlash::Device::init();
|
||||
}
|
||||
|
||||
void shutdownPeripherals(bool keepLEDAwake) {
|
||||
shutdownSysTick();
|
||||
SWD::Device::shutdown();
|
||||
Console::Device::shutdown();
|
||||
#if USE_SD_CARD
|
||||
SDCard::Device::shutdown();
|
||||
#endif
|
||||
USB::Device::shutdown();
|
||||
Battery::Device::shutdown();
|
||||
if (!keepLEDAwake) {
|
||||
LED::Device::shutdown();
|
||||
}
|
||||
Keyboard::Device::shutdown();
|
||||
Backlight::Device::shutdown();
|
||||
Display::Device::shutdown();
|
||||
}
|
||||
|
||||
void initClocks() {
|
||||
/* System clock
|
||||
* Configure the CPU at 96 MHz, APB2 and USB at 48 MHz. */
|
||||
@@ -325,3 +163,4 @@ void shutdownClocks(bool keepLEDAwake) {
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,28 +1,23 @@
|
||||
#ifndef ION_DEVICE_BACKLIGHT_H
|
||||
#define ION_DEVICE_BACKLIGHT_H
|
||||
#ifndef ION_DEVICE_N0100_CONFIG_BACKLIGHT_H
|
||||
#define ION_DEVICE_N0100_CONFIG_BACKLIGHT_H
|
||||
|
||||
#include <ion/backlight.h>
|
||||
|
||||
namespace Ion {
|
||||
namespace Backlight {
|
||||
namespace Device {
|
||||
#include <regs/regs.h>
|
||||
|
||||
/* Pin | Role | Mode | Function
|
||||
* -----+-------------------+-----------------------+----------
|
||||
* PC6 | Backlight Enable | Output |
|
||||
*/
|
||||
|
||||
void init();
|
||||
void shutdown();
|
||||
void suspend();
|
||||
void resume();
|
||||
void setLevel(uint8_t level);
|
||||
uint8_t level();
|
||||
namespace Ion {
|
||||
namespace Device {
|
||||
namespace Backlight {
|
||||
namespace Config {
|
||||
|
||||
void sendPulses(int n);
|
||||
constexpr static GPIOPin BacklightPin = GPIOPin(GPIOC, 6);
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -1,11 +1,7 @@
|
||||
#ifndef ION_DEVICE_BATTERY_H
|
||||
#define ION_DEVICE_BATTERY_H
|
||||
#ifndef ION_DEVICE_N0100_CONFIG_BATTERY_H
|
||||
#define ION_DEVICE_N0100_CONFIG_BATTERY_H
|
||||
|
||||
#include "regs/regs.h"
|
||||
|
||||
namespace Ion {
|
||||
namespace Battery {
|
||||
namespace Device {
|
||||
#include <regs/regs.h>
|
||||
|
||||
/* Pin | Role | Mode | Function
|
||||
* -----+-------------------+-----------------------+----------
|
||||
@@ -13,23 +9,20 @@ namespace Device {
|
||||
* PA1 | VBAT_SNS | Analog | ADC1_1
|
||||
*/
|
||||
|
||||
void init();
|
||||
void shutdown();
|
||||
void initGPIO();
|
||||
void initADC();
|
||||
namespace Ion {
|
||||
namespace Device {
|
||||
namespace Battery {
|
||||
namespace Config {
|
||||
|
||||
constexpr GPIO ChargingGPIO = GPIOA;
|
||||
constexpr uint8_t ChargingPin = 0;
|
||||
|
||||
constexpr GPIO ADCGPIO = GPIOA;
|
||||
constexpr uint8_t ADCPin = 1;
|
||||
constexpr static GPIOPin ChargingPin = GPIOPin(GPIOA, 0);
|
||||
constexpr static GPIOPin ADCPin = GPIOPin(GPIOA, 1);
|
||||
constexpr uint8_t ADCChannel = 1;
|
||||
|
||||
constexpr float ADCReferenceVoltage = 2.8f;
|
||||
constexpr float ADCDividerBridgeRatio = 2.0f;
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -1,12 +1,7 @@
|
||||
#ifndef ION_DEVICE_CONSOLE_H
|
||||
#define ION_DEVICE_CONSOLE_H
|
||||
#ifndef ION_DEVICE_N0100_CONFIG_CONSOLE_H
|
||||
#define ION_DEVICE_N0100_CONFIG_CONSOLE_H
|
||||
|
||||
#include <ion/console.h>
|
||||
#include "regs/regs.h"
|
||||
|
||||
namespace Ion {
|
||||
namespace Console {
|
||||
namespace Device {
|
||||
#include <regs/regs.h>
|
||||
|
||||
/* Pin | Role | Mode
|
||||
* -----+-------------------+--------------------
|
||||
@@ -14,11 +9,12 @@ namespace Device {
|
||||
* PD8 | UART3 TX | Alternate Function
|
||||
*/
|
||||
|
||||
void init();
|
||||
void shutdown();
|
||||
bool peerConnected();
|
||||
namespace Ion {
|
||||
namespace Device {
|
||||
namespace Console {
|
||||
namespace Config {
|
||||
|
||||
constexpr USART UARTPort = USART(3);
|
||||
constexpr static USART UARTPort = USART(3);
|
||||
constexpr static GPIOPin RxPin = GPIOPin(GPIOC, 11);
|
||||
constexpr static GPIOPin TxPin = GPIOPin(GPIOD, 8);
|
||||
constexpr static GPIOPin Pins[] = { RxPin, TxPin };
|
||||
@@ -26,5 +22,6 @@ constexpr static GPIOPin Pins[] = { RxPin, TxPin };
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -1,16 +1,7 @@
|
||||
#ifndef ION_DEVICE_DISPLAY_H
|
||||
#define ION_DEVICE_DISPLAY_H
|
||||
#ifndef ION_DEVICE_N0100_CONFIG_DISPLAY_H
|
||||
#define ION_DEVICE_N0100_CONFIG_DISPLAY_H
|
||||
|
||||
#include <kandinsky/rect.h>
|
||||
#include <kandinsky/color.h>
|
||||
extern "C" {
|
||||
#include <stddef.h>
|
||||
}
|
||||
#include "regs/regs.h"
|
||||
|
||||
namespace Ion {
|
||||
namespace Display {
|
||||
namespace Device {
|
||||
#include <regs/regs.h>
|
||||
|
||||
/* Pin | Role | Mode | Function | Note
|
||||
* -----+-------------------+-----------------------+----------|------
|
||||
@@ -38,44 +29,11 @@ namespace Device {
|
||||
* PE15 | LCD D12 | Alternate Function 12 | FSMC_D12 |
|
||||
*/
|
||||
|
||||
void init();
|
||||
void shutdown();
|
||||
|
||||
void initDMA();
|
||||
void initGPIO();
|
||||
void shutdownGPIO();
|
||||
void initFSMC();
|
||||
void shutdownFSMC();
|
||||
void initPanel();
|
||||
void shutdownPanel();
|
||||
|
||||
enum class Orientation {
|
||||
Landscape = 0,
|
||||
Portrait = 1
|
||||
};
|
||||
|
||||
void setDrawingArea(KDRect r, Orientation o);
|
||||
void waitForPendingDMAUploadCompletion();
|
||||
void pushPixels(const KDColor * pixels, size_t numberOfPixels);
|
||||
void pushColor(KDColor color, size_t numberOfPixels);
|
||||
void pullPixels(KDColor * pixels, size_t numberOfPixels);
|
||||
|
||||
enum class Command : uint16_t {
|
||||
Nop = 0x00,
|
||||
Reset = 0x01,
|
||||
SleepIn = 0x10,
|
||||
SleepOut = 0x11,
|
||||
DisplayOff = 0x28,
|
||||
DisplayOn = 0x29,
|
||||
ColumnAddressSet = 0x2A,
|
||||
PageAddressSet = 0x2B,
|
||||
MemoryWrite = 0x2C,
|
||||
MemoryRead = 0x2E,
|
||||
TearingEffectLineOn = 0x35,
|
||||
MemoryAccessControl = 0x36,
|
||||
PixelFormatSet = 0x3A,
|
||||
FrameRateControl = 0xC6
|
||||
};
|
||||
namespace Ion {
|
||||
namespace Device {
|
||||
namespace Display {
|
||||
namespace Config {
|
||||
|
||||
constexpr static GPIOPin FSMCPins[] = {
|
||||
GPIOPin(GPIOA, 2), GPIOPin(GPIOA, 3), GPIOPin(GPIOA, 4), GPIOPin(GPIOB, 12),
|
||||
@@ -91,18 +49,10 @@ constexpr static GPIOPin ResetPin = GPIOPin(GPIOE, 9);
|
||||
constexpr static GPIOPin ExtendedCommandPin = GPIOPin(GPIOB, 13);
|
||||
constexpr static GPIOPin TearingEffectPin = GPIOPin(GPIOB, 10);
|
||||
|
||||
constexpr static int FSMCMemoryBank = 1;
|
||||
constexpr static int FSMCDataCommandAddressBit = 16;
|
||||
|
||||
constexpr static uint32_t FSMCBaseAddress = 0x60000000;
|
||||
constexpr static uint32_t FSMCBankAddress = FSMCBaseAddress + (FSMCMemoryBank-1)*0x04000000;
|
||||
|
||||
constexpr static DMA DMAEngine = DMA2;
|
||||
constexpr static int DMAStream = 0;
|
||||
|
||||
static volatile Command * const CommandAddress = (Command *)(FSMCBankAddress);
|
||||
static volatile uint16_t * const DataAddress = (uint16_t *)(FSMCBankAddress | (1<<(FSMCDataCommandAddressBit+1)));
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
31
ion/src/device/n0100/drivers/config/external_flash.h
Normal file
31
ion/src/device/n0100/drivers/config/external_flash.h
Normal file
@@ -0,0 +1,31 @@
|
||||
#ifndef ION_DEVICE_N0100_CONFIG_EXTERNAL_FLASH_H
|
||||
#define ION_DEVICE_N0100_CONFIG_EXTERNAL_FLASH_H
|
||||
|
||||
#include <regs/regs.h>
|
||||
|
||||
/* Pin | Role | Mode | Function
|
||||
* -----+----------------------+-----------------------+-----------------
|
||||
* PB2 | QUADSPI CLK | Alternate Function 9 | QUADSPI_CLK
|
||||
* PB6 | QUADSPI BK1_NCS | Alternate Function 10 | QUADSPI_BK1_NCS
|
||||
* PC8 | QUADSPI BK1_IO2/WP | Alternate Function 9 | QUADSPI_BK1_IO2
|
||||
* PC9 | QUADSPI BK1_IO0/SO | Alternate Function 9 | QUADSPI_BK1_IO0
|
||||
* PD12 | QUADSPI BK1_IO1/SI | Alternate Function 9 | QUADSPI_BK1_IO1
|
||||
* PD13 | QUADSPI BK1_IO3/HOLD | Alternate Function 9 | QUADSPI_BK1_IO3
|
||||
*/
|
||||
|
||||
namespace Ion {
|
||||
namespace Device {
|
||||
namespace ExternalFlash {
|
||||
namespace Config {
|
||||
|
||||
constexpr static GPIOPin QSPIPins[] = {
|
||||
GPIOPin(GPIOB, 2), GPIOPin(GPIOB, 6), GPIOPin(GPIOC, 9), GPIOPin(GPIOD,12),
|
||||
GPIOPin(GPIOC, 8), GPIOPin(GPIOD,13)
|
||||
};
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -1,13 +1,7 @@
|
||||
#ifndef ION_DEVICE_KEYBOARD_H
|
||||
#define ION_DEVICE_KEYBOARD_H
|
||||
#ifndef ION_DEVICE_N0100_CONFIG_KEYBOARD_H
|
||||
#define ION_DEVICE_N0100_CONFIG_KEYBOARD_H
|
||||
|
||||
#include <ion/keyboard.h>
|
||||
#include <ion.h>
|
||||
#include "regs/regs.h"
|
||||
|
||||
namespace Ion {
|
||||
namespace Keyboard {
|
||||
namespace Device {
|
||||
#include <regs/regs.h>
|
||||
|
||||
/* Pin | Role | Mode
|
||||
* -----+-------------------+--------------------
|
||||
@@ -28,8 +22,10 @@ namespace Device {
|
||||
* PE8 | Keyboard row I | Output, open drain
|
||||
*/
|
||||
|
||||
void init();
|
||||
void shutdown();
|
||||
namespace Ion {
|
||||
namespace Device {
|
||||
namespace Keyboard {
|
||||
namespace Config {
|
||||
|
||||
constexpr GPIO RowGPIO = GPIOE;
|
||||
constexpr uint8_t numberOfRows = 9;
|
||||
@@ -39,30 +35,7 @@ constexpr GPIO ColumnGPIO = GPIOC;
|
||||
constexpr uint8_t numberOfColumns = 6;
|
||||
constexpr uint8_t ColumnPins[numberOfColumns] = {0, 1, 2, 3, 4, 5};
|
||||
|
||||
inline uint8_t rowForKey(Key key) {
|
||||
return (int)key/numberOfColumns;
|
||||
}
|
||||
inline uint8_t columnForKey(Key key) {
|
||||
return (int)key%numberOfColumns;
|
||||
}
|
||||
|
||||
inline void activateRow(uint8_t row) {
|
||||
/* In open-drain mode, a 0 in the register drives the pin low, and a 1 lets
|
||||
* the pin floating (Hi-Z). So we want to set the current row to zero and all
|
||||
* the others to 1. */
|
||||
uint16_t rowState = ~(1<<row);
|
||||
|
||||
// TODO: Assert pin numbers are sequentials and dynamically find 9 and 0
|
||||
Device::RowGPIO.ODR()->setBitRange(9, 0, rowState);
|
||||
|
||||
// TODO: 100 us seems to work, but wasn't really calculated
|
||||
Timing::usleep(100);
|
||||
}
|
||||
|
||||
inline bool columnIsActive(uint8_t column) {
|
||||
return !(Device::ColumnGPIO.IDR()->getBitRange(column,column));
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,11 +1,7 @@
|
||||
#ifndef ION_DEVICE_LED_H
|
||||
#define ION_DEVICE_LED_H
|
||||
#ifndef ION_DEVICE_N0100_CONFIG_LED_H
|
||||
#define ION_DEVICE_N0100_CONFIG_LED_H
|
||||
|
||||
#include "regs/regs.h"
|
||||
|
||||
namespace Ion {
|
||||
namespace LED {
|
||||
namespace Device {
|
||||
#include <regs/regs.h>
|
||||
|
||||
/* Pin | Role | Mode | Function
|
||||
* -----+-------------------+-----------------------+----------
|
||||
@@ -14,33 +10,16 @@ namespace Device {
|
||||
* PC7 | LED red | Alternate Function 2 | TIM3_CH2
|
||||
*/
|
||||
|
||||
enum class Mode {
|
||||
PWM,
|
||||
Blink
|
||||
};
|
||||
|
||||
enum class Color {
|
||||
Red,
|
||||
Green,
|
||||
Blue
|
||||
};
|
||||
|
||||
void init();
|
||||
void shutdown();
|
||||
void setPeriodAndDutyCycles(Mode mode, float dutyCycleRed, float dutyCycleGreen, float dutyCycleBlue, uint16_t period = 0);
|
||||
|
||||
void initGPIO();
|
||||
void shutdownGPIO();
|
||||
void initTimer();
|
||||
void shutdownTimer();
|
||||
namespace Ion {
|
||||
namespace Device {
|
||||
namespace LED {
|
||||
namespace Config {
|
||||
|
||||
constexpr static GPIOPin RGBPins[] = {
|
||||
GPIOPin(GPIOC, 7), GPIOPin(GPIOB, 1), GPIOPin(GPIOB, 0)
|
||||
};
|
||||
|
||||
|
||||
constexpr uint16_t PWMPeriod = 40000;
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,11 +1,7 @@
|
||||
#ifndef ION_DEVICE_SWD_H
|
||||
#define ION_DEVICE_SWD_H
|
||||
#ifndef ION_DEVICE_N0100_CONFIG_SWD_H
|
||||
#define ION_DEVICE_N0100_CONFIG_SWD_H
|
||||
|
||||
#include "regs/regs.h"
|
||||
|
||||
namespace Ion {
|
||||
namespace SWD {
|
||||
namespace Device {
|
||||
#include <regs/regs.h>
|
||||
|
||||
/* Pin | Role | Mode
|
||||
* -----+-------------------+---------------------
|
||||
@@ -14,8 +10,10 @@ namespace Device {
|
||||
* PB3 | SWO | Alternate Function 0
|
||||
*/
|
||||
|
||||
void init();
|
||||
void shutdown();
|
||||
namespace Ion {
|
||||
namespace Device {
|
||||
namespace SWD {
|
||||
namespace Config {
|
||||
|
||||
constexpr static GPIOPin Pins[] = {
|
||||
GPIOPin(GPIOA, 13), GPIOPin(GPIOA, 14), GPIOPin(GPIOB, 3)
|
||||
@@ -24,5 +22,6 @@ constexpr static GPIOPin Pins[] = {
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
24
ion/src/device/n0100/drivers/config/timing.h
Normal file
24
ion/src/device/n0100/drivers/config/timing.h
Normal file
@@ -0,0 +1,24 @@
|
||||
#ifndef ION_DEVICE_N0100_CONFIG_TIMING_H
|
||||
#define ION_DEVICE_N0100_CONFIG_TIMING_H
|
||||
|
||||
#include <regs/regs.h>
|
||||
|
||||
namespace Ion {
|
||||
namespace Device {
|
||||
namespace Timing {
|
||||
namespace Config {
|
||||
|
||||
constexpr static int LoopsPerMillisecond = 8852;
|
||||
constexpr static int LoopsPerMicrosecond = 9;
|
||||
// CPU clock is 96 MHz, and systick clock source is divided by 8
|
||||
// To get 1 ms systick overflow we need to reset it to
|
||||
// 96 000 000 (Hz) / 8 / 1 000 (ms/s) - 1 (because the counter resets *after* counting to 0)
|
||||
constexpr static int SysTickPerMillisecond = 12000;
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
20
ion/src/device/n0100/drivers/config/usb.h
Normal file
20
ion/src/device/n0100/drivers/config/usb.h
Normal file
@@ -0,0 +1,20 @@
|
||||
#ifndef ION_DEVICE_N0100_CONFIG_USB_H
|
||||
#define ION_DEVICE_N0100_CONFIG_USB_H
|
||||
|
||||
#include <regs/regs.h>
|
||||
|
||||
namespace Ion {
|
||||
namespace Device {
|
||||
namespace USB {
|
||||
namespace Config {
|
||||
|
||||
constexpr static GPIOPin VbusPin = GPIOPin(GPIOA, 9);
|
||||
constexpr static GPIOPin DmPin = GPIOPin(GPIOA, 11);
|
||||
constexpr static GPIOPin DpPin = GPIOPin(GPIOA, 12);
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -1,95 +0,0 @@
|
||||
#include "sd_card.h"
|
||||
#include "regs/regs.h"
|
||||
extern "C" {
|
||||
#include <assert.h>
|
||||
}
|
||||
|
||||
namespace Ion {
|
||||
namespace SDCard {
|
||||
namespace Device {
|
||||
|
||||
void init() {
|
||||
initGPIO();
|
||||
initCard();
|
||||
}
|
||||
|
||||
void initGPIO() {
|
||||
// Configure GPIOs to use AF
|
||||
GPIOA.MODER()->setMode(8, GPIO::MODER::Mode::AlternateFunction);
|
||||
GPIOB.MODER()->setMode(4, GPIO::MODER::Mode::AlternateFunction);
|
||||
GPIOB.MODER()->setMode(5, GPIO::MODER::Mode::AlternateFunction);
|
||||
GPIOB.MODER()->setMode(15, GPIO::MODER::Mode::AlternateFunction);
|
||||
GPIOC.MODER()->setMode(10, GPIO::MODER::Mode::AlternateFunction);
|
||||
GPIOD.MODER()->setMode(2, GPIO::MODER::Mode::AlternateFunction);
|
||||
|
||||
// More precisely, AF12 which correspond to SDIO alternate functions
|
||||
GPIOA.AFR()->setAlternateFunction(8, GPIO::AFR::AlternateFunction::AF12);
|
||||
GPIOB.AFR()->setAlternateFunction(4, GPIO::AFR::AlternateFunction::AF12);
|
||||
GPIOB.AFR()->setAlternateFunction(5, GPIO::AFR::AlternateFunction::AF12);
|
||||
GPIOB.AFR()->setAlternateFunction(15, GPIO::AFR::AlternateFunction::AF12);
|
||||
GPIOC.AFR()->setAlternateFunction(10, GPIO::AFR::AlternateFunction::AF12);
|
||||
GPIOD.AFR()->setAlternateFunction(2, GPIO::AFR::AlternateFunction::AF12);
|
||||
}
|
||||
|
||||
void initCard() {
|
||||
|
||||
// Power on
|
||||
SDIO.POWER()->setPWRCTRL(SDIO::POWER::PWRCTRL::On);
|
||||
while (SDIO.POWER()->getPWRCTRL() != SDIO::POWER::PWRCTRL::On) {
|
||||
}
|
||||
|
||||
// Clock set
|
||||
SDIO.CLKCR()->setCLKDIV(254);
|
||||
SDIO.CLKCR()->setCLKEN(true);
|
||||
|
||||
sendCommand(0, 0);
|
||||
// CMD8 : 0b0001 = 2.7 - 3.6V
|
||||
// 0xB7 = Pattern to see back in response
|
||||
sendCommand(8, 0x1B7);
|
||||
|
||||
assert(SDIO.RESP(1)->get() == 0x1B7);
|
||||
}
|
||||
|
||||
void sendCommand(uint32_t cmd, uint32_t arg) {
|
||||
class SDIO::ICR icr(0);
|
||||
icr.setCCRCFAILC(true);
|
||||
icr.setCTIMEOUTC(true);
|
||||
icr.setCMDRENDC(true);
|
||||
icr.setCMDSENTC(true);
|
||||
SDIO.ICR()->set(icr);
|
||||
|
||||
SDIO.ARG()->set(arg);
|
||||
|
||||
SDIO::CMD::WAITRESP responseType = SDIO::CMD::WAITRESP::Short;
|
||||
switch (cmd) {
|
||||
case 0:
|
||||
responseType = SDIO::CMD::WAITRESP::None;
|
||||
break;
|
||||
case 2:
|
||||
case 9:
|
||||
case 10:
|
||||
responseType = SDIO::CMD::WAITRESP::Long;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
class SDIO::CMD command(0);
|
||||
command.setCMDINDEX(cmd);
|
||||
command.setCPSMEN(true);
|
||||
command.setWAITRESP(responseType);
|
||||
SDIO.CMD()->set(command);
|
||||
|
||||
if (responseType == SDIO::CMD::WAITRESP::None) {
|
||||
// Wait for timeout or command sent
|
||||
while (!SDIO.STA()->getCTIMEOUT() && !SDIO.STA()->getCMDSENT()) {
|
||||
}
|
||||
} else {
|
||||
while (!SDIO.STA()->getCTIMEOUT() && !SDIO.STA()->getCMDREND() && !SDIO.STA()->getCCRCFAIL()) {
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,33 +0,0 @@
|
||||
#ifndef ION_DEVICE_SD_CARD_H
|
||||
#define ION_DEVICE_SD_CARD_H
|
||||
|
||||
extern "C" {
|
||||
#include <stdint.h>
|
||||
}
|
||||
|
||||
namespace Ion {
|
||||
namespace SDCard {
|
||||
namespace Device {
|
||||
|
||||
/* Pin | Role | Mode | Function
|
||||
* -----+-------------------+-----------------------+----------
|
||||
* PA8 | SDIO D1 | Alternate Function 12 | SDIO_D1
|
||||
* PB4 | SDIO D0 | Alternate Function 12 | SDIO_D0
|
||||
* PB5 | SDIO D3 | Alternate Function 12 | SDIO_D3
|
||||
* PB15 | SDIO CLK | Alternate Function 12 | SDIO_CK
|
||||
* PC10 | SDIO D2 | Alternate Function 12 | SDIO_D2
|
||||
* PD2 | SDIO CMD | Alternate Function 12 | SDIO_CMD
|
||||
*/
|
||||
|
||||
void init();
|
||||
void initGPIO();
|
||||
|
||||
void initCard();
|
||||
|
||||
void sendCommand(uint32_t cmd, uint32_t arg);
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
3
ion/src/device/shared/Makefile
Normal file
3
ion/src/device/shared/Makefile
Normal file
@@ -0,0 +1,3 @@
|
||||
include ion/src/device/shared/boot/Makefile
|
||||
include ion/src/device/shared/usb/Makefile
|
||||
include ion/src/device/shared/drivers/Makefile
|
||||
4
ion/src/device/shared/boot/Makefile
Normal file
4
ion/src/device/shared/boot/Makefile
Normal file
@@ -0,0 +1,4 @@
|
||||
objs += $(addprefix ion/src/device/shared/boot/, \
|
||||
isr.o \
|
||||
rt0.o \
|
||||
)
|
||||
@@ -2,9 +2,9 @@
|
||||
#include <stdint.h>
|
||||
#include <string.h>
|
||||
#include <ion.h>
|
||||
#include "../device.h"
|
||||
#include "../timing.h"
|
||||
#include "../console.h"
|
||||
#include "../drivers/board.h"
|
||||
#include "../drivers/reset.h"
|
||||
#include "../drivers/timing.h"
|
||||
|
||||
typedef void (*cxx_constructor)();
|
||||
|
||||
@@ -23,7 +23,7 @@ void abort() {
|
||||
while (1) {
|
||||
}
|
||||
#else
|
||||
Ion::Device::coreReset();
|
||||
Ion::Device::Reset::core();
|
||||
#endif
|
||||
}
|
||||
|
||||
@@ -59,7 +59,8 @@ void start() {
|
||||
|
||||
/* Initialize the FPU as early as possible.
|
||||
* For example, static C++ objects are very likely to manipulate float values */
|
||||
Ion::Device::initFPU();
|
||||
// FIXME//TODO//Ion::Device::initFPU();
|
||||
#warning BOO
|
||||
|
||||
#if 0
|
||||
Ion::Device::initMPU();
|
||||
@@ -85,7 +86,7 @@ void start() {
|
||||
}
|
||||
#endif
|
||||
|
||||
Ion::Device::init();
|
||||
Ion::Device::Board::init();
|
||||
|
||||
non_inlined_ion_main();
|
||||
|
||||
@@ -93,5 +94,7 @@ void start() {
|
||||
}
|
||||
|
||||
void __attribute__((interrupt)) isr_systick() {
|
||||
Ion::Timing::Device::MillisElapsed++;
|
||||
#warning BOO
|
||||
// FIXME: TODO//
|
||||
//Ion::Timing::Device::MillisElapsed++;
|
||||
}
|
||||
22
ion/src/device/shared/drivers/Makefile
Normal file
22
ion/src/device/shared/drivers/Makefile
Normal file
@@ -0,0 +1,22 @@
|
||||
ion_device_objs += $(addprefix ion/src/device/shared/drivers/, \
|
||||
backlight.o \
|
||||
battery.o \
|
||||
base64.o \
|
||||
board.o \
|
||||
console.o \
|
||||
crc32.o \
|
||||
display.o \
|
||||
events.o \
|
||||
external_flash.o \
|
||||
flash.o \
|
||||
keyboard.o \
|
||||
led.o \
|
||||
power.o\
|
||||
random.o\
|
||||
reset.o \
|
||||
serial_number.o \
|
||||
swd.o \
|
||||
timing.o \
|
||||
usb.o \
|
||||
wakeup.o \
|
||||
)
|
||||
@@ -1,6 +1,7 @@
|
||||
#include <ion.h>
|
||||
#include "regs/regs.h"
|
||||
#include "backlight.h"
|
||||
#include <ion/backlight.h>
|
||||
#include <ion/timing.h>
|
||||
#include <drivers/config/backlight.h>
|
||||
|
||||
/* This driver controls the RT9365 LED driver.
|
||||
* This chip allows the brightness to be set to 16 different values. It starts
|
||||
@@ -13,12 +14,14 @@
|
||||
namespace Ion {
|
||||
namespace Backlight {
|
||||
|
||||
using namespace Ion::Device::Backlight;
|
||||
|
||||
void setBrightness(uint8_t b) {
|
||||
Device::setLevel(b >> 4);
|
||||
setLevel(b >> 4);
|
||||
}
|
||||
|
||||
uint8_t brightness() {
|
||||
return Device::level() << 4;
|
||||
return level() << 4;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -27,29 +30,29 @@ uint8_t brightness() {
|
||||
// Private Ion::Backlight::Device methods
|
||||
|
||||
namespace Ion {
|
||||
namespace Backlight {
|
||||
namespace Device {
|
||||
namespace Backlight {
|
||||
|
||||
static uint8_t sLevel;
|
||||
|
||||
void init() {
|
||||
GPIOC.MODER()->setMode(6, GPIO::MODER::Mode::Output);
|
||||
Config::BacklightPin.group().MODER()->setMode(Config::BacklightPin.pin(), GPIO::MODER::Mode::Output);
|
||||
sLevel = 0xF;
|
||||
resume();
|
||||
}
|
||||
|
||||
void shutdown() {
|
||||
GPIOC.MODER()->setMode(6, GPIO::MODER::Mode::Analog);
|
||||
GPIOC.PUPDR()->setPull(6, GPIO::PUPDR::Pull::None);
|
||||
Config::BacklightPin.group().MODER()->setMode(Config::BacklightPin.pin(), GPIO::MODER::Mode::Analog);
|
||||
Config::BacklightPin.group().PUPDR()->setPull(Config::BacklightPin.pin(), GPIO::PUPDR::Pull::None);
|
||||
}
|
||||
|
||||
void suspend() {
|
||||
GPIOC.ODR()->set(6, false);
|
||||
Config::BacklightPin.group().ODR()->set(Config::BacklightPin.pin(), false);
|
||||
Timing::msleep(3); // Might not need to be blocking
|
||||
}
|
||||
|
||||
void resume() {
|
||||
GPIOC.ODR()->set(6, true);
|
||||
Config::BacklightPin.group().ODR()->set(Config::BacklightPin.pin(), true);
|
||||
Timing::usleep(50);
|
||||
uint8_t level = sLevel;
|
||||
sLevel = 0xF;
|
||||
@@ -73,9 +76,9 @@ uint8_t level() {
|
||||
|
||||
void sendPulses(int n) {
|
||||
for (int i=0; i<n; i++) {
|
||||
GPIOC.ODR()->set(6, false);
|
||||
Config::BacklightPin.group().ODR()->set(Config::BacklightPin.pin(), false);
|
||||
Timing::usleep(20);
|
||||
GPIOC.ODR()->set(6, true);
|
||||
Config::BacklightPin.group().ODR()->set(Config::BacklightPin.pin(), true);
|
||||
Timing::usleep(20);
|
||||
}
|
||||
}
|
||||
24
ion/src/device/shared/drivers/backlight.h
Normal file
24
ion/src/device/shared/drivers/backlight.h
Normal file
@@ -0,0 +1,24 @@
|
||||
#ifndef ION_DEVICE_SHARED_BACKLIGHT_H
|
||||
#define ION_DEVICE_SHARED_BACKLIGHT_H
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
namespace Ion {
|
||||
namespace Device {
|
||||
namespace Backlight {
|
||||
|
||||
void init();
|
||||
void shutdown();
|
||||
void suspend();
|
||||
void resume();
|
||||
|
||||
uint8_t level();
|
||||
void setLevel(uint8_t level);
|
||||
|
||||
void sendPulses(int n);
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -1,6 +1,6 @@
|
||||
#include <ion/battery.h>
|
||||
#include "battery.h"
|
||||
#include "regs/regs.h"
|
||||
#include <ion/battery.h>
|
||||
#include <drivers/config/battery.h>
|
||||
|
||||
/* To measure the battery voltage, we're using the internal ADC. The ADC works
|
||||
* by comparing the input voltage to a reference voltage. The only fixed voltage
|
||||
@@ -10,11 +10,14 @@
|
||||
* To avoid draining the battery, we're using an high-impedence voltage divider,
|
||||
* so we need to be careful when sampling the ADC. See AN2834 for more info. */
|
||||
|
||||
|
||||
namespace Ion {
|
||||
namespace Battery {
|
||||
|
||||
using namespace Ion::Device::Battery;
|
||||
|
||||
bool isCharging() {
|
||||
return !Device::ChargingGPIO.IDR()->get(Device::ChargingPin);
|
||||
return !Config::ChargingPin.group().IDR()->get(Config::ChargingPin.pin());
|
||||
}
|
||||
|
||||
Charge level() {
|
||||
@@ -37,22 +40,22 @@ float voltage() {
|
||||
uint16_t value = ADC.DR()->get();
|
||||
|
||||
// The ADC is 12 bits by default
|
||||
return Device::ADCDividerBridgeRatio*(Device::ADCReferenceVoltage * value)/0xFFF;
|
||||
return Config::ADCDividerBridgeRatio*(Config::ADCReferenceVoltage * value)/0xFFF;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
namespace Ion {
|
||||
namespace Battery {
|
||||
namespace Device {
|
||||
namespace Battery {
|
||||
|
||||
void init() {
|
||||
initGPIO();
|
||||
|
||||
/* The BAT_SNS pin is connected to Vbat through a divider bridge. It therefore
|
||||
* has a voltage of Vbat/2. We'll measure this using ADC channel 0. */
|
||||
ADCGPIO.MODER()->setMode(ADCPin, GPIO::MODER::Mode::Analog);
|
||||
Config::ADCPin.group().MODER()->setMode(Config::ADCPin.pin(), GPIO::MODER::Mode::Analog);
|
||||
|
||||
// Step 2 - Enable the ADC
|
||||
RCC.APB2ENR()->setADC1EN(true);
|
||||
@@ -60,8 +63,8 @@ void init() {
|
||||
|
||||
// Configure the ADC channel
|
||||
ADC.SQR1()->setL(0); // Always sample the same channel
|
||||
ADC.SQR3()->setSQ1(ADCChannel);
|
||||
ADC.SMPR()->setSamplingTime(ADCChannel, ADC::SMPR::SamplingTime::Cycles480); // Use the max sampling time
|
||||
ADC.SQR3()->setSQ1(Config::ADCChannel);
|
||||
ADC.SMPR()->setSamplingTime(Config::ADCChannel, ADC::SMPR::SamplingTime::Cycles480); // Use the max sampling time
|
||||
}
|
||||
|
||||
void initGPIO() {
|
||||
@@ -70,13 +73,13 @@ void initGPIO() {
|
||||
* open-drain output. Open-drain output are either connected to ground or left
|
||||
* floating. To interact with such an output, our input must therefore be
|
||||
* pulled up. */
|
||||
ChargingGPIO.MODER()->setMode(ChargingPin, GPIO::MODER::Mode::Input);
|
||||
ChargingGPIO.PUPDR()->setPull(ChargingPin, GPIO::PUPDR::Pull::Up);
|
||||
Config::ChargingPin.group().MODER()->setMode(Config::ChargingPin.pin(), GPIO::MODER::Mode::Input);
|
||||
Config::ChargingPin.group().PUPDR()->setPull(Config::ChargingPin.pin(), GPIO::PUPDR::Pull::Up);
|
||||
}
|
||||
|
||||
void shutdown() {
|
||||
ChargingGPIO.MODER()->setMode(ChargingPin, GPIO::MODER::Mode::Analog);
|
||||
ChargingGPIO.PUPDR()->setPull(ChargingPin, GPIO::PUPDR::Pull::None);
|
||||
Config::ChargingPin.group().MODER()->setMode(Config::ChargingPin.pin(), GPIO::MODER::Mode::Analog);
|
||||
Config::ChargingPin.group().PUPDR()->setPull(Config::ChargingPin.pin(), GPIO::PUPDR::Pull::None);
|
||||
|
||||
// Disable the ADC
|
||||
ADC.CR2()->setADON(false);
|
||||
17
ion/src/device/shared/drivers/battery.h
Normal file
17
ion/src/device/shared/drivers/battery.h
Normal file
@@ -0,0 +1,17 @@
|
||||
#ifndef ION_DEVICE_SHARED_BATTERY_H
|
||||
#define ION_DEVICE_SHARED_BATTERY_H
|
||||
|
||||
namespace Ion {
|
||||
namespace Device {
|
||||
namespace Battery {
|
||||
|
||||
void init();
|
||||
void shutdown();
|
||||
void initGPIO();
|
||||
void initADC();
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
59
ion/src/device/shared/drivers/board.cpp
Normal file
59
ion/src/device/shared/drivers/board.cpp
Normal file
@@ -0,0 +1,59 @@
|
||||
#include "board.h"
|
||||
#include <drivers/board.h>
|
||||
#include <drivers/backlight.h>
|
||||
#include <drivers/battery.h>
|
||||
#include <drivers/console.h>
|
||||
#include <drivers/display.h>
|
||||
#include <drivers/external_flash.h>
|
||||
#include <drivers/keyboard.h>
|
||||
#include <drivers/led.h>
|
||||
#include <drivers/swd.h>
|
||||
#include <drivers/timing.h>
|
||||
#include <drivers/usb.h>
|
||||
|
||||
namespace Ion {
|
||||
namespace Device {
|
||||
namespace Board {
|
||||
|
||||
void shutdown() {
|
||||
shutdownPeripherals();
|
||||
shutdownClocks();
|
||||
}
|
||||
|
||||
void initFPU() {
|
||||
// http://infocenter.arm.com/help/index.jsp?topic=/com.arm.doc.dui0553a/BABDBFBJ.html
|
||||
CM4.CPACR()->setAccess(10, CM4::CPACR::Access::Full);
|
||||
CM4.CPACR()->setAccess(11, CM4::CPACR::Access::Full);
|
||||
// FIXME: The pipeline should be flushed at this point
|
||||
}
|
||||
|
||||
void initPeripherals() {
|
||||
Display::init();
|
||||
Backlight::init();
|
||||
Keyboard::init();
|
||||
LED::init();
|
||||
Battery::init();
|
||||
USB::init();
|
||||
Console::init();
|
||||
SWD::init();
|
||||
Timing::init();
|
||||
ExternalFlash::init();
|
||||
}
|
||||
|
||||
void shutdownPeripherals(bool keepLEDAwake) {
|
||||
Timing::shutdown();
|
||||
SWD::shutdown();
|
||||
Console::shutdown();
|
||||
USB::shutdown();
|
||||
Battery::shutdown();
|
||||
if (!keepLEDAwake) {
|
||||
LED::shutdown();
|
||||
}
|
||||
Keyboard::shutdown();
|
||||
Backlight::shutdown();
|
||||
Display::shutdown();
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
21
ion/src/device/shared/drivers/board.h
Normal file
21
ion/src/device/shared/drivers/board.h
Normal file
@@ -0,0 +1,21 @@
|
||||
#ifndef ION_DEVICE_SHARED_DRIVERS_BOARD_H
|
||||
#define ION_DEVICE_SHARED_DRIVERS_BOARD_H
|
||||
|
||||
namespace Ion {
|
||||
namespace Device {
|
||||
namespace Board {
|
||||
|
||||
void init();
|
||||
void shutdown();
|
||||
|
||||
void initClocks();
|
||||
void shutdownClocks(bool keepLEDAwake = false);
|
||||
|
||||
void initPeripherals();
|
||||
void shutdownPeripherals(bool keepLEDAwake = false);
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -1,5 +1,7 @@
|
||||
#include <ion.h>
|
||||
#include "console.h"
|
||||
#include <ion/console.h>
|
||||
#include <ion/timing.h>
|
||||
#include <drivers/config/console.h>
|
||||
|
||||
/* This file implements a serial console.
|
||||
* We use a 115200 8N1 serial port */
|
||||
@@ -7,36 +9,38 @@
|
||||
namespace Ion {
|
||||
namespace Console {
|
||||
|
||||
using namespace Ion::Device::Console;
|
||||
|
||||
char readChar() {
|
||||
while (Device::UARTPort.SR()->getRXNE() == 0) {
|
||||
while (Config::UARTPort.SR()->getRXNE() == 0) {
|
||||
}
|
||||
return (char)Device::UARTPort.DR()->get();
|
||||
return (char)Config::UARTPort.DR()->get();
|
||||
}
|
||||
|
||||
void writeChar(char c) {
|
||||
while (Device::UARTPort.SR()->getTXE() == 0) {
|
||||
while (Config::UARTPort.SR()->getTXE() == 0) {
|
||||
}
|
||||
Device::UARTPort.DR()->set(c);
|
||||
Config::UARTPort.DR()->set(c);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
namespace Ion {
|
||||
namespace Console {
|
||||
namespace Device {
|
||||
namespace Console {
|
||||
|
||||
void init() {
|
||||
RCC.APB1ENR()->setUSART3EN(true);
|
||||
|
||||
for(const GPIOPin & g : Pins) {
|
||||
for(const GPIOPin & g : Config::Pins) {
|
||||
g.group().MODER()->setMode(g.pin(), GPIO::MODER::Mode::AlternateFunction);
|
||||
g.group().AFR()->setAlternateFunction(g.pin(), GPIO::AFR::AlternateFunction::AF7);
|
||||
}
|
||||
|
||||
UARTPort.CR1()->setUE(true);
|
||||
UARTPort.CR1()->setTE(true);
|
||||
UARTPort.CR1()->setRE(true);
|
||||
Config::UARTPort.CR1()->setUE(true);
|
||||
Config::UARTPort.CR1()->setTE(true);
|
||||
Config::UARTPort.CR1()->setRE(true);
|
||||
|
||||
/* We need to set the baud rate of the UART port.
|
||||
* This is set relative to the APB1 clock, which runs at 48 MHz.
|
||||
@@ -49,28 +53,27 @@ void init() {
|
||||
* DIV_MANTISSA = 26
|
||||
* DIV_FRAC = 16*0.0416667 = 1
|
||||
*/
|
||||
UARTPort.BRR()->setDIV_MANTISSA(26);
|
||||
UARTPort.BRR()->setDIV_FRAC(1);
|
||||
Config::UARTPort.BRR()->setDIV_MANTISSA(26);
|
||||
Config::UARTPort.BRR()->setDIV_FRAC(1);
|
||||
}
|
||||
|
||||
void shutdown() {
|
||||
for(const GPIOPin & g : Pins) {
|
||||
for(const GPIOPin & g : Config::Pins) {
|
||||
g.group().MODER()->setMode(g.pin(), GPIO::MODER::Mode::Analog);
|
||||
g.group().PUPDR()->setPull(g.pin(), GPIO::PUPDR::Pull::None);
|
||||
}
|
||||
}
|
||||
|
||||
bool peerConnected() {
|
||||
RxPin.group().PUPDR()->setPull(RxPin.pin(), GPIO::PUPDR::Pull::Down);
|
||||
RxPin.group().MODER()->setMode(RxPin.pin(), GPIO::MODER::Mode::Input);
|
||||
Config::RxPin.group().PUPDR()->setPull(Config::RxPin.pin(), GPIO::PUPDR::Pull::Down);
|
||||
Config::RxPin.group().MODER()->setMode(Config::RxPin.pin(), GPIO::MODER::Mode::Input);
|
||||
Timing::msleep(1);
|
||||
bool result = RxPin.group().IDR()->get(RxPin.pin());
|
||||
RxPin.group().PUPDR()->setPull(RxPin.pin(), GPIO::PUPDR::Pull::None);
|
||||
RxPin.group().MODER()->setMode(RxPin.pin(), GPIO::MODER::Mode::AlternateFunction);
|
||||
bool result = Config::RxPin.group().IDR()->get(Config::RxPin.pin());
|
||||
Config::RxPin.group().PUPDR()->setPull(Config::RxPin.pin(), GPIO::PUPDR::Pull::None);
|
||||
Config::RxPin.group().MODER()->setMode(Config::RxPin.pin(), GPIO::MODER::Mode::AlternateFunction);
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
16
ion/src/device/shared/drivers/console.h
Normal file
16
ion/src/device/shared/drivers/console.h
Normal file
@@ -0,0 +1,16 @@
|
||||
#ifndef ION_DEVICE_SHARED_CONSOLE_H
|
||||
#define ION_DEVICE_SHARED_CONSOLE_H
|
||||
|
||||
namespace Ion {
|
||||
namespace Device {
|
||||
namespace Console {
|
||||
|
||||
void init();
|
||||
void shutdown();
|
||||
bool peerConnected();
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
17
ion/src/device/shared/drivers/crc32.cpp
Normal file
17
ion/src/device/shared/drivers/crc32.cpp
Normal file
@@ -0,0 +1,17 @@
|
||||
#include <ion.h>
|
||||
#include <regs/regs.h>
|
||||
|
||||
uint32_t Ion::crc32(const uint32_t * data, size_t length) {
|
||||
bool initialCRCEngineState = RCC.AHB1ENR()->getCRCEN();
|
||||
RCC.AHB1ENR()->setCRCEN(true);
|
||||
CRC.CR()->setRESET(true);
|
||||
|
||||
const uint32_t * end = data + length;
|
||||
while (data < end) {
|
||||
CRC.DR()->set(*data++);
|
||||
}
|
||||
|
||||
uint32_t result = CRC.DR()->get();
|
||||
RCC.AHB1ENR()->setCRCEN(initialCRCEngineState);
|
||||
return result;
|
||||
}
|
||||
@@ -1,9 +1,8 @@
|
||||
#include <ion.h>
|
||||
#include "display.h"
|
||||
#include "regs/regs.h"
|
||||
extern "C" {
|
||||
#include <ion/display.h>
|
||||
#include <ion/timing.h>
|
||||
#include <drivers/config/display.h>
|
||||
#include <assert.h>
|
||||
}
|
||||
|
||||
/* This driver interfaces with the ST7789V LCD controller.
|
||||
* This chip keeps a whole frame in SRAM memory and feeds it to the LCD panel as
|
||||
@@ -16,42 +15,42 @@ extern "C" {
|
||||
|
||||
#define USE_DMA (USE_DMA_FOR_PUSH_PIXELS|USE_DMA_FOR_PUSH_COLOR)
|
||||
|
||||
// Public Ion::Display methods
|
||||
|
||||
namespace Ion {
|
||||
namespace Display {
|
||||
|
||||
using namespace Ion::Device::Display;
|
||||
|
||||
void pushRect(KDRect r, const KDColor * pixels) {
|
||||
#if USE_DMA
|
||||
Device::waitForPendingDMAUploadCompletion();
|
||||
waitForPendingDMAUploadCompletion();
|
||||
#endif
|
||||
Device::setDrawingArea(r, Device::Orientation::Landscape);
|
||||
Device::pushPixels(pixels, r.width()*r.height());
|
||||
setDrawingArea(r, Orientation::Landscape);
|
||||
pushPixels(pixels, r.width()*r.height());
|
||||
}
|
||||
|
||||
void pushRectUniform(KDRect r, KDColor c) {
|
||||
#if USE_DMA
|
||||
Device::waitForPendingDMAUploadCompletion();
|
||||
waitForPendingDMAUploadCompletion();
|
||||
#endif
|
||||
Device::setDrawingArea(r, Device::Orientation::Portrait);
|
||||
Device::pushColor(c, r.width()*r.height());
|
||||
setDrawingArea(r, Orientation::Portrait);
|
||||
pushColor(c, r.width()*r.height());
|
||||
}
|
||||
|
||||
void pullRect(KDRect r, KDColor * pixels) {
|
||||
#if USE_DMA
|
||||
Device::waitForPendingDMAUploadCompletion();
|
||||
waitForPendingDMAUploadCompletion();
|
||||
#endif
|
||||
Device::setDrawingArea(r, Device::Orientation::Landscape);
|
||||
Device::pullPixels(pixels, r.width()*r.height());
|
||||
setDrawingArea(r, Orientation::Landscape);
|
||||
pullPixels(pixels, r.width()*r.height());
|
||||
}
|
||||
|
||||
void waitForVBlank() {
|
||||
// We want to return as soon as the TE line is transitionning from "DOWN" to "UP"
|
||||
while (Device::TearingEffectPin.group().IDR()->get(Device::TearingEffectPin.pin())) {
|
||||
while (Config::TearingEffectPin.group().IDR()->get(Config::TearingEffectPin.pin())) {
|
||||
// Loop while high, exit when low
|
||||
// Wait for zero
|
||||
}
|
||||
while (!Device::TearingEffectPin.group().IDR()->get(Device::TearingEffectPin.pin())) {
|
||||
while (!Config::TearingEffectPin.group().IDR()->get(Config::TearingEffectPin.pin())) {
|
||||
// Loop while low, exit when high
|
||||
}
|
||||
}
|
||||
@@ -59,11 +58,9 @@ void waitForVBlank() {
|
||||
}
|
||||
}
|
||||
|
||||
// Private Ion::Display::Device methods
|
||||
|
||||
namespace Ion {
|
||||
namespace Display {
|
||||
namespace Device {
|
||||
namespace Display {
|
||||
|
||||
static inline void send_data(uint16_t d) {
|
||||
*DataAddress = d;
|
||||
@@ -107,82 +104,81 @@ void shutdown() {
|
||||
#if USE_DMA
|
||||
void initDMA() {
|
||||
// Only DMA2 can perform memory-to-memory transfers
|
||||
//assert(DMAEngine == DMA2);
|
||||
//assert(Config::DMAEngine == DMA2);
|
||||
|
||||
/* In memory-to-memory transfers, the "peripheral" is the source and the
|
||||
* "memory" is the destination. In other words, memory is copied from address
|
||||
* DMA_SxPAR to address DMA_SxM0AR. */
|
||||
|
||||
DMAEngine.SCR(DMAStream)->setDIR(DMA::SCR::Direction::MemoryToMemory);
|
||||
DMAEngine.SM0AR(DMAStream)->set((uint32_t)DataAddress);
|
||||
DMAEngine.SCR(DMAStream)->setMSIZE(DMA::SCR::DataSize::HalfWord);
|
||||
DMAEngine.SCR(DMAStream)->setPSIZE(DMA::SCR::DataSize::HalfWord);
|
||||
DMAEngine.SCR(DMAStream)->setMBURST(DMA::SCR::Burst::Incremental4);
|
||||
DMAEngine.SCR(DMAStream)->setPBURST(DMA::SCR::Burst::Incremental4);
|
||||
DMAEngine.SCR(DMAStream)->setMINC(false);
|
||||
Config::DMAEngine.SCR(Config::DMAStream)->setDIR(DMA::SCR::Direction::MemoryToMemory);
|
||||
Config::DMAEngine.SM0AR(Config::DMAStream)->set((uint32_t)DataAddress);
|
||||
Config::DMAEngine.SCR(Config::DMAStream)->setMSIZE(DMA::SCR::DataSize::HalfWord);
|
||||
Config::DMAEngine.SCR(Config::DMAStream)->setPSIZE(DMA::SCR::DataSize::HalfWord);
|
||||
Config::DMAEngine.SCR(Config::DMAStream)->setMBURST(DMA::SCR::Burst::Incremental4);
|
||||
Config::DMAEngine.SCR(Config::DMAStream)->setPBURST(DMA::SCR::Burst::Incremental4);
|
||||
Config::DMAEngine.SCR(Config::DMAStream)->setMINC(false);
|
||||
}
|
||||
|
||||
void waitForPendingDMAUploadCompletion() {
|
||||
// Loop until DMA engine available
|
||||
while (DMAEngine.SCR(DMAStream)->getEN()) {
|
||||
while (Config::DMAEngine.SCR(Config::DMAStream)->getEN()) {
|
||||
}
|
||||
}
|
||||
|
||||
static inline void startDMAUpload(const KDColor * src, bool incrementSrc, uint16_t length) {
|
||||
// Reset interruption markers
|
||||
DMAEngine.LIFCR()->set(0xF7D0F7D);
|
||||
Config::DMAEngine.LIFCR()->set(0xF7D0F7D);
|
||||
|
||||
DMAEngine.SNDTR(DMAStream)->set(length);
|
||||
DMAEngine.SPAR(DMAStream)->set((uint32_t)src);
|
||||
DMAEngine.SCR(DMAStream)->setPINC(incrementSrc);
|
||||
DMAEngine.SCR(DMAStream)->setEN(true);
|
||||
Config::DMAEngine.SNDTR(Config::DMAStream)->set(length);
|
||||
Config::DMAEngine.SPAR(Config::DMAStream)->set((uint32_t)src);
|
||||
Config::DMAEngine.SCR(Config::DMAStream)->setPINC(incrementSrc);
|
||||
Config::DMAEngine.SCR(Config::DMAStream)->setEN(true);
|
||||
}
|
||||
#endif
|
||||
|
||||
void initGPIO() {
|
||||
// All the FSMC GPIO pins use the alternate function number 12
|
||||
for(const GPIOPin & g : FSMCPins) {
|
||||
for(const GPIOPin & g : Config::FSMCPins) {
|
||||
g.group().MODER()->setMode(g.pin(), GPIO::MODER::Mode::AlternateFunction);
|
||||
g.group().AFR()->setAlternateFunction(g.pin(), GPIO::AFR::AlternateFunction::AF12);
|
||||
}
|
||||
|
||||
// Turn on the power
|
||||
PowerPin.group().MODER()->setMode(PowerPin.pin(), GPIO::MODER::Mode::Output);
|
||||
PowerPin.group().ODR()->set(PowerPin.pin(), true);
|
||||
Config::PowerPin.group().MODER()->setMode(Config::PowerPin.pin(), GPIO::MODER::Mode::Output);
|
||||
Config::PowerPin.group().ODR()->set(Config::PowerPin.pin(), true);
|
||||
|
||||
// Turn on the reset pin
|
||||
ResetPin.group().MODER()->setMode(ResetPin.pin(), GPIO::MODER::Mode::Output);
|
||||
ResetPin.group().ODR()->set(ResetPin.pin(), true);
|
||||
Config::ResetPin.group().MODER()->setMode(Config::ResetPin.pin(), GPIO::MODER::Mode::Output);
|
||||
Config::ResetPin.group().ODR()->set(Config::ResetPin.pin(), true);
|
||||
|
||||
// Turn on the extended command pin
|
||||
ExtendedCommandPin.group().MODER()->setMode(ExtendedCommandPin.pin(), GPIO::MODER::Mode::Output);
|
||||
ExtendedCommandPin.group().ODR()->set(ExtendedCommandPin.pin(), true);
|
||||
Config::ExtendedCommandPin.group().MODER()->setMode(Config::ExtendedCommandPin.pin(), GPIO::MODER::Mode::Output);
|
||||
Config::ExtendedCommandPin.group().ODR()->set(Config::ExtendedCommandPin.pin(), true);
|
||||
|
||||
// Turn on the Tearing Effect pin
|
||||
TearingEffectPin.group().MODER()->setMode(TearingEffectPin.pin(), GPIO::MODER::Mode::Input);
|
||||
TearingEffectPin.group().PUPDR()->setPull(TearingEffectPin.pin(), GPIO::PUPDR::Pull::None);
|
||||
Config::TearingEffectPin.group().MODER()->setMode(Config::TearingEffectPin.pin(), GPIO::MODER::Mode::Input);
|
||||
Config::TearingEffectPin.group().PUPDR()->setPull(Config::TearingEffectPin.pin(), GPIO::PUPDR::Pull::None);
|
||||
|
||||
Timing::msleep(120);
|
||||
}
|
||||
|
||||
|
||||
void shutdownGPIO() {
|
||||
// All the FSMC GPIO pins use the alternate function number 12
|
||||
for(const GPIOPin & g : FSMCPins) {
|
||||
for(const GPIOPin & g : Config::FSMCPins) {
|
||||
g.group().MODER()->setMode(g.pin(), GPIO::MODER::Mode::Analog);
|
||||
g.group().PUPDR()->setPull(g.pin(), GPIO::PUPDR::Pull::None);
|
||||
}
|
||||
|
||||
ResetPin.group().MODER()->setMode(ResetPin.pin(), GPIO::MODER::Mode::Analog);
|
||||
ResetPin.group().PUPDR()->setPull(ResetPin.pin(), GPIO::PUPDR::Pull::None);
|
||||
Config::ResetPin.group().MODER()->setMode(Config::ResetPin.pin(), GPIO::MODER::Mode::Analog);
|
||||
Config::ResetPin.group().PUPDR()->setPull(Config::ResetPin.pin(), GPIO::PUPDR::Pull::None);
|
||||
|
||||
PowerPin.group().MODER()->setMode(PowerPin.pin(), GPIO::MODER::Mode::Analog);
|
||||
PowerPin.group().PUPDR()->setPull(PowerPin.pin(), GPIO::PUPDR::Pull::None);
|
||||
Config::PowerPin.group().MODER()->setMode(Config::PowerPin.pin(), GPIO::MODER::Mode::Analog);
|
||||
Config::PowerPin.group().PUPDR()->setPull(Config::PowerPin.pin(), GPIO::PUPDR::Pull::None);
|
||||
|
||||
ExtendedCommandPin.group().MODER()->setMode(ExtendedCommandPin.pin(), GPIO::MODER::Mode::Analog);
|
||||
ExtendedCommandPin.group().PUPDR()->setPull(ExtendedCommandPin.pin(), GPIO::PUPDR::Pull::None);
|
||||
Config::ExtendedCommandPin.group().MODER()->setMode(Config::ExtendedCommandPin.pin(), GPIO::MODER::Mode::Analog);
|
||||
Config::ExtendedCommandPin.group().PUPDR()->setPull(Config::ExtendedCommandPin.pin(), GPIO::PUPDR::Pull::None);
|
||||
|
||||
TearingEffectPin.group().MODER()->setMode(TearingEffectPin.pin(), GPIO::MODER::Mode::Analog);
|
||||
Config::TearingEffectPin.group().MODER()->setMode(Config::TearingEffectPin.pin(), GPIO::MODER::Mode::Analog);
|
||||
}
|
||||
|
||||
void initFSMC() {
|
||||
67
ion/src/device/shared/drivers/display.h
Normal file
67
ion/src/device/shared/drivers/display.h
Normal file
@@ -0,0 +1,67 @@
|
||||
#ifndef ION_DEVICE_SHARED_DISPLAY_H
|
||||
#define ION_DEVICE_SHARED_DISPLAY_H
|
||||
|
||||
#include <kandinsky/rect.h>
|
||||
#include <kandinsky/color.h>
|
||||
extern "C" {
|
||||
#include <stddef.h>
|
||||
}
|
||||
|
||||
namespace Ion {
|
||||
namespace Device {
|
||||
namespace Display {
|
||||
|
||||
void init();
|
||||
void shutdown();
|
||||
|
||||
void initDMA();
|
||||
void initGPIO();
|
||||
void shutdownGPIO();
|
||||
void initFSMC();
|
||||
void shutdownFSMC();
|
||||
void initPanel();
|
||||
void shutdownPanel();
|
||||
|
||||
enum class Orientation {
|
||||
Landscape = 0,
|
||||
Portrait = 1
|
||||
};
|
||||
|
||||
void setDrawingArea(KDRect r, Orientation o);
|
||||
void waitForPendingDMAUploadCompletion();
|
||||
void pushPixels(const KDColor * pixels, size_t numberOfPixels);
|
||||
void pushColor(KDColor color, size_t numberOfPixels);
|
||||
void pullPixels(KDColor * pixels, size_t numberOfPixels);
|
||||
|
||||
enum class Command : uint16_t {
|
||||
Nop = 0x00,
|
||||
Reset = 0x01,
|
||||
SleepIn = 0x10,
|
||||
SleepOut = 0x11,
|
||||
DisplayOff = 0x28,
|
||||
DisplayOn = 0x29,
|
||||
ColumnAddressSet = 0x2A,
|
||||
PageAddressSet = 0x2B,
|
||||
MemoryWrite = 0x2C,
|
||||
MemoryRead = 0x2E,
|
||||
TearingEffectLineOn = 0x35,
|
||||
MemoryAccessControl = 0x36,
|
||||
PixelFormatSet = 0x3A,
|
||||
FrameRateControl = 0xC6
|
||||
};
|
||||
|
||||
constexpr static int FSMCMemoryBank = 1;
|
||||
constexpr static int FSMCDataCommandAddressBit = 16;
|
||||
|
||||
constexpr static uint32_t FSMCBaseAddress = 0x60000000;
|
||||
constexpr static uint32_t FSMCBankAddress = FSMCBaseAddress + (FSMCMemoryBank-1)*0x04000000;
|
||||
|
||||
|
||||
static volatile Command * const CommandAddress = (Command *)(FSMCBankAddress);
|
||||
static volatile uint16_t * const DataAddress = (uint16_t *)(FSMCBankAddress | (1<<(FSMCDataCommandAddressBit+1)));
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -1,8 +1,9 @@
|
||||
#include "external_flash.h"
|
||||
#include <drivers/config/external_flash.h>
|
||||
|
||||
namespace Ion {
|
||||
namespace ExternalFlash {
|
||||
namespace Device {
|
||||
namespace ExternalFlash {
|
||||
|
||||
/* The external flash and the Quad-SPI peripheral support
|
||||
* several operating modes, corresponding to different numbers of signals
|
||||
@@ -206,7 +207,7 @@ void init() {
|
||||
}
|
||||
|
||||
void initGPIO() {
|
||||
for(const GPIOPin & g : QSPIPins) {
|
||||
for(const GPIOPin & g : Config::QSPIPins) {
|
||||
g.group().OSPEEDR()->setOutputSpeed(g.pin(), GPIO::OSPEEDR::OutputSpeed::High);
|
||||
g.group().MODER()->setMode(g.pin(), GPIO::MODER::Mode::AlternateFunction);
|
||||
g.group().AFR()->setAlternateFunction(g.pin(), (g.pin() == 6 ? GPIO::AFR::AlternateFunction::AF10 : GPIO::AFR::AlternateFunction::AF9));
|
||||
@@ -1,9 +1,8 @@
|
||||
#ifndef ION_DEVICE_EXTERNAL_FLASH_H
|
||||
#define ION_DEVICE_EXTERNAL_FLASH_H
|
||||
#ifndef ION_DEVICE_SHARED_EXTERNAL_FLASH_H
|
||||
#define ION_DEVICE_SHARED_EXTERNAL_FLASH_H
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stddef.h>
|
||||
#include "regs/regs.h"
|
||||
#include <stdint.h>
|
||||
|
||||
// Quad-SPI on STM32 microcontroller
|
||||
// https://www.st.com/resource/en/application_note/dm00227538.pdf
|
||||
@@ -19,8 +18,8 @@
|
||||
* 2^7 * 2 * 2^3 * 2^4 256B pages 0x....00 - 0x....FF */
|
||||
|
||||
namespace Ion {
|
||||
namespace ExternalFlash {
|
||||
namespace Device {
|
||||
namespace ExternalFlash {
|
||||
|
||||
/* Pin | Role | Mode | Function
|
||||
* -----+----------------------+-----------------------+-----------------
|
||||
@@ -69,11 +68,6 @@ constexpr static uint8_t NumberOfAddressBitsInChip = 23;
|
||||
constexpr static uint8_t NumberOfAddressBitsIn64KbyteBlock = 16;
|
||||
constexpr static uint32_t FlashAddressSpaceSize = 1 << NumberOfAddressBitsInChip;
|
||||
|
||||
constexpr static GPIOPin QSPIPins[] = {
|
||||
GPIOPin(GPIOB, 2), GPIOPin(GPIOB, 6), GPIOPin(GPIOC, 9), GPIOPin(GPIOD,12),
|
||||
GPIOPin(GPIOC, 8), GPIOPin(GPIOD,13)
|
||||
};
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -2,8 +2,8 @@
|
||||
#include <assert.h>
|
||||
|
||||
namespace Ion {
|
||||
namespace Flash {
|
||||
namespace Device {
|
||||
namespace Flash {
|
||||
|
||||
static inline void wait() {
|
||||
// Wait for pending Flash operations to complete
|
||||
@@ -1,12 +1,12 @@
|
||||
#ifndef ION_DEVICE_FLASH_H
|
||||
#define ION_DEVICE_FLASH_H
|
||||
#ifndef ION_DEVICE_SHARED_FLASH_H
|
||||
#define ION_DEVICE_SHARED_FLASH_H
|
||||
|
||||
#include <stddef.h>
|
||||
#include "regs/flash.h"
|
||||
#include <regs/regs.h>
|
||||
|
||||
namespace Ion {
|
||||
namespace Flash {
|
||||
namespace Device {
|
||||
namespace Flash {
|
||||
|
||||
void MassErase();
|
||||
|
||||
@@ -42,19 +42,19 @@
|
||||
|
||||
#include "keyboard.h"
|
||||
|
||||
// Public Ion::Keyboard methods
|
||||
|
||||
namespace Ion {
|
||||
namespace Keyboard {
|
||||
|
||||
using namespace Ion::Device::Keyboard;
|
||||
|
||||
State scan() {
|
||||
uint64_t state = 0;
|
||||
|
||||
for (uint8_t i=0; i<Device::numberOfRows; i++) {
|
||||
Device::activateRow(Device::numberOfRows-1-i);
|
||||
for (uint8_t i=0; i<Config::numberOfRows; i++) {
|
||||
activateRow(Config::numberOfRows-1-i);
|
||||
|
||||
// TODO: Assert pin numbers are sequentials and dynamically find 8 and 0
|
||||
uint8_t columns = Device::ColumnGPIO.IDR()->getBitRange(5,0);
|
||||
uint8_t columns = Config::ColumnGPIO.IDR()->getBitRange(5,0);
|
||||
|
||||
/* The key is down if the input is brought low by the output. In other
|
||||
* words, we want to return true if the input is low (false). So we need to
|
||||
@@ -73,37 +73,35 @@ State scan() {
|
||||
}
|
||||
}
|
||||
|
||||
// Private Ion::Keyboard::Device methods
|
||||
|
||||
namespace Ion {
|
||||
namespace Keyboard {
|
||||
namespace Device {
|
||||
namespace Keyboard {
|
||||
|
||||
void init() {
|
||||
for (uint8_t i=0; i<numberOfRows; i++) {
|
||||
uint8_t pin = RowPins[i];
|
||||
RowGPIO.MODER()->setMode(pin, GPIO::MODER::Mode::Output);
|
||||
RowGPIO.OTYPER()->setType(pin, GPIO::OTYPER::Type::OpenDrain);
|
||||
for (uint8_t i=0; i<Config::numberOfRows; i++) {
|
||||
uint8_t pin = Config::RowPins[i];
|
||||
Config::RowGPIO.MODER()->setMode(pin, GPIO::MODER::Mode::Output);
|
||||
Config::RowGPIO.OTYPER()->setType(pin, GPIO::OTYPER::Type::OpenDrain);
|
||||
}
|
||||
|
||||
for (uint8_t i=0; i<numberOfColumns; i++) {
|
||||
uint8_t pin = ColumnPins[i];
|
||||
ColumnGPIO.MODER()->setMode(pin, GPIO::MODER::Mode::Input);
|
||||
ColumnGPIO.PUPDR()->setPull(pin, GPIO::PUPDR::Pull::Up);
|
||||
for (uint8_t i=0; i<Config::numberOfColumns; i++) {
|
||||
uint8_t pin = Config::ColumnPins[i];
|
||||
Config::ColumnGPIO.MODER()->setMode(pin, GPIO::MODER::Mode::Input);
|
||||
Config::ColumnGPIO.PUPDR()->setPull(pin, GPIO::PUPDR::Pull::Up);
|
||||
}
|
||||
}
|
||||
|
||||
void shutdown() {
|
||||
for (uint8_t i=0; i<numberOfRows; i++) {
|
||||
uint8_t pin = RowPins[i];
|
||||
RowGPIO.MODER()->setMode(pin, GPIO::MODER::Mode::Analog);
|
||||
RowGPIO.PUPDR()->setPull(pin, GPIO::PUPDR::Pull::None);
|
||||
for (uint8_t i=0; i<Config::numberOfRows; i++) {
|
||||
uint8_t pin = Config::RowPins[i];
|
||||
Config::RowGPIO.MODER()->setMode(pin, GPIO::MODER::Mode::Analog);
|
||||
Config::RowGPIO.PUPDR()->setPull(pin, GPIO::PUPDR::Pull::None);
|
||||
}
|
||||
|
||||
for (uint8_t i=0; i<numberOfColumns; i++) {
|
||||
uint8_t pin = ColumnPins[i];
|
||||
ColumnGPIO.MODER()->setMode(pin, GPIO::MODER::Mode::Analog);
|
||||
ColumnGPIO.PUPDR()->setPull(pin, GPIO::PUPDR::Pull::None);
|
||||
for (uint8_t i=0; i<Config::numberOfColumns; i++) {
|
||||
uint8_t pin = Config::ColumnPins[i];
|
||||
Config::ColumnGPIO.MODER()->setMode(pin, GPIO::MODER::Mode::Analog);
|
||||
Config::ColumnGPIO.PUPDR()->setPull(pin, GPIO::PUPDR::Pull::None);
|
||||
}
|
||||
}
|
||||
|
||||
45
ion/src/device/shared/drivers/keyboard.h
Normal file
45
ion/src/device/shared/drivers/keyboard.h
Normal file
@@ -0,0 +1,45 @@
|
||||
#ifndef ION_DEVICE_SHARED_KEYBOARD_H
|
||||
#define ION_DEVICE_SHARED_KEYBOARD_H
|
||||
|
||||
#include <ion/keyboard.h>
|
||||
#include <ion/timing.h>
|
||||
#include <drivers/config/keyboard.h>
|
||||
|
||||
namespace Ion {
|
||||
namespace Device {
|
||||
namespace Keyboard {
|
||||
|
||||
using namespace Ion::Keyboard;
|
||||
|
||||
void init();
|
||||
void shutdown();
|
||||
|
||||
inline uint8_t rowForKey(Key key) {
|
||||
return (int)key/Config::numberOfColumns;
|
||||
}
|
||||
inline uint8_t columnForKey(Key key) {
|
||||
return (int)key%Config::numberOfColumns;
|
||||
}
|
||||
|
||||
inline void activateRow(uint8_t row) {
|
||||
/* In open-drain mode, a 0 in the register drives the pin low, and a 1 lets
|
||||
* the pin floating (Hi-Z). So we want to set the current row to zero and all
|
||||
* the others to 1. */
|
||||
uint16_t rowState = ~(1<<row);
|
||||
|
||||
// TODO: Assert pin numbers are sequentials and dynamically find 9 and 0
|
||||
Config::RowGPIO.ODR()->setBitRange(9, 0, rowState);
|
||||
|
||||
// TODO: 100 us seems to work, but wasn't really calculated
|
||||
Timing::usleep(100);
|
||||
}
|
||||
|
||||
inline bool columnIsActive(uint8_t column) {
|
||||
return !(Config::ColumnGPIO.IDR()->getBitRange(column,column));
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -1,18 +1,19 @@
|
||||
#include <ion/led.h>
|
||||
#include <ion/display.h>
|
||||
#include "device.h"
|
||||
#include "led.h"
|
||||
#include "regs/regs.h"
|
||||
|
||||
// Public Ion::LED methods
|
||||
#include <ion/led.h>
|
||||
#include <drivers/config/led.h>
|
||||
|
||||
static KDColor sLedColor = KDColorBlack;
|
||||
|
||||
KDColor Ion::LED::getColor() {
|
||||
namespace Ion {
|
||||
namespace LED {
|
||||
|
||||
using namespace Ion::Device::LED;
|
||||
|
||||
KDColor getColor() {
|
||||
return sLedColor;
|
||||
}
|
||||
|
||||
void Ion::LED::setColor(KDColor c) {
|
||||
void setColor(KDColor c) {
|
||||
sLedColor = c;
|
||||
|
||||
/* Active all RGB colors */
|
||||
@@ -22,10 +23,10 @@ void Ion::LED::setColor(KDColor c) {
|
||||
|
||||
/* Set the PWM duty cycles to display the right color */
|
||||
constexpr float maxColorValue = (float)((1 << 8) -1);
|
||||
Device::setPeriodAndDutyCycles(Device::Mode::PWM, c.red()/maxColorValue, c.green()/maxColorValue, c.blue()/maxColorValue);
|
||||
setPeriodAndDutyCycles(Mode::PWM, c.red()/maxColorValue, c.green()/maxColorValue, c.blue()/maxColorValue);
|
||||
}
|
||||
|
||||
void Ion::LED::setBlinking(uint16_t period, float dutyCycle) {
|
||||
void setBlinking(uint16_t period, float dutyCycle) {
|
||||
/* We want to use the PWM at a slow rate to display a seeable blink.
|
||||
* Consequently, we do not use PWM to display the right color anymore but to
|
||||
* blink. We cannot use the PWM to display the exact color so we 'project the
|
||||
@@ -34,14 +35,15 @@ void Ion::LED::setBlinking(uint16_t period, float dutyCycle) {
|
||||
TIM3.CCMR()->setOC4M(sLedColor.green() > 0 ? TIM<Register16>::CCMR::OCM::PWM1 : TIM<Register16>::CCMR::OCM::ForceInactive);
|
||||
TIM3.CCMR()->setOC3M(sLedColor.blue() > 0 ? TIM<Register16>::CCMR::OCM::PWM1 : TIM<Register16>::CCMR::OCM::ForceInactive);
|
||||
|
||||
Device::setPeriodAndDutyCycles(Device::Mode::Blink, dutyCycle, dutyCycle, dutyCycle, period);
|
||||
setPeriodAndDutyCycles(Mode::Blink, dutyCycle, dutyCycle, dutyCycle, period);
|
||||
}
|
||||
|
||||
// Private Ion::Device::LED methods
|
||||
}
|
||||
}
|
||||
|
||||
namespace Ion {
|
||||
namespace LED {
|
||||
namespace Device {
|
||||
namespace LED {
|
||||
|
||||
void init() {
|
||||
initGPIO();
|
||||
@@ -57,14 +59,14 @@ void initGPIO() {
|
||||
/* RED_LED(PC7), GREEN_LED(PB1), and BLUE_LED(PB0) are driven using a timer,
|
||||
* which is an alternate function. More precisely, we will use AF2, which maps
|
||||
* PB0 to TIM3_CH2, PB1 to TIM3_CH4, and PC7 to TIM3_CH2. */
|
||||
for(const GPIOPin & g : RGBPins) {
|
||||
for(const GPIOPin & g : Config::RGBPins) {
|
||||
g.group().MODER()->setMode(g.pin(), GPIO::MODER::Mode::AlternateFunction);
|
||||
g.group().AFR()->setAlternateFunction(g.pin(), GPIO::AFR::AlternateFunction::AF2);
|
||||
}
|
||||
}
|
||||
|
||||
void shutdownGPIO() {
|
||||
for(const GPIOPin & g : RGBPins) {
|
||||
for(const GPIOPin & g : Config::RGBPins) {
|
||||
g.group().MODER()->setMode(g.pin(), GPIO::MODER::Mode::Analog);
|
||||
g.group().PUPDR()->setPull(g.pin(), GPIO::PUPDR::Pull::None);
|
||||
}
|
||||
36
ion/src/device/shared/drivers/led.h
Normal file
36
ion/src/device/shared/drivers/led.h
Normal file
@@ -0,0 +1,36 @@
|
||||
#ifndef ION_DEVICE_SHARED_LED_H
|
||||
#define ION_DEVICE_SHARED_LED_H
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
namespace Ion {
|
||||
namespace Device {
|
||||
namespace LED {
|
||||
|
||||
enum class Mode {
|
||||
PWM,
|
||||
Blink
|
||||
};
|
||||
|
||||
enum class Color {
|
||||
Red,
|
||||
Green,
|
||||
Blue
|
||||
};
|
||||
|
||||
void init();
|
||||
void shutdown();
|
||||
void setPeriodAndDutyCycles(Mode mode, float dutyCycleRed, float dutyCycleGreen, float dutyCycleBlue, uint16_t period = 0);
|
||||
|
||||
void initGPIO();
|
||||
void shutdownGPIO();
|
||||
void initTimer();
|
||||
void shutdownTimer();
|
||||
|
||||
constexpr uint16_t PWMPeriod = 40000;
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -1,14 +1,15 @@
|
||||
#include <ion.h>
|
||||
#include "battery.h"
|
||||
#include "device.h"
|
||||
#include "display.h"
|
||||
#include "keyboard.h"
|
||||
#include "led.h"
|
||||
#include "usb.h"
|
||||
#include "wakeup.h"
|
||||
#include "regs/regs.h"
|
||||
#include <ion/keyboard.h>
|
||||
#include <ion/led.h>
|
||||
#include <ion/usb.h>
|
||||
#include <drivers/board.h>
|
||||
#include <drivers/keyboard.h>
|
||||
#include <drivers/wakeup.h>
|
||||
#include <regs/regs.h>
|
||||
|
||||
void Ion::Power::suspend(bool checkIfPowerKeyReleased) {
|
||||
namespace Ion {
|
||||
namespace Power {
|
||||
|
||||
void suspend(bool checkIfPowerKeyReleased) {
|
||||
bool isLEDActive = Ion::LED::getColor() != KDColorBlack;
|
||||
if (checkIfPowerKeyReleased) {
|
||||
/* Wait until power is released to avoid restarting just after suspending */
|
||||
@@ -18,7 +19,7 @@ void Ion::Power::suspend(bool checkIfPowerKeyReleased) {
|
||||
isPowerDown = scan.keyDown(Keyboard::Key::B2);
|
||||
}
|
||||
}
|
||||
Device::shutdownPeripherals(isLEDActive);
|
||||
Device::Board::shutdownPeripherals(isLEDActive);
|
||||
|
||||
PWR.CR()->setLPDS(true); // Turn the regulator off. Takes longer to wake up.
|
||||
PWR.CR()->setFPDS(true); // Put the flash to sleep. Takes longer to wake up.
|
||||
@@ -33,13 +34,13 @@ void Ion::Power::suspend(bool checkIfPowerKeyReleased) {
|
||||
//Ion::LED::setCharging(Ion::USB::isPlugged(), Ion::Battery::isCharging());
|
||||
#endif
|
||||
|
||||
WakeUp::Device::onPowerKeyDown();
|
||||
WakeUp::Device::onUSBPlugging();
|
||||
Device::WakeUp::onPowerKeyDown();
|
||||
Device::WakeUp::onUSBPlugging();
|
||||
#if EPSILON_LED_WHILE_CHARGING
|
||||
WakeUp::Device::onChargingEvent();
|
||||
Device::WakeUp::onChargingEvent();
|
||||
#endif
|
||||
|
||||
Device::shutdownClocks(isLEDActive);
|
||||
Device::Board::shutdownClocks(isLEDActive);
|
||||
|
||||
/* To enter sleep, we need to issue a WFE instruction, which waits for the
|
||||
* event flag to be set and then clears it. However, the event flag might
|
||||
@@ -51,11 +52,11 @@ void Ion::Power::suspend(bool checkIfPowerKeyReleased) {
|
||||
asm("nop");
|
||||
asm("wfe");
|
||||
|
||||
Device::initClocks();
|
||||
Device::Board::initClocks();
|
||||
|
||||
Keyboard::Device::init();
|
||||
Device::Keyboard::init();
|
||||
Keyboard::State scan = Keyboard::scan();
|
||||
Keyboard::Device::shutdown();
|
||||
Device::Keyboard::shutdown();
|
||||
|
||||
Ion::Keyboard::State OnlyPowerKeyDown = Keyboard::State(Keyboard::Key::B2);
|
||||
if (scan == OnlyPowerKeyDown || USB::isPlugged()) {
|
||||
@@ -63,7 +64,10 @@ void Ion::Power::suspend(bool checkIfPowerKeyReleased) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
Device::initClocks();
|
||||
Device::Board::initClocks();
|
||||
|
||||
Device::initPeripherals();
|
||||
Device::Board::initPeripherals();
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
18
ion/src/device/shared/drivers/random.cpp
Normal file
18
ion/src/device/shared/drivers/random.cpp
Normal file
@@ -0,0 +1,18 @@
|
||||
#include <ion.h>
|
||||
#include <regs/regs.h>
|
||||
|
||||
uint32_t Ion::random() {
|
||||
bool initialRNGEngineState = RCC.AHB2ENR()->getRNGEN();
|
||||
RCC.AHB2ENR()->setRNGEN(true);
|
||||
|
||||
RNG.CR()->setRNGEN(true);
|
||||
|
||||
while (RNG.SR()->getDRDY() == 0) {
|
||||
}
|
||||
uint32_t result = RNG.DR()->get();
|
||||
|
||||
RNG.CR()->setRNGEN(false);
|
||||
RCC.AHB2ENR()->setRNGEN(initialRNGEngineState);
|
||||
|
||||
return result;
|
||||
}
|
||||
32
ion/src/device/shared/drivers/reset.cpp
Normal file
32
ion/src/device/shared/drivers/reset.cpp
Normal file
@@ -0,0 +1,32 @@
|
||||
#include "reset.h"
|
||||
#include <regs/regs.h>
|
||||
|
||||
namespace Ion {
|
||||
namespace Device {
|
||||
namespace Reset {
|
||||
|
||||
void core() {
|
||||
// Perform a full core reset
|
||||
CM4.AIRCR()->requestReset();
|
||||
}
|
||||
|
||||
void jump() {
|
||||
uint32_t * stackPointerAddress = reinterpret_cast<uint32_t *>(0x08000000);
|
||||
uint32_t * resetHandlerAddress = reinterpret_cast<uint32_t *>(0x08000004);
|
||||
|
||||
/* Jump to the reset service routine after having reset the stack pointer.
|
||||
* Both addresses are fetched from the base of the Flash memory, just like a
|
||||
* real reset would. These operations should be made at once, otherwise the C
|
||||
* compiler might emit some instructions that modify the stack inbetween. */
|
||||
|
||||
asm volatile (
|
||||
"msr MSP, %[stackPointer] ; bx %[resetHandler]"
|
||||
: :
|
||||
[stackPointer] "r" (*stackPointerAddress),
|
||||
[resetHandler] "r" (*resetHandlerAddress)
|
||||
);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
15
ion/src/device/shared/drivers/reset.h
Normal file
15
ion/src/device/shared/drivers/reset.h
Normal file
@@ -0,0 +1,15 @@
|
||||
#ifndef ION_DEVICE_SHARED_RESET_H
|
||||
#define ION_DEVICE_SHARED_RESET_H
|
||||
|
||||
namespace Ion {
|
||||
namespace Device {
|
||||
namespace Reset {
|
||||
|
||||
void core();
|
||||
void jump();
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
30
ion/src/device/shared/drivers/serial_number.cpp
Normal file
30
ion/src/device/shared/drivers/serial_number.cpp
Normal file
@@ -0,0 +1,30 @@
|
||||
#include "serial_number.h"
|
||||
#include "base64.h"
|
||||
|
||||
namespace Ion {
|
||||
|
||||
using namespace Ion::Device::SerialNumber;
|
||||
|
||||
const char * serialNumber() {
|
||||
static char serialNumber[Length + 1] = {0};
|
||||
if (serialNumber[0] == 0) {
|
||||
copy(serialNumber);
|
||||
}
|
||||
return serialNumber;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
namespace Ion {
|
||||
namespace Device {
|
||||
namespace SerialNumber {
|
||||
|
||||
void copy(char * buffer) {
|
||||
const unsigned char * rawUniqueID = (const unsigned char *)0x1FFF7A10;
|
||||
Base64::encode(rawUniqueID, 12, buffer);
|
||||
buffer[Length] = 0;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
19
ion/src/device/shared/drivers/serial_number.h
Normal file
19
ion/src/device/shared/drivers/serial_number.h
Normal file
@@ -0,0 +1,19 @@
|
||||
#ifndef ION_DEVICE_SHARED_SERIAL_NUMBER_H
|
||||
#define ION_DEVICE_SHARED_SERIAL_NUMBER_H
|
||||
|
||||
namespace Ion {
|
||||
namespace Device {
|
||||
namespace SerialNumber {
|
||||
|
||||
/* The serial number is 96 bits long. That's equal to 16 digits in base 64. We
|
||||
* expose a convenient "copySerialNumber" routine which can be called without
|
||||
* using a static variable (and therefore without a .bss section). This is used
|
||||
* in the RAM'ed DFU bootloader. */
|
||||
constexpr static int Length = 16;
|
||||
void copy(char * buffer);
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -1,19 +1,19 @@
|
||||
#include "swd.h"
|
||||
#include "regs/regs.h"
|
||||
#include <drivers/config/swd.h>
|
||||
|
||||
namespace Ion {
|
||||
namespace SWD {
|
||||
namespace Device {
|
||||
namespace SWD {
|
||||
|
||||
void init() {
|
||||
for(const GPIOPin & g : Pins) {
|
||||
for(const GPIOPin & g : Config::Pins) {
|
||||
g.group().MODER()->setMode(g.pin(), GPIO::MODER::Mode::AlternateFunction);
|
||||
g.group().AFR()->setAlternateFunction(g.pin(), GPIO::AFR::AlternateFunction::AF0);
|
||||
}
|
||||
}
|
||||
|
||||
void shutdown() {
|
||||
for(const GPIOPin & g : Pins) {
|
||||
for(const GPIOPin & g : Config::Pins) {
|
||||
g.group().MODER()->setMode(g.pin(), GPIO::MODER::Mode::Analog);
|
||||
g.group().PUPDR()->setPull(g.pin(), GPIO::PUPDR::Pull::None);
|
||||
}
|
||||
15
ion/src/device/shared/drivers/swd.h
Normal file
15
ion/src/device/shared/drivers/swd.h
Normal file
@@ -0,0 +1,15 @@
|
||||
#ifndef ION_DEVICE_SHARED_SWD_H
|
||||
#define ION_DEVICE_SHARED_SWD_H
|
||||
|
||||
namespace Ion {
|
||||
namespace Device {
|
||||
namespace SWD {
|
||||
|
||||
void init();
|
||||
void shutdown();
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
53
ion/src/device/shared/drivers/timing.cpp
Normal file
53
ion/src/device/shared/drivers/timing.cpp
Normal file
@@ -0,0 +1,53 @@
|
||||
#include "timing.h"
|
||||
#include <ion/timing.h>
|
||||
#include <drivers/config/timing.h>
|
||||
|
||||
namespace Ion {
|
||||
namespace Timing {
|
||||
|
||||
using namespace Ion::Device::Timing;
|
||||
|
||||
/* TODO: The delay methods 'msleep' and 'usleep' are currently dependent on the
|
||||
* optimizations chosen by the compiler. To prevent that and to gain in
|
||||
* precision, we could use the controller cycle counter (Systick). */
|
||||
|
||||
void msleep(uint32_t ms) {
|
||||
for (volatile uint32_t i=0; i<Config::LoopsPerMillisecond*ms; i++) {
|
||||
__asm volatile("nop");
|
||||
}
|
||||
}
|
||||
void usleep(uint32_t us) {
|
||||
for (volatile uint32_t i=0; i<Config::LoopsPerMicrosecond*us; i++) {
|
||||
__asm volatile("nop");
|
||||
}
|
||||
}
|
||||
|
||||
uint64_t millis() {
|
||||
return MillisElapsed;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
namespace Ion {
|
||||
namespace Device {
|
||||
namespace Timing {
|
||||
|
||||
volatile uint64_t MillisElapsed = 0;
|
||||
|
||||
void init() {
|
||||
CM4.SYST_RVR()->setRELOAD(Config::SysTickPerMillisecond - 1); // Remove 1 because the counter resets *after* counting to 0
|
||||
CM4.SYST_CVR()->setCURRENT(0);
|
||||
CM4.SYST_CSR()->setCLKSOURCE(CM4::SYST_CSR::CLKSOURCE::AHB_DIV8);
|
||||
CM4.SYST_CSR()->setTICKINT(true);
|
||||
CM4.SYST_CSR()->setENABLE(true);
|
||||
}
|
||||
|
||||
void shutdown() {
|
||||
CM4.SYST_CSR()->setENABLE(false);
|
||||
CM4.SYST_CSR()->setTICKINT(false);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
19
ion/src/device/shared/drivers/timing.h
Normal file
19
ion/src/device/shared/drivers/timing.h
Normal file
@@ -0,0 +1,19 @@
|
||||
#ifndef ION_DEVICE_SHARED_TIMING_H
|
||||
#define ION_DEVICE_SHARED_TIMING_H
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
namespace Ion {
|
||||
namespace Device {
|
||||
namespace Timing {
|
||||
|
||||
void init();
|
||||
void shutdown();
|
||||
|
||||
extern volatile uint64_t MillisElapsed;
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -1,16 +1,14 @@
|
||||
#include <ion/usb.h>
|
||||
#include "usb.h"
|
||||
#include <ion/display.h>
|
||||
#include "device.h"
|
||||
#include "display.h"
|
||||
#include "regs/regs.h"
|
||||
#include <stdlib.h>
|
||||
#include <ion/usb.h>
|
||||
#include <drivers/config/usb.h>
|
||||
|
||||
namespace Ion {
|
||||
namespace USB {
|
||||
|
||||
using namespace Ion::Device::USB;
|
||||
|
||||
bool isPlugged() {
|
||||
return Device::VbusPin.group().IDR()->get(Device::VbusPin.pin());
|
||||
return Config::VbusPin.group().IDR()->get(Config::VbusPin.pin());
|
||||
}
|
||||
|
||||
bool isEnumerated() {
|
||||
@@ -38,8 +36,8 @@ void disable() {
|
||||
}
|
||||
|
||||
namespace Ion {
|
||||
namespace USB {
|
||||
namespace Device {
|
||||
namespace USB {
|
||||
|
||||
void init() {
|
||||
initGPIO();
|
||||
@@ -69,22 +67,22 @@ void initGPIO() {
|
||||
* plugged, the pin must be pulled down. */
|
||||
// FIXME: Understand how the Vbus pin really works!
|
||||
#if 0
|
||||
VbusPin.group().MODER()->setMode(VbusPin.pin(), GPIO::MODER::Mode::Input);
|
||||
VbusPin.group().PUPDR()->setPull(VbusPin.pin(), GPIO::PUPDR::Pull::Down);
|
||||
Config::VbusPin.group().MODER()->setMode(Config::VbusPin.pin(), GPIO::MODER::Mode::Input);
|
||||
Config::VbusPin.group().PUPDR()->setPull(Config::VbusPin.pin(), GPIO::PUPDR::Pull::Down);
|
||||
#else
|
||||
VbusPin.group().MODER()->setMode(VbusPin.pin(), GPIO::MODER::Mode::AlternateFunction);
|
||||
VbusPin.group().AFR()->setAlternateFunction(VbusPin.pin(), GPIO::AFR::AlternateFunction::AF10);
|
||||
Config::VbusPin.group().MODER()->setMode(Config::VbusPin.pin(), GPIO::MODER::Mode::AlternateFunction);
|
||||
Config::VbusPin.group().AFR()->setAlternateFunction(Config::VbusPin.pin(), GPIO::AFR::AlternateFunction::AF10);
|
||||
#endif
|
||||
|
||||
DmPin.group().MODER()->setMode(DmPin.pin(), GPIO::MODER::Mode::AlternateFunction);
|
||||
DmPin.group().AFR()->setAlternateFunction(DmPin.pin(), GPIO::AFR::AlternateFunction::AF10);
|
||||
Config::DmPin.group().MODER()->setMode(Config::DmPin.pin(), GPIO::MODER::Mode::AlternateFunction);
|
||||
Config::DmPin.group().AFR()->setAlternateFunction(Config::DmPin.pin(), GPIO::AFR::AlternateFunction::AF10);
|
||||
|
||||
DpPin.group().MODER()->setMode(DpPin.pin(), GPIO::MODER::Mode::AlternateFunction);
|
||||
DpPin.group().AFR()->setAlternateFunction(DpPin.pin(), GPIO::AFR::AlternateFunction::AF10);
|
||||
Config::DpPin.group().MODER()->setMode(Config::DpPin.pin(), GPIO::MODER::Mode::AlternateFunction);
|
||||
Config::DpPin.group().AFR()->setAlternateFunction(Config::DpPin.pin(), GPIO::AFR::AlternateFunction::AF10);
|
||||
}
|
||||
|
||||
void shutdownGPIO() {
|
||||
constexpr static GPIOPin USBPins[] = {DpPin, DmPin, VbusPin};
|
||||
constexpr static GPIOPin USBPins[] = {Config::DpPin, Config::DmPin, Config::VbusPin};
|
||||
for (const GPIOPin & g : USBPins) {
|
||||
g.group().MODER()->setMode(g.pin(), GPIO::MODER::Mode::Analog);
|
||||
g.group().PUPDR()->setPull(g.pin(), GPIO::PUPDR::Pull::None);
|
||||
19
ion/src/device/shared/drivers/usb.h
Normal file
19
ion/src/device/shared/drivers/usb.h
Normal file
@@ -0,0 +1,19 @@
|
||||
#ifndef ION_DEVICE_SHARED_USB_H
|
||||
#define ION_DEVICE_SHARED_USB_H
|
||||
|
||||
namespace Ion {
|
||||
namespace Device {
|
||||
namespace USB {
|
||||
|
||||
void init();
|
||||
void shutdown();
|
||||
void initGPIO();
|
||||
void shutdownGPIO();
|
||||
void initOTG();
|
||||
void shutdownOTG();
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
72
ion/src/device/shared/drivers/wakeup.cpp
Normal file
72
ion/src/device/shared/drivers/wakeup.cpp
Normal file
@@ -0,0 +1,72 @@
|
||||
#include "wakeup.h"
|
||||
#include <drivers/battery.h>
|
||||
#include <drivers/keyboard.h>
|
||||
#include <drivers/usb.h>
|
||||
#include <drivers/config/battery.h>
|
||||
#include <drivers/config/keyboard.h>
|
||||
#include <drivers/config/usb.h>
|
||||
#include <regs/regs.h>
|
||||
|
||||
namespace Ion {
|
||||
namespace Device {
|
||||
namespace WakeUp {
|
||||
|
||||
void onChargingEvent() {
|
||||
Battery::initGPIO();
|
||||
|
||||
/* Warning: pins with the same number in different groups cannot be set as
|
||||
* source input for EXTI at the same time. Here, EXTICR1 register is filled
|
||||
* between position 0-3 (charging pin = 0) with
|
||||
* 0000 (ChargingGPIO = group A). */
|
||||
SYSCFG.EXTICR1()->setEXTI(Battery::Config::ChargingPin.pin(), Battery::Config::ChargingPin.group());
|
||||
|
||||
EXTI.EMR()->set(Battery::Config::ChargingPin.pin(), true);
|
||||
|
||||
/* We need to detect when the battery stops charging. We set the
|
||||
* wake up event on the rising edge. */
|
||||
EXTI.RTSR()->set(Battery::Config::ChargingPin.pin(), true);
|
||||
}
|
||||
|
||||
void onUSBPlugging() {
|
||||
USB::initGPIO();
|
||||
/* Here, EXTICR3 register is filled between position 4-7 (Vbus pin = 9) with
|
||||
* 0000 (Vbus GPIO = group A). */
|
||||
SYSCFG.EXTICR3()->setEXTI(USB::Config::VbusPin.pin(), USB::Config::VbusPin.group());
|
||||
|
||||
EXTI.EMR()->set(USB::Config::VbusPin.pin(), true);
|
||||
#if EPSILON_LED_WHILE_CHARGING
|
||||
EXTI.FTSR()->set(USB::Config::VbusPin.pin(), true);
|
||||
#endif
|
||||
EXTI.RTSR()->set(USB::Config::VbusPin.pin(), true);
|
||||
}
|
||||
|
||||
|
||||
void onPowerKeyDown() {
|
||||
Keyboard::Key key = Keyboard::Key::B2;
|
||||
uint8_t rowPin = Keyboard::Config::RowPins[Keyboard::rowForKey(key)];
|
||||
Keyboard::Config::RowGPIO.MODER()->setMode(rowPin, GPIO::MODER::Mode::Output);
|
||||
Keyboard::Config::RowGPIO.OTYPER()->setType(rowPin, GPIO::OTYPER::Type::OpenDrain);
|
||||
Keyboard::Config::RowGPIO.ODR()->set(rowPin, 0);
|
||||
|
||||
uint8_t column = Keyboard::columnForKey(key);
|
||||
uint8_t columnPin = Keyboard::Config::ColumnPins[column];
|
||||
|
||||
Keyboard::Config::ColumnGPIO.MODER()->setMode(columnPin, GPIO::MODER::Mode::Input);
|
||||
Keyboard::Config::ColumnGPIO.PUPDR()->setPull(columnPin, GPIO::PUPDR::Pull::Up);
|
||||
|
||||
/* Here, EXTICR1 register is filled between position 4-7 (column pin = 1) with
|
||||
* 0010 (ColumnGPIO = group C). */
|
||||
|
||||
SYSCFG.EXTICR1()->setEXTI(columnPin, Keyboard::Config::ColumnGPIO);
|
||||
|
||||
EXTI.EMR()->set(columnPin, true);
|
||||
|
||||
/* When the key is pressed, it will go from 1 (because it's pulled up) to
|
||||
* zero (because it's connected to the open-drain output. In other words,
|
||||
* we're waiting for a falling edge. */
|
||||
EXTI.FTSR()->set(columnPin, true);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -4,8 +4,8 @@
|
||||
#include "regs/regs.h"
|
||||
|
||||
namespace Ion {
|
||||
namespace WakeUp {
|
||||
namespace Device {
|
||||
namespace WakeUp {
|
||||
|
||||
/* All wakeup functions can be called together without overwriting the same
|
||||
* register. All togethed, they will set SYSCFG and EXTi registers as follow:
|
||||
73
ion/src/device/shared/usb/Makefile
Normal file
73
ion/src/device/shared/usb/Makefile
Normal file
@@ -0,0 +1,73 @@
|
||||
usb_objs += $(addprefix ion/src/device/shared/usb/, \
|
||||
calculator.o \
|
||||
dfu_interface.o\
|
||||
)
|
||||
|
||||
usb_objs += $(addprefix ion/src/device/shared/usb/stack/, \
|
||||
device.o\
|
||||
endpoint0.o \
|
||||
interface.o\
|
||||
request_recipient.o\
|
||||
setup_packet.o\
|
||||
streamable.o\
|
||||
)
|
||||
|
||||
usb_objs += $(addprefix ion/src/device/shared/usb/stack/descriptor/, \
|
||||
bos_descriptor.o\
|
||||
configuration_descriptor.o \
|
||||
descriptor.o\
|
||||
device_descriptor.o\
|
||||
device_capability_descriptor.o\
|
||||
dfu_functional_descriptor.o\
|
||||
extended_compat_id_descriptor.o \
|
||||
interface_descriptor.o\
|
||||
language_id_string_descriptor.o \
|
||||
microsoft_os_string_descriptor.o\
|
||||
platform_device_capability_descriptor.o\
|
||||
string_descriptor.o\
|
||||
url_descriptor.o\
|
||||
webusb_platform_descriptor.o\
|
||||
)
|
||||
|
||||
$(usb_objs): SFLAGS += $(ION_DEVICE_SFLAGS)
|
||||
|
||||
EPSILON_USB_DFU_XIP ?= 0
|
||||
|
||||
ifeq ($(EPSILON_USB_DFU_XIP),1)
|
||||
|
||||
ion_device_objs += ion/src/device/shared/usb/dfu_xip.o
|
||||
ion_device_objs += $(usb_objs)
|
||||
|
||||
else
|
||||
|
||||
dfu_objs += liba/src/assert.o
|
||||
dfu_objs += liba/src/strlen.o
|
||||
dfu_objs += liba/src/strlcpy.o
|
||||
dfu_objs += liba/src/memset.o
|
||||
dfu_objs += liba/src/memcpy.o
|
||||
dfu_objs += libaxx/src/cxxabi/pure_virtual.o
|
||||
dfu_objs += ion/src/device/shared/usb/boot.o
|
||||
dfu_objs += $(addprefix ion/src/device/shared/drivers/, \
|
||||
base64.o \
|
||||
external_flash.o \
|
||||
flash.o \
|
||||
keyboard.o \
|
||||
reset.o \
|
||||
serial_number.o \
|
||||
timing.o \
|
||||
usb.o \
|
||||
)
|
||||
|
||||
ion/src/device/shared/usb/dfu.elf: LDSCRIPT = ion/src/device/shared/usb/dfu.ld
|
||||
ion/src/device/shared/usb/dfu.elf: $(usb_objs) $(dfu_objs)
|
||||
|
||||
ion/src/device/shared/usb/dfu.o: ion/src/device/shared/usb/dfu.bin
|
||||
@echo "OBJCOPY $@"
|
||||
$(Q) $(OBJCOPY) -I binary -O elf32-littlearm -B arm --rename-section .data=.rodata --redefine-sym _binary_ion_src_device_shared_usb_dfu_bin_start=_dfu_bootloader_flash_start --redefine-sym _binary_ion_src_device_shared_usb_dfu_bin_end=_dfu_bootloader_flash_end $< $@
|
||||
|
||||
ion_device_objs += ion/src/device/shared/usb/dfu.o
|
||||
ion_device_objs += ion/src/device/shared/usb/dfu_relocated.o
|
||||
|
||||
products += $(usb_objs) $(addprefix ion/src/device/shared/usb/dfu, .elf .bin)
|
||||
|
||||
endif
|
||||
@@ -1,27 +1,27 @@
|
||||
#include "calculator.h"
|
||||
#include <ion/usb.h>
|
||||
#include <ion/src/device/regs/regs.h>
|
||||
#include <ion/src/device/device.h>
|
||||
#include <ion/src/device/keyboard.h>
|
||||
#include <drivers/keyboard.h>
|
||||
#include <drivers/reset.h>
|
||||
#include <drivers/serial_number.h>
|
||||
|
||||
namespace Ion {
|
||||
namespace USB {
|
||||
namespace Device {
|
||||
namespace USB {
|
||||
|
||||
void Calculator::PollAndReset(bool exitWithKeyboard) {
|
||||
char serialNumber[Ion::Device::SerialNumberLength+1];
|
||||
Ion::Device::copySerialNumber(serialNumber);
|
||||
char serialNumber[Ion::Device::SerialNumber::Length+1];
|
||||
Ion::Device::SerialNumber::copy(serialNumber);
|
||||
Calculator c(serialNumber);
|
||||
|
||||
/* Leave DFU mode if the Back key is pressed, the calculator unplugged or the
|
||||
* USB core soft-disconnected. */
|
||||
Ion::Keyboard::Key exitKey = Ion::Keyboard::Key::A6;
|
||||
uint8_t exitKeyRow = Ion::Keyboard::Device::rowForKey(exitKey);
|
||||
uint8_t exitKeyColumn = Ion::Keyboard::Device::columnForKey(exitKey);
|
||||
uint8_t exitKeyRow = Ion::Device::Keyboard::rowForKey(exitKey);
|
||||
uint8_t exitKeyColumn = Ion::Device::Keyboard::columnForKey(exitKey);
|
||||
|
||||
Ion::Keyboard::Device::activateRow(exitKeyRow);
|
||||
Ion::Device::Keyboard::activateRow(exitKeyRow);
|
||||
|
||||
while (!(exitWithKeyboard && Ion::Keyboard::Device::columnIsActive(exitKeyColumn)) &&
|
||||
while (!(exitWithKeyboard && Ion::Device::Keyboard::columnIsActive(exitKeyColumn)) &&
|
||||
Ion::USB::isPlugged() &&
|
||||
!c.isSoftDisconnected()) {
|
||||
c.poll();
|
||||
@@ -35,7 +35,7 @@ void Calculator::PollAndReset(bool exitWithKeyboard) {
|
||||
* thing to do but would therefore result in the device entering the ROMed
|
||||
* DFU bootloader, which we want to avoid. By performing a jump-reset, we
|
||||
* will enter the newly flashed firmware. */
|
||||
Ion::Device::jumpReset();
|
||||
Ion::Device::Reset::jump();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
#ifndef ION_DEVICE_USB_CALCULATOR_H
|
||||
#define ION_DEVICE_USB_CALCULATOR_H
|
||||
#ifndef ION_DEVICE_SHARED_USB_CALCULATOR_H
|
||||
#define ION_DEVICE_SHARED_USB_CALCULATOR_H
|
||||
|
||||
#include <stddef.h>
|
||||
#include <assert.h>
|
||||
@@ -19,8 +19,8 @@
|
||||
#include "stack/descriptor/webusb_platform_descriptor.h"
|
||||
|
||||
namespace Ion {
|
||||
namespace USB {
|
||||
namespace Device {
|
||||
namespace USB {
|
||||
|
||||
class Calculator : public Device {
|
||||
public:
|
||||
@@ -1,11 +1,11 @@
|
||||
#include "dfu_interface.h"
|
||||
#include <string.h>
|
||||
#include <ion/src/device/flash.h>
|
||||
#include <ion/src/device/external_flash.h>
|
||||
#include "../drivers/flash.h"
|
||||
#include "../drivers/external_flash.h"
|
||||
|
||||
namespace Ion {
|
||||
namespace USB {
|
||||
namespace Device {
|
||||
namespace USB {
|
||||
|
||||
static inline uint32_t min(uint32_t x, uint32_t y) { return (x<y ? x : y); }
|
||||
|
||||
@@ -174,7 +174,7 @@ void DFUInterface::eraseCommand(uint8_t * transferBuffer, uint16_t transferBuffe
|
||||
|
||||
if (transferBufferLength == 1) {
|
||||
// Mass erase
|
||||
m_erasePage = Flash::Device::NumberOfSectors + ExternalFlash::Device::NumberOfSectors;
|
||||
m_erasePage = Flash::NumberOfSectors + ExternalFlash::NumberOfSectors;
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -187,9 +187,9 @@ void DFUInterface::eraseCommand(uint8_t * transferBuffer, uint16_t transferBuffe
|
||||
+ (transferBuffer[4] << 24);
|
||||
|
||||
if (eraseAddress >= k_flashStartAddress && eraseAddress <= k_flashEndAddress) {
|
||||
m_erasePage = Flash::Device::SectorAtAddress(eraseAddress);
|
||||
m_erasePage = Flash::SectorAtAddress(eraseAddress);
|
||||
} else if (eraseAddress >= k_externalFlashStartAddress && eraseAddress <= k_externalFlashEndAddress) {
|
||||
m_erasePage = Flash::Device::NumberOfSectors + ExternalFlash::Device::SectorAtAddress(eraseAddress - k_externalFlashStartAddress);
|
||||
m_erasePage = Flash::NumberOfSectors + ExternalFlash::SectorAtAddress(eraseAddress - k_externalFlashStartAddress);
|
||||
} else {
|
||||
// Unrecognized sector
|
||||
m_state = State::dfuERROR;
|
||||
@@ -204,13 +204,13 @@ void DFUInterface::eraseMemoryIfNeeded() {
|
||||
return;
|
||||
}
|
||||
|
||||
if (m_erasePage == Flash::Device::NumberOfSectors + ExternalFlash::Device::NumberOfSectors) {
|
||||
Flash::Device::MassErase();
|
||||
ExternalFlash::Device::MassErase();
|
||||
} else if (m_erasePage < Flash::Device::NumberOfSectors) {
|
||||
Flash::Device::EraseSector(m_erasePage);
|
||||
if (m_erasePage == Flash::NumberOfSectors + ExternalFlash::NumberOfSectors) {
|
||||
Flash::MassErase();
|
||||
ExternalFlash::MassErase();
|
||||
} else if (m_erasePage < Flash::NumberOfSectors) {
|
||||
Flash::EraseSector(m_erasePage);
|
||||
} else {
|
||||
ExternalFlash::Device::EraseSector(m_erasePage - Flash::Device::NumberOfSectors);
|
||||
ExternalFlash::EraseSector(m_erasePage - Flash::NumberOfSectors);
|
||||
}
|
||||
|
||||
/* Put an out of range value in m_erasePage to indicate that no erase is
|
||||
@@ -223,13 +223,13 @@ void DFUInterface::eraseMemoryIfNeeded() {
|
||||
void DFUInterface::writeOnMemory() {
|
||||
if (m_writeAddress >= k_flashStartAddress && m_writeAddress <= k_flashEndAddress) {
|
||||
// Write to the Flash memory
|
||||
Flash::Device::WriteMemory(m_largeBuffer, reinterpret_cast<uint8_t *>(m_writeAddress), m_largeBufferLength);
|
||||
Flash::WriteMemory(m_largeBuffer, reinterpret_cast<uint8_t *>(m_writeAddress), m_largeBufferLength);
|
||||
} else if (m_writeAddress >= k_sramStartAddress && m_writeAddress <= k_sramEndAddress) {
|
||||
// Write on SRAM
|
||||
// FIXME We should check that we are not overriding the current instructions.
|
||||
memcpy((void *)m_writeAddress, m_largeBuffer, m_largeBufferLength);
|
||||
} else if (m_writeAddress >= k_externalFlashStartAddress && m_writeAddress <= k_externalFlashEndAddress) {
|
||||
ExternalFlash::Device::WriteMemory(m_largeBuffer, reinterpret_cast<uint8_t *>(m_writeAddress) - k_externalFlashStartAddress, m_largeBufferLength);
|
||||
ExternalFlash::WriteMemory(m_largeBuffer, reinterpret_cast<uint8_t *>(m_writeAddress) - k_externalFlashStartAddress, m_largeBufferLength);
|
||||
} else {
|
||||
// Invalid write address
|
||||
m_largeBufferLength = 0;
|
||||
@@ -1,5 +1,5 @@
|
||||
#ifndef ION_DEVICE_USB_DFU_INTERFACE_H
|
||||
#define ION_DEVICE_USB_DFU_INTERFACE_H
|
||||
#ifndef ION_DEVICE_SHARED_USB_DFU_INTERFACE_H
|
||||
#define ION_DEVICE_SHARED_USB_DFU_INTERFACE_H
|
||||
|
||||
#include <assert.h>
|
||||
#include <stddef.h>
|
||||
@@ -10,8 +10,8 @@
|
||||
#include "stack/streamable.h"
|
||||
|
||||
namespace Ion {
|
||||
namespace USB {
|
||||
namespace Device {
|
||||
namespace USB {
|
||||
|
||||
class DFUInterface : public Interface {
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
#include <ion/usb.h>
|
||||
#include <string.h>
|
||||
#include <assert.h>
|
||||
#include <ion/src/device/device.h>
|
||||
#include "../drivers/timing.h"
|
||||
|
||||
extern char _stack_end;
|
||||
extern char _dfu_bootloader_flash_start;
|
||||
@@ -51,7 +51,7 @@ void DFU() {
|
||||
/* 4- Disable all interrupts
|
||||
* The interrupt service routines live in the Flash and could be overwritten
|
||||
* by garbage during a firmware upgrade opration, so we disable them. */
|
||||
Device::shutdownSysTick();
|
||||
Device::Timing::shutdown();
|
||||
|
||||
/* 5- Jump to DFU bootloader code. We made sure in the linker script that the
|
||||
* first function we want to call is at the beginning of the DFU code. */
|
||||
@@ -70,7 +70,7 @@ void DFU() {
|
||||
dfu_bootloader_entry(true);
|
||||
|
||||
/* 5- Restore interrupts */
|
||||
Device::initSysTick();
|
||||
Device::Timing::init();
|
||||
|
||||
/* 6- That's all. The DFU bootloader on the stack is now dead code that will
|
||||
* be overwritten when the stack grows. */
|
||||
@@ -1,11 +1,10 @@
|
||||
#include "calculator.h"
|
||||
#include "../device.h"
|
||||
|
||||
namespace Ion {
|
||||
namespace USB {
|
||||
|
||||
void DFU() {
|
||||
Ion::USB::Device::Calculator::PollAndReset(true);
|
||||
Ion::Device::USB::Calculator::PollAndReset(true);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,8 +1,8 @@
|
||||
#include "bos_descriptor.h"
|
||||
|
||||
namespace Ion {
|
||||
namespace USB {
|
||||
namespace Device {
|
||||
namespace USB {
|
||||
|
||||
void BOSDescriptor::push(Channel * c) const {
|
||||
Descriptor::push(c);
|
||||
@@ -1,12 +1,12 @@
|
||||
#ifndef ION_DEVICE_USB_STACK_BOS_DESCRIPTOR_H
|
||||
#define ION_DEVICE_USB_STACK_BOS_DESCRIPTOR_H
|
||||
#ifndef ION_DEVICE_SHARED_USB_STACK_BOS_DESCRIPTOR_H
|
||||
#define ION_DEVICE_SHARED_USB_STACK_BOS_DESCRIPTOR_H
|
||||
|
||||
#include "descriptor.h"
|
||||
#include "device_capability_descriptor.h"
|
||||
|
||||
namespace Ion {
|
||||
namespace USB {
|
||||
namespace Device {
|
||||
namespace USB {
|
||||
|
||||
class BOSDescriptor : public Descriptor {
|
||||
public:
|
||||
@@ -1,8 +1,8 @@
|
||||
#include "configuration_descriptor.h"
|
||||
|
||||
namespace Ion {
|
||||
namespace USB {
|
||||
namespace Device {
|
||||
namespace USB {
|
||||
|
||||
void ConfigurationDescriptor::push(Channel * c) const {
|
||||
Descriptor::push(c);
|
||||
@@ -1,12 +1,12 @@
|
||||
#ifndef ION_DEVICE_USB_STACK_CONFIGURATION_DESCRIPTOR_H
|
||||
#define ION_DEVICE_USB_STACK_CONFIGURATION_DESCRIPTOR_H
|
||||
#ifndef ION_DEVICE_SHARED_USB_STACK_CONFIGURATION_DESCRIPTOR_H
|
||||
#define ION_DEVICE_SHARED_USB_STACK_CONFIGURATION_DESCRIPTOR_H
|
||||
|
||||
#include "descriptor.h"
|
||||
#include "interface_descriptor.h"
|
||||
|
||||
namespace Ion {
|
||||
namespace USB {
|
||||
namespace Device {
|
||||
namespace USB {
|
||||
|
||||
class ConfigurationDescriptor : public Descriptor {
|
||||
public:
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user