mirror of
https://github.com/Polprzewodnikowy/SummerCart64.git
synced 2024-11-21 21:49:15 +01:00
[SC64][SW] Added board bring-up via UART header
This commit is contained in:
parent
4f6c65c770
commit
bc921d762d
3
build.sh
3
build.sh
@ -89,6 +89,7 @@ build_update () {
|
|||||||
--mcu ../controller/build/app/app.bin \
|
--mcu ../controller/build/app/app.bin \
|
||||||
--fpga ../../fw/project/lcmxo2/impl1/sc64_impl1.jed \
|
--fpga ../../fw/project/lcmxo2/impl1/sc64_impl1.jed \
|
||||||
--boot ../bootloader/build/bootloader.bin \
|
--boot ../bootloader/build/bootloader.bin \
|
||||||
|
--primer ../controller/build/primer/primer.bin \
|
||||||
sc64.upd
|
sc64.upd
|
||||||
popd > /dev/null
|
popd > /dev/null
|
||||||
|
|
||||||
@ -113,7 +114,7 @@ print_usage () {
|
|||||||
echo "usage: ./build.sh [bootloader] [controller] [fpga] [update] [release] [-c] [--help]"
|
echo "usage: ./build.sh [bootloader] [controller] [fpga] [update] [release] [-c] [--help]"
|
||||||
echo "parameters:"
|
echo "parameters:"
|
||||||
echo " bootloader - compile N64 bootloader software"
|
echo " bootloader - compile N64 bootloader software"
|
||||||
echo " controller - compile ARM controller software"
|
echo " controller - compile MCU controller software"
|
||||||
echo " fpga - compile FPGA design"
|
echo " fpga - compile FPGA design"
|
||||||
echo " update - compile all software and designs"
|
echo " update - compile all software and designs"
|
||||||
echo " release - collect and zip files for release (triggers 'update' build)"
|
echo " release - collect and zip files for release (triggers 'update' build)"
|
||||||
|
@ -200,7 +200,7 @@ LOCATE COMP "usb_miosi[6]" SITE "14" ;
|
|||||||
LOCATE COMP "usb_miosi[7]" SITE "13" ;
|
LOCATE COMP "usb_miosi[7]" SITE "13" ;
|
||||||
LOCATE COMP "usb_miso" SITE "10" ;
|
LOCATE COMP "usb_miso" SITE "10" ;
|
||||||
LOCATE COMP "usb_pwrsav" SITE "2" ;
|
LOCATE COMP "usb_pwrsav" SITE "2" ;
|
||||||
SYSCONFIG SDM_PORT=DISABLE ;
|
SYSCONFIG SDM_PORT=DISABLE I2C_PORT=ENABLE ;
|
||||||
VOLTAGE 3.300 V;
|
VOLTAGE 3.300 V;
|
||||||
FREQUENCY NET "clk" 100.000000 MHz PAR_ADJ 10.000000 ;
|
FREQUENCY NET "clk" 100.000000 MHz PAR_ADJ 10.000000 ;
|
||||||
BLOCK PATH TO PORT "mcu_int" ;
|
BLOCK PATH TO PORT "mcu_int" ;
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
.set noat
|
.set noat
|
||||||
.set noreorder
|
.set noreorder
|
||||||
|
|
||||||
|
|
||||||
.section .data.ipl2
|
.section .data.ipl2
|
||||||
ipl2:
|
ipl2:
|
||||||
.global ipl2
|
.global ipl2
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
MEMORY {
|
MEMORY {
|
||||||
loader (rx) : org = 0x08000000, len = 4k
|
loader (rx) : org = 0x08000000, len = 4k
|
||||||
rom (rx) : org = 0x08001000, len = 28k
|
code (rx) : org = 0x08001000, len = 28k
|
||||||
ram (rwx) : org = 0x20000000, len = 8k
|
ram (rwx) : org = 0x20000000, len = 8k
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -17,7 +17,7 @@ SECTIONS {
|
|||||||
. = ALIGN(4);
|
. = ALIGN(4);
|
||||||
KEEP(*(.isr_vector))
|
KEEP(*(.isr_vector))
|
||||||
. = ALIGN(4);
|
. = ALIGN(4);
|
||||||
} > rom
|
} > code
|
||||||
|
|
||||||
.text : {
|
.text : {
|
||||||
. = ALIGN(4);
|
. = ALIGN(4);
|
||||||
@ -27,18 +27,16 @@ SECTIONS {
|
|||||||
*(.glue_7t)
|
*(.glue_7t)
|
||||||
. = ALIGN(4);
|
. = ALIGN(4);
|
||||||
_etext = .;
|
_etext = .;
|
||||||
} > rom
|
} > code
|
||||||
|
|
||||||
.bss : {
|
.bss : {
|
||||||
. = ALIGN(4);
|
. = ALIGN(4);
|
||||||
_sbss = .;
|
_sbss = .;
|
||||||
__bss_start__ = _sbss;
|
|
||||||
*(.bss)
|
*(.bss)
|
||||||
*(.bss*)
|
*(.bss*)
|
||||||
*(COMMON)
|
*(COMMON)
|
||||||
. = ALIGN(4);
|
. = ALIGN(4);
|
||||||
_ebss = .;
|
_ebss = .;
|
||||||
__bss_end__ = _ebss;
|
|
||||||
} > ram
|
} > ram
|
||||||
|
|
||||||
.data : {
|
.data : {
|
||||||
@ -49,14 +47,14 @@ SECTIONS {
|
|||||||
*(.data*)
|
*(.data*)
|
||||||
. = ALIGN(4);
|
. = ALIGN(4);
|
||||||
_edata = .;
|
_edata = .;
|
||||||
} > ram AT > rom
|
} > ram AT > code
|
||||||
|
|
||||||
.rodata : {
|
.rodata : {
|
||||||
. = ALIGN(4);
|
. = ALIGN(4);
|
||||||
*(.rodata)
|
*(.rodata)
|
||||||
*(.rodata*)
|
*(.rodata*)
|
||||||
. = ALIGN(4);
|
. = ALIGN(4);
|
||||||
} > rom
|
} > code
|
||||||
|
|
||||||
_estack = ORIGIN(ram) + LENGTH(ram);
|
_estack = ORIGIN(ram) + LENGTH(ram);
|
||||||
}
|
}
|
||||||
|
@ -1,6 +1,9 @@
|
|||||||
EXE_NAME = app
|
EXE_NAME = app
|
||||||
LD_SCRIPT = app.ld
|
|
||||||
BUILD_DIR = build/app
|
BUILD_DIR = build/app
|
||||||
|
|
||||||
|
LD_SCRIPT = app.ld
|
||||||
|
PAD_TO = 0x08008000
|
||||||
|
|
||||||
SRC_FILES = \
|
SRC_FILES = \
|
||||||
app.S \
|
app.S \
|
||||||
app.c \
|
app.c \
|
||||||
@ -24,7 +27,6 @@ SRC_FILES = \
|
|||||||
update.c \
|
update.c \
|
||||||
usb.c \
|
usb.c \
|
||||||
writeback.c
|
writeback.c
|
||||||
PAD_TO = 0x08008000
|
|
||||||
|
|
||||||
include common.mk
|
include common.mk
|
||||||
|
|
||||||
|
@ -4,10 +4,12 @@ set -e
|
|||||||
|
|
||||||
case "$1" in
|
case "$1" in
|
||||||
all)
|
all)
|
||||||
|
make all -j -f primer.mk USER_FLAGS="$USER_FLAGS"
|
||||||
make all -j -f loader.mk USER_FLAGS="$USER_FLAGS"
|
make all -j -f loader.mk USER_FLAGS="$USER_FLAGS"
|
||||||
make all -j -f app.mk USER_FLAGS="$USER_FLAGS"
|
make all -j -f app.mk USER_FLAGS="$USER_FLAGS"
|
||||||
;;
|
;;
|
||||||
clean)
|
clean)
|
||||||
|
make clean -f primer.mk
|
||||||
make clean -f loader.mk
|
make clean -f loader.mk
|
||||||
make clean -f app.mk
|
make clean -f app.mk
|
||||||
;;
|
;;
|
||||||
|
@ -14,7 +14,6 @@ SRC_DIR = src
|
|||||||
SRCS = $(addprefix $(SRC_DIR)/, $(SRC_FILES))
|
SRCS = $(addprefix $(SRC_DIR)/, $(SRC_FILES))
|
||||||
OBJS = $(addprefix $(BUILD_DIR)/, $(notdir $(patsubst %,%.o,$(SRCS))))
|
OBJS = $(addprefix $(BUILD_DIR)/, $(notdir $(patsubst %,%.o,$(SRCS))))
|
||||||
DEPS = $(OBJS:.o=.d)
|
DEPS = $(OBJS:.o=.d)
|
||||||
|
|
||||||
VPATH = $(SRC_DIR)
|
VPATH = $(SRC_DIR)
|
||||||
|
|
||||||
$(@info $(shell mkdir -p ./$(BUILD_DIR) &> /dev/null))
|
$(@info $(shell mkdir -p ./$(BUILD_DIR) &> /dev/null))
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
MEMORY {
|
MEMORY {
|
||||||
rom (rx) : org = 0x08000000, len = 4k
|
code (rx) : org = 0x08000000, len = 4k
|
||||||
ram (rwx) : org = 0x20000000, len = 8k
|
ram (rwx) : org = 0x20000000, len = 8k
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -10,13 +10,13 @@ SECTIONS {
|
|||||||
. = ALIGN(4);
|
. = ALIGN(4);
|
||||||
KEEP(*(.isr_vector))
|
KEEP(*(.isr_vector))
|
||||||
. = ALIGN(4);
|
. = ALIGN(4);
|
||||||
} > rom
|
} > code
|
||||||
|
|
||||||
.startup : {
|
.startup : {
|
||||||
. = ALIGN(4);
|
. = ALIGN(4);
|
||||||
*(.text.Reset_Handler)
|
*(.text.Reset_Handler)
|
||||||
. = ALIGN(4);
|
. = ALIGN(4);
|
||||||
} > rom
|
} > code
|
||||||
|
|
||||||
.text : {
|
.text : {
|
||||||
_sitext = LOADADDR(.text);
|
_sitext = LOADADDR(.text);
|
||||||
@ -28,18 +28,16 @@ SECTIONS {
|
|||||||
*(.glue_7t)
|
*(.glue_7t)
|
||||||
. = ALIGN(4);
|
. = ALIGN(4);
|
||||||
_etext = .;
|
_etext = .;
|
||||||
} > ram AT > rom
|
} > ram AT > code
|
||||||
|
|
||||||
.bss : {
|
.bss : {
|
||||||
. = ALIGN(4);
|
. = ALIGN(4);
|
||||||
_sbss = .;
|
_sbss = .;
|
||||||
__bss_start__ = _sbss;
|
|
||||||
*(.bss)
|
*(.bss)
|
||||||
*(.bss*)
|
*(.bss*)
|
||||||
*(COMMON)
|
*(COMMON)
|
||||||
. = ALIGN(4);
|
. = ALIGN(4);
|
||||||
_ebss = .;
|
_ebss = .;
|
||||||
__bss_end__ = _ebss;
|
|
||||||
} > ram
|
} > ram
|
||||||
|
|
||||||
.data : {
|
.data : {
|
||||||
@ -50,7 +48,7 @@ SECTIONS {
|
|||||||
*(.data*)
|
*(.data*)
|
||||||
. = ALIGN(4);
|
. = ALIGN(4);
|
||||||
_edata = .;
|
_edata = .;
|
||||||
} > ram AT > rom
|
} > ram AT > code
|
||||||
|
|
||||||
.rodata : {
|
.rodata : {
|
||||||
_sirodata = LOADADDR(.rodata);
|
_sirodata = LOADADDR(.rodata);
|
||||||
@ -60,9 +58,9 @@ SECTIONS {
|
|||||||
*(.rodata*)
|
*(.rodata*)
|
||||||
. = ALIGN(4);
|
. = ALIGN(4);
|
||||||
_erodata = .;
|
_erodata = .;
|
||||||
} > ram AT > rom
|
} > ram AT > code
|
||||||
|
|
||||||
_app_header = ORIGIN(rom) + LENGTH(rom);
|
_app_header = ORIGIN(code) + LENGTH(code);
|
||||||
_app_magic = _app_header + 16;
|
_app_magic = _app_header + 16;
|
||||||
_estack = ORIGIN(ram) + LENGTH(ram);
|
_estack = ORIGIN(ram) + LENGTH(ram);
|
||||||
}
|
}
|
||||||
|
@ -1,6 +1,9 @@
|
|||||||
EXE_NAME = loader
|
EXE_NAME = loader
|
||||||
LD_SCRIPT = loader.ld
|
|
||||||
BUILD_DIR = build/loader
|
BUILD_DIR = build/loader
|
||||||
|
|
||||||
|
LD_SCRIPT = loader.ld
|
||||||
|
PAD_TO = 0x08001000
|
||||||
|
|
||||||
SRC_FILES = \
|
SRC_FILES = \
|
||||||
loader.S \
|
loader.S \
|
||||||
flash.c \
|
flash.c \
|
||||||
@ -9,6 +12,5 @@ SRC_FILES = \
|
|||||||
lcmxo2.c \
|
lcmxo2.c \
|
||||||
loader.c \
|
loader.c \
|
||||||
update.c
|
update.c
|
||||||
PAD_TO = 0x08001000
|
|
||||||
|
|
||||||
include common.mk
|
include common.mk
|
||||||
|
50
sw/controller/primer.ld
Normal file
50
sw/controller/primer.ld
Normal file
@ -0,0 +1,50 @@
|
|||||||
|
MEMORY {
|
||||||
|
ram (rwx) : org = 0x20000000, len = 4k
|
||||||
|
code (rwx) : org = 0x20001000, len = 4k
|
||||||
|
}
|
||||||
|
|
||||||
|
ENTRY(Reset_Handler)
|
||||||
|
|
||||||
|
SECTIONS {
|
||||||
|
.isr_vector : {
|
||||||
|
. = ALIGN(4);
|
||||||
|
_header = .;
|
||||||
|
KEEP(*(.isr_vector))
|
||||||
|
. = ALIGN(4);
|
||||||
|
} > code
|
||||||
|
|
||||||
|
.text : {
|
||||||
|
. = ALIGN(4);
|
||||||
|
*(.text)
|
||||||
|
*(.text*)
|
||||||
|
*(.glue_7)
|
||||||
|
*(.glue_7t)
|
||||||
|
. = ALIGN(4);
|
||||||
|
} > code
|
||||||
|
|
||||||
|
.bss : {
|
||||||
|
. = ALIGN(4);
|
||||||
|
_sbss = .;
|
||||||
|
*(.bss)
|
||||||
|
*(.bss*)
|
||||||
|
*(COMMON)
|
||||||
|
. = ALIGN(4);
|
||||||
|
_ebss = .;
|
||||||
|
} > ram
|
||||||
|
|
||||||
|
.data : {
|
||||||
|
. = ALIGN(4);
|
||||||
|
*(.data)
|
||||||
|
*(.data*)
|
||||||
|
. = ALIGN(4);
|
||||||
|
} > code
|
||||||
|
|
||||||
|
.rodata : {
|
||||||
|
. = ALIGN(4);
|
||||||
|
*(.rodata)
|
||||||
|
*(.rodata*)
|
||||||
|
. = ALIGN(4);
|
||||||
|
} > code
|
||||||
|
|
||||||
|
_estack = ORIGIN(ram) + LENGTH(ram);
|
||||||
|
}
|
16
sw/controller/primer.mk
Normal file
16
sw/controller/primer.mk
Normal file
@ -0,0 +1,16 @@
|
|||||||
|
EXE_NAME = primer
|
||||||
|
BUILD_DIR = build/primer
|
||||||
|
|
||||||
|
LD_SCRIPT = primer.ld
|
||||||
|
PAD_TO = 0x20002000
|
||||||
|
|
||||||
|
SRC_FILES = \
|
||||||
|
primer.S \
|
||||||
|
fpga.c \
|
||||||
|
hw.c \
|
||||||
|
lcmxo2.c \
|
||||||
|
primer.c
|
||||||
|
|
||||||
|
include common.mk
|
||||||
|
|
||||||
|
FLAGS += -DLCMXO2_I2C
|
@ -3,6 +3,7 @@
|
|||||||
.fpu softvfp
|
.fpu softvfp
|
||||||
.thumb
|
.thumb
|
||||||
|
|
||||||
|
|
||||||
.section .loader, "a", %progbits
|
.section .loader, "a", %progbits
|
||||||
.type loader, %object
|
.type loader, %object
|
||||||
loader:
|
loader:
|
||||||
@ -13,7 +14,6 @@ loader:
|
|||||||
.type Reset_Handler, %function
|
.type Reset_Handler, %function
|
||||||
Reset_Handler:
|
Reset_Handler:
|
||||||
.global Reset_Handler
|
.global Reset_Handler
|
||||||
cpsid i
|
|
||||||
|
|
||||||
init_data:
|
init_data:
|
||||||
ldr r0, =_sdata
|
ldr r0, =_sdata
|
||||||
|
@ -1,7 +1,11 @@
|
|||||||
|
#include <stddef.h>
|
||||||
#include <stm32g0xx.h>
|
#include <stm32g0xx.h>
|
||||||
#include "hw.h"
|
#include "hw.h"
|
||||||
|
|
||||||
|
|
||||||
|
#define UART_BAUD (115200)
|
||||||
|
|
||||||
|
|
||||||
typedef enum {
|
typedef enum {
|
||||||
GPIO_INPUT = 0b00,
|
GPIO_INPUT = 0b00,
|
||||||
GPIO_OUTPUT = 0b01,
|
GPIO_OUTPUT = 0b01,
|
||||||
@ -108,6 +112,13 @@ void hw_gpio_reset (gpio_id_t id) {
|
|||||||
gpio->BSRR = (GPIO_BSRR_BR0 << pin);
|
gpio->BSRR = (GPIO_BSRR_BR0 << pin);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void hw_uart_read (uint8_t *data, int length) {
|
||||||
|
for (int i = 0; i < length; i++) {
|
||||||
|
while (!(USART1->ISR & USART_ISR_RXNE_RXFNE));
|
||||||
|
*data++ = (uint8_t) (USART1->RDR);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void hw_uart_write (uint8_t *data, int length) {
|
void hw_uart_write (uint8_t *data, int length) {
|
||||||
for (int i = 0; i < length; i++) {
|
for (int i = 0; i < length; i++) {
|
||||||
while (!(USART1->ISR & USART_ISR_TXE_TXFNF));
|
while (!(USART1->ISR & USART_ISR_TXE_TXFNF));
|
||||||
@ -181,7 +192,30 @@ void hw_i2c_write (uint8_t i2c_address, uint8_t address, uint8_t *data, uint8_t
|
|||||||
}
|
}
|
||||||
|
|
||||||
uint32_t hw_i2c_get_error (void) {
|
uint32_t hw_i2c_get_error (void) {
|
||||||
return I2C1->ISR & I2C_ISR_NACKF;
|
return (I2C1->ISR & I2C_ISR_NACKF);
|
||||||
|
}
|
||||||
|
|
||||||
|
void hw_i2c_raw (uint8_t i2c_address, uint8_t *data, int length, i2c_type_t type) {
|
||||||
|
if (type & I2C_START) {
|
||||||
|
I2C1->ICR = I2C_ICR_NACKCF;
|
||||||
|
}
|
||||||
|
I2C1->CR2 = (
|
||||||
|
((type & I2C_AUTOEND) ? I2C_CR2_AUTOEND : 0) |
|
||||||
|
(length << I2C_CR2_NBYTES_Pos) |
|
||||||
|
((type & I2C_STOP) ? I2C_CR2_STOP : 0) |
|
||||||
|
((type & I2C_START) ? I2C_CR2_START : 0) |
|
||||||
|
((type & I2C_READ) ? I2C_CR2_RD_WRN : 0) |
|
||||||
|
(i2c_address << I2C_CR2_SADD_Pos)
|
||||||
|
);
|
||||||
|
for (int i = 0; i < length; i++) {
|
||||||
|
if (type & I2C_READ) {
|
||||||
|
while (!(I2C1->ISR & I2C_ISR_RXNE));
|
||||||
|
*data++ = I2C1->RXDR;
|
||||||
|
} else if (type & I2C_WRITE) {
|
||||||
|
while (!(I2C1->ISR & I2C_ISR_TXE));
|
||||||
|
I2C1->TXDR = *data++;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void hw_i2c_disable_irq (void) {
|
void hw_i2c_disable_irq (void) {
|
||||||
@ -311,16 +345,18 @@ hw_flash_t hw_flash_read (uint32_t offset) {
|
|||||||
return *(uint64_t *) (FLASH_BASE + offset);
|
return *(uint64_t *) (FLASH_BASE + offset);
|
||||||
}
|
}
|
||||||
|
|
||||||
void hw_loader_reset (loader_parameters_t *parameters) {
|
void hw_reset (loader_parameters_t *parameters) {
|
||||||
RCC->APBENR1 |= RCC_APBENR1_PWREN | RCC_APBENR1_RTCAPBEN;
|
if (parameters != NULL) {
|
||||||
PWR->CR1 |= PWR_CR1_DBP;
|
RCC->APBENR1 |= RCC_APBENR1_PWREN | RCC_APBENR1_RTCAPBEN;
|
||||||
TAMP->BKP0R = parameters->magic;
|
PWR->CR1 |= PWR_CR1_DBP;
|
||||||
TAMP->BKP1R = parameters->flags;
|
TAMP->BKP0R = parameters->magic;
|
||||||
TAMP->BKP2R = parameters->mcu_address;
|
TAMP->BKP1R = parameters->flags;
|
||||||
TAMP->BKP3R = parameters->fpga_address;
|
TAMP->BKP2R = parameters->mcu_address;
|
||||||
TAMP->BKP4R = parameters->bootloader_address;
|
TAMP->BKP3R = parameters->fpga_address;
|
||||||
PWR->CR1 &= ~(PWR_CR1_DBP);
|
TAMP->BKP4R = parameters->bootloader_address;
|
||||||
RCC->APBENR1 &= ~(RCC_APBENR1_PWREN | RCC_APBENR1_RTCAPBEN);
|
PWR->CR1 &= ~(PWR_CR1_DBP);
|
||||||
|
RCC->APBENR1 &= ~(RCC_APBENR1_PWREN | RCC_APBENR1_RTCAPBEN);
|
||||||
|
}
|
||||||
NVIC_SystemReset();
|
NVIC_SystemReset();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -397,7 +433,6 @@ static void hw_init_spi (void) {
|
|||||||
hw_gpio_init(GPIO_ID_SPI_CLK, GPIO_ALT, GPIO_PP, GPIO_SPEED_HIGH, GPIO_PULL_NONE, GPIO_AF_0, 0);
|
hw_gpio_init(GPIO_ID_SPI_CLK, GPIO_ALT, GPIO_PP, GPIO_SPEED_HIGH, GPIO_PULL_NONE, GPIO_AF_0, 0);
|
||||||
hw_gpio_init(GPIO_ID_SPI_MISO, GPIO_ALT, GPIO_PP, GPIO_SPEED_HIGH, GPIO_PULL_DOWN, GPIO_AF_0, 0);
|
hw_gpio_init(GPIO_ID_SPI_MISO, GPIO_ALT, GPIO_PP, GPIO_SPEED_HIGH, GPIO_PULL_DOWN, GPIO_AF_0, 0);
|
||||||
hw_gpio_init(GPIO_ID_SPI_MOSI, GPIO_ALT, GPIO_PP, GPIO_SPEED_HIGH, GPIO_PULL_NONE, GPIO_AF_0, 0);
|
hw_gpio_init(GPIO_ID_SPI_MOSI, GPIO_ALT, GPIO_PP, GPIO_SPEED_HIGH, GPIO_PULL_NONE, GPIO_AF_0, 0);
|
||||||
hw_gpio_init(GPIO_ID_FPGA_INT, GPIO_INPUT, GPIO_PP, GPIO_SPEED_VLOW, GPIO_PULL_UP, GPIO_AF_0, 0);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void hw_init_i2c (void) {
|
static void hw_init_i2c (void) {
|
||||||
@ -408,7 +443,6 @@ static void hw_init_i2c (void) {
|
|||||||
|
|
||||||
hw_gpio_init(GPIO_ID_I2C_SCL, GPIO_ALT, GPIO_OD, GPIO_SPEED_VLOW, GPIO_PULL_NONE, GPIO_AF_6, 0);
|
hw_gpio_init(GPIO_ID_I2C_SCL, GPIO_ALT, GPIO_OD, GPIO_SPEED_VLOW, GPIO_PULL_NONE, GPIO_AF_6, 0);
|
||||||
hw_gpio_init(GPIO_ID_I2C_SDA, GPIO_ALT, GPIO_OD, GPIO_SPEED_VLOW, GPIO_PULL_NONE, GPIO_AF_6, 0);
|
hw_gpio_init(GPIO_ID_I2C_SDA, GPIO_ALT, GPIO_OD, GPIO_SPEED_VLOW, GPIO_PULL_NONE, GPIO_AF_6, 0);
|
||||||
hw_gpio_init(GPIO_ID_RTC_MFP, GPIO_INPUT, GPIO_PP, GPIO_SPEED_VLOW, GPIO_PULL_UP, GPIO_AF_0, 0);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void hw_init_uart (void) {
|
static void hw_init_uart (void) {
|
||||||
@ -416,11 +450,12 @@ static void hw_init_uart (void) {
|
|||||||
|
|
||||||
SYSCFG->CFGR1 |= (SYSCFG_CFGR1_PA12_RMP | SYSCFG_CFGR1_PA11_RMP);
|
SYSCFG->CFGR1 |= (SYSCFG_CFGR1_PA12_RMP | SYSCFG_CFGR1_PA11_RMP);
|
||||||
|
|
||||||
USART1->BRR = (64000000UL) / 1000000;
|
|
||||||
USART1->CR1 = USART_CR1_FIFOEN | USART_CR1_TE | USART_CR1_UE;
|
|
||||||
|
|
||||||
hw_gpio_init(GPIO_ID_UART_TX, GPIO_ALT, GPIO_PP, GPIO_SPEED_LOW, GPIO_PULL_NONE, GPIO_AF_1, 0);
|
hw_gpio_init(GPIO_ID_UART_TX, GPIO_ALT, GPIO_PP, GPIO_SPEED_LOW, GPIO_PULL_NONE, GPIO_AF_1, 0);
|
||||||
hw_gpio_init(GPIO_ID_UART_RX, GPIO_ALT, GPIO_PP, GPIO_SPEED_LOW, GPIO_PULL_NONE, GPIO_AF_1, 0);
|
hw_gpio_init(GPIO_ID_UART_RX, GPIO_ALT, GPIO_PP, GPIO_SPEED_LOW, GPIO_PULL_UP, GPIO_AF_1, 0);
|
||||||
|
|
||||||
|
USART1->BRR = (64000000UL) / UART_BAUD;
|
||||||
|
USART1->CR1 = USART_CR1_FIFOEN | USART_CR1_M0 | USART_CR1_PCE | USART_CR1_TE | USART_CR1_RE | USART_CR1_UE;
|
||||||
|
USART1->RQR = USART_RQR_TXFRQ | USART_RQR_RXFRQ;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void hw_init_tim (void) {
|
static void hw_init_tim (void) {
|
||||||
@ -445,14 +480,22 @@ static void hw_init_tim (void) {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void hw_init_misc (void) {
|
static void hw_init_crc (void) {
|
||||||
RCC->AHBENR |= RCC_AHBENR_CRCEN;
|
RCC->AHBENR |= RCC_AHBENR_CRCEN;
|
||||||
|
|
||||||
CRC->CR = (CRC_CR_REV_OUT | CRC_CR_REV_IN_0);
|
CRC->CR = (CRC_CR_REV_OUT | CRC_CR_REV_IN_0);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void hw_init_misc (void) {
|
||||||
hw_gpio_init(GPIO_ID_N64_RESET, GPIO_INPUT, GPIO_PP, GPIO_SPEED_VLOW, GPIO_PULL_DOWN, GPIO_AF_0, 0);
|
hw_gpio_init(GPIO_ID_N64_RESET, GPIO_INPUT, GPIO_PP, GPIO_SPEED_VLOW, GPIO_PULL_DOWN, GPIO_AF_0, 0);
|
||||||
hw_gpio_init(GPIO_ID_N64_CIC_CLK, GPIO_INPUT, GPIO_PP, GPIO_SPEED_VLOW, GPIO_PULL_DOWN, GPIO_AF_0, 0);
|
hw_gpio_init(GPIO_ID_N64_CIC_CLK, GPIO_INPUT, GPIO_PP, GPIO_SPEED_VLOW, GPIO_PULL_DOWN, GPIO_AF_0, 0);
|
||||||
hw_gpio_init(GPIO_ID_N64_CIC_DQ, GPIO_OUTPUT, GPIO_OD, GPIO_SPEED_VLOW, GPIO_PULL_UP, GPIO_AF_0, 1);
|
hw_gpio_init(GPIO_ID_N64_CIC_DQ, GPIO_OUTPUT, GPIO_OD, GPIO_SPEED_VLOW, GPIO_PULL_UP, GPIO_AF_0, 1);
|
||||||
|
hw_gpio_init(GPIO_ID_FPGA_INT, GPIO_INPUT, GPIO_PP, GPIO_SPEED_VLOW, GPIO_PULL_UP, GPIO_AF_0, 0);
|
||||||
|
hw_gpio_init(GPIO_ID_RTC_MFP, GPIO_INPUT, GPIO_PP, GPIO_SPEED_VLOW, GPIO_PULL_UP, GPIO_AF_0, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
void hw_set_vector_table (uint32_t offset) {
|
||||||
|
SCB->VTOR = (__IOM uint32_t) (offset);
|
||||||
}
|
}
|
||||||
|
|
||||||
void hw_init (void) {
|
void hw_init (void) {
|
||||||
@ -461,6 +504,7 @@ void hw_init (void) {
|
|||||||
hw_init_i2c();
|
hw_init_i2c();
|
||||||
hw_init_uart();
|
hw_init_uart();
|
||||||
hw_init_tim();
|
hw_init_tim();
|
||||||
|
hw_init_crc();
|
||||||
hw_init_misc();
|
hw_init_misc();
|
||||||
|
|
||||||
NVIC_SetPriority(EXTI0_1_IRQn, 0);
|
NVIC_SetPriority(EXTI0_1_IRQn, 0);
|
||||||
@ -489,6 +533,14 @@ void hw_loader_init (void) {
|
|||||||
hw_init_spi();
|
hw_init_spi();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void hw_primer_init (void) {
|
||||||
|
hw_init_mcu();
|
||||||
|
hw_init_spi();
|
||||||
|
hw_init_i2c();
|
||||||
|
hw_init_uart();
|
||||||
|
hw_init_crc();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
void EXTI0_1_IRQHandler (void) {
|
void EXTI0_1_IRQHandler (void) {
|
||||||
for (int i = 0; i <= 1; i++) {
|
for (int i = 0; i <= 1; i++) {
|
||||||
|
@ -29,6 +29,14 @@ typedef enum {
|
|||||||
GPIO_IRQ_RISING = 0b10,
|
GPIO_IRQ_RISING = 0b10,
|
||||||
} gpio_irq_t;
|
} gpio_irq_t;
|
||||||
|
|
||||||
|
typedef enum {
|
||||||
|
I2C_START = (1 << 0),
|
||||||
|
I2C_AUTOEND = (1 << 1),
|
||||||
|
I2C_STOP = (1 << 2),
|
||||||
|
I2C_READ = (1 << 3),
|
||||||
|
I2C_WRITE = (1 << 4),
|
||||||
|
} i2c_type_t;
|
||||||
|
|
||||||
typedef enum {
|
typedef enum {
|
||||||
TIM_ID_CIC = 0,
|
TIM_ID_CIC = 0,
|
||||||
TIM_ID_RTC = 1,
|
TIM_ID_RTC = 1,
|
||||||
@ -63,6 +71,7 @@ void hw_gpio_irq_setup (gpio_id_t id, gpio_irq_t irq, void (*callback)(void));
|
|||||||
uint32_t hw_gpio_get (gpio_id_t id);
|
uint32_t hw_gpio_get (gpio_id_t id);
|
||||||
void hw_gpio_set (gpio_id_t id);
|
void hw_gpio_set (gpio_id_t id);
|
||||||
void hw_gpio_reset (gpio_id_t id);
|
void hw_gpio_reset (gpio_id_t id);
|
||||||
|
void hw_uart_read (uint8_t *data, int length);
|
||||||
void hw_uart_write (uint8_t *data, int length);
|
void hw_uart_write (uint8_t *data, int length);
|
||||||
void hw_spi_start (void);
|
void hw_spi_start (void);
|
||||||
void hw_spi_stop (void);
|
void hw_spi_stop (void);
|
||||||
@ -70,6 +79,7 @@ void hw_spi_trx (uint8_t *data, int length, spi_direction_t direction);
|
|||||||
void hw_i2c_read (uint8_t i2c_address, uint8_t address, uint8_t *data, uint8_t length, void (*callback)(void));
|
void hw_i2c_read (uint8_t i2c_address, uint8_t address, uint8_t *data, uint8_t length, void (*callback)(void));
|
||||||
void hw_i2c_write (uint8_t i2c_address, uint8_t address, uint8_t *data, uint8_t length, void (*callback)(void));
|
void hw_i2c_write (uint8_t i2c_address, uint8_t address, uint8_t *data, uint8_t length, void (*callback)(void));
|
||||||
uint32_t hw_i2c_get_error (void);
|
uint32_t hw_i2c_get_error (void);
|
||||||
|
void hw_i2c_raw (uint8_t i2c_address, uint8_t *data, int length, i2c_type_t type);
|
||||||
void hw_i2c_disable_irq (void);
|
void hw_i2c_disable_irq (void);
|
||||||
void hw_i2c_enable_irq (void);
|
void hw_i2c_enable_irq (void);
|
||||||
void hw_tim_setup (tim_id_t id, uint16_t delay, void (*callback)(void));
|
void hw_tim_setup (tim_id_t id, uint16_t delay, void (*callback)(void));
|
||||||
@ -83,10 +93,12 @@ uint32_t hw_flash_size (void);
|
|||||||
void hw_flash_erase (void);
|
void hw_flash_erase (void);
|
||||||
void hw_flash_program (uint32_t offset, hw_flash_t value);
|
void hw_flash_program (uint32_t offset, hw_flash_t value);
|
||||||
hw_flash_t hw_flash_read (uint32_t offset);
|
hw_flash_t hw_flash_read (uint32_t offset);
|
||||||
void hw_loader_reset (loader_parameters_t *parameters);
|
void hw_reset (loader_parameters_t *parameters);
|
||||||
void hw_loader_get_parameters (loader_parameters_t *parameters);
|
void hw_loader_get_parameters (loader_parameters_t *parameters);
|
||||||
|
void hw_set_vector_table (uint32_t offset);
|
||||||
void hw_init (void);
|
void hw_init (void);
|
||||||
void hw_loader_init (void);
|
void hw_loader_init (void);
|
||||||
|
void hw_primer_init (void);
|
||||||
|
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
@ -1,253 +1,451 @@
|
|||||||
#include <stdbool.h>
|
#include <stdbool.h>
|
||||||
#include "fpga.h"
|
#include "fpga.h"
|
||||||
#include "vendor.h"
|
#include "hw.h"
|
||||||
|
#include "vendor.h"
|
||||||
|
|
||||||
#define VENDOR_SCR_START (1 << 0)
|
|
||||||
#define VENDOR_SCR_BUSY (1 << 0)
|
#define VENDOR_SCR_START (1 << 0)
|
||||||
#define VENDOR_SCR_WRITE (1 << 1)
|
#define VENDOR_SCR_BUSY (1 << 0)
|
||||||
#define VENDOR_SCR_LENGTH_BIT (2)
|
#define VENDOR_SCR_WRITE (1 << 1)
|
||||||
#define VENDOR_SCR_DELAY (1 << 4)
|
#define VENDOR_SCR_LENGTH_BIT (2)
|
||||||
#define VENDOR_SCR_ADDRESS_BIT (8)
|
#define VENDOR_SCR_DELAY (1 << 4)
|
||||||
|
#define VENDOR_SCR_ADDRESS_BIT (8)
|
||||||
#define LCMXO2_CFGCR (0x70)
|
|
||||||
#define LCMXO2_CFGTXDR (0x71)
|
#define LCMXO2_I2C_ADDR_CFG (0x80)
|
||||||
#define LCMXO2_CFGRXDR (0x73)
|
#define LCMXO2_I2C_ADDR_RESET (0x86)
|
||||||
|
|
||||||
#define CFGCR_RSTE (1 << 6)
|
#define LCMXO2_CFGCR (0x70)
|
||||||
#define CFGCR_WBCE (1 << 7)
|
#define LCMXO2_CFGTXDR (0x71)
|
||||||
|
#define LCMXO2_CFGRXDR (0x73)
|
||||||
#define ISC_ERASE (0x0E)
|
|
||||||
#define ISC_DISABLE (0x26)
|
#define CFGCR_RSTE (1 << 6)
|
||||||
#define LSC_READ_STATUS (0x3C)
|
#define CFGCR_WBCE (1 << 7)
|
||||||
#define LSC_INIT_ADDRESS (0x46)
|
|
||||||
#define ISC_PROGRAM_DONE (0x5E)
|
#define ISC_ERASE (0x0E)
|
||||||
#define LSC_PROG_INCR_NV (0x70)
|
#define ISC_DISABLE (0x26)
|
||||||
#define LSC_READ_INCR_NV (0x73)
|
#define LSC_READ_STATUS (0x3C)
|
||||||
#define ISC_ENABLE_X (0x74)
|
#define LSC_INIT_ADDRESS (0x46)
|
||||||
#define LSC_REFRESH (0x79)
|
#define ISC_PROGRAM_DONE (0x5E)
|
||||||
#define ISC_NOOP (0xFF)
|
#define LSC_PROG_INCR_NV (0x70)
|
||||||
|
#define LSC_READ_INCR_NV (0x73)
|
||||||
#define ISC_ERASE_CFG (1 << 18)
|
#define ISC_ENABLE_X (0x74)
|
||||||
#define ISC_ERASE_UFM (1 << 19)
|
#define LSC_REFRESH (0x79)
|
||||||
|
#define ISC_ENABLE (0xC6)
|
||||||
#define LSC_STATUS_1_BUSY (1 << 4)
|
#define IDCODE_PUB (0xE0)
|
||||||
#define LSC_STATUS_1_FAIL (1 << 5)
|
#define LSC_PROG_FEABITS (0xF8)
|
||||||
|
#define LSC_READ_FEABITS (0xFB)
|
||||||
#define FLASH_PAGE_SIZE (16)
|
#define ISC_NOOP (0xFF)
|
||||||
#define FLASH_NUM_PAGES (11260)
|
|
||||||
|
#define ISC_ERASE_FEATURE (1 << 17)
|
||||||
|
#define ISC_ERASE_CFG (1 << 18)
|
||||||
typedef enum {
|
#define ISC_ERASE_UFM (1 << 19)
|
||||||
CMD_NORMAL,
|
|
||||||
CMD_DELAYED,
|
#define LSC_STATUS_1_BUSY (1 << 4)
|
||||||
CMD_TWO_OP,
|
#define LSC_STATUS_1_FAIL (1 << 5)
|
||||||
} cmd_type_t;
|
|
||||||
|
#define DEVICE_ID_SIZE (4)
|
||||||
|
|
||||||
static void lcmxo2_reg_set (uint8_t reg, uint8_t value) {
|
#define FLASH_PAGE_SIZE (16)
|
||||||
fpga_reg_set(REG_VENDOR_DATA, value << 24);
|
#define FLASH_NUM_PAGES (11260)
|
||||||
fpga_reg_set(REG_VENDOR_SCR,
|
|
||||||
(reg << VENDOR_SCR_ADDRESS_BIT) |
|
#define FEATBITS_SIZE (2)
|
||||||
(0 << VENDOR_SCR_LENGTH_BIT) |
|
|
||||||
VENDOR_SCR_WRITE |
|
|
||||||
VENDOR_SCR_START
|
typedef enum {
|
||||||
);
|
CMD_NORMAL,
|
||||||
while (fpga_reg_get(REG_VENDOR_SCR) & VENDOR_SCR_BUSY);
|
CMD_DELAYED,
|
||||||
}
|
CMD_TWO_OP,
|
||||||
|
} cmd_type_t;
|
||||||
static void lcmxo2_reset_bus (void) {
|
|
||||||
lcmxo2_reg_set(LCMXO2_CFGCR, CFGCR_RSTE);
|
|
||||||
lcmxo2_reg_set(LCMXO2_CFGCR, 0);
|
#ifndef LCMXO2_I2C
|
||||||
}
|
static void lcmxo2_reg_set (uint8_t reg, uint8_t value) {
|
||||||
|
fpga_reg_set(REG_VENDOR_DATA, value << 24);
|
||||||
static void lcmxo2_execute_cmd (uint8_t cmd, uint32_t arg, cmd_type_t type) {
|
fpga_reg_set(REG_VENDOR_SCR,
|
||||||
lcmxo2_reg_set(LCMXO2_CFGCR, 0);
|
(reg << VENDOR_SCR_ADDRESS_BIT) |
|
||||||
uint32_t data = (cmd << 24) | (arg & 0x00FFFFFF);
|
(0 << VENDOR_SCR_LENGTH_BIT) |
|
||||||
lcmxo2_reg_set(LCMXO2_CFGCR, CFGCR_WBCE);
|
VENDOR_SCR_WRITE |
|
||||||
fpga_reg_set(REG_VENDOR_DATA, data);
|
VENDOR_SCR_START
|
||||||
fpga_reg_set(REG_VENDOR_SCR,
|
);
|
||||||
(LCMXO2_CFGTXDR << VENDOR_SCR_ADDRESS_BIT) |
|
while (fpga_reg_get(REG_VENDOR_SCR) & VENDOR_SCR_BUSY);
|
||||||
(type == CMD_DELAYED ? VENDOR_SCR_DELAY : 0) |
|
}
|
||||||
((type == CMD_TWO_OP ? 2 : 3) << VENDOR_SCR_LENGTH_BIT) |
|
#endif
|
||||||
VENDOR_SCR_WRITE |
|
|
||||||
VENDOR_SCR_START
|
static void lcmxo2_reset_bus (void) {
|
||||||
);
|
#ifdef LCMXO2_I2C
|
||||||
while (fpga_reg_get(REG_VENDOR_SCR) & VENDOR_SCR_BUSY);
|
uint8_t reset_data = 0;
|
||||||
}
|
hw_i2c_raw(LCMXO2_I2C_ADDR_RESET, &reset_data, sizeof(reset_data), I2C_START | I2C_AUTOEND | I2C_WRITE);
|
||||||
|
#else
|
||||||
static void lcmxo2_cleanup (void) {
|
lcmxo2_reg_set(LCMXO2_CFGCR, CFGCR_RSTE);
|
||||||
lcmxo2_reg_set(LCMXO2_CFGCR, 0);
|
lcmxo2_reg_set(LCMXO2_CFGCR, 0);
|
||||||
}
|
#endif
|
||||||
|
}
|
||||||
static void lcmxo2_read_data (uint8_t *buffer, uint32_t length) {
|
|
||||||
while (length > 0) {
|
static void lcmxo2_execute_cmd (uint8_t cmd, uint32_t arg, cmd_type_t type) {
|
||||||
uint32_t block_size = (length > 4) ? 4 : length;
|
#ifdef LCMXO2_I2C
|
||||||
fpga_reg_set(REG_VENDOR_SCR,
|
uint8_t data[4] = { cmd, ((arg >> 16) & 0xFF), ((arg >> 8) & 0xFF), (arg & 0xFF) };
|
||||||
(LCMXO2_CFGRXDR << VENDOR_SCR_ADDRESS_BIT) |
|
int length = CMD_TWO_OP ? 3 : 4;
|
||||||
((block_size - 1) << VENDOR_SCR_LENGTH_BIT) |
|
hw_i2c_raw(LCMXO2_I2C_ADDR_CFG, data, length, I2C_START | I2C_WRITE);
|
||||||
VENDOR_SCR_START
|
#else
|
||||||
);
|
uint32_t data = (cmd << 24) | (arg & 0x00FFFFFF);
|
||||||
while (fpga_reg_get(REG_VENDOR_SCR) & VENDOR_SCR_BUSY);
|
lcmxo2_reg_set(LCMXO2_CFGCR, CFGCR_WBCE);
|
||||||
uint32_t data = fpga_reg_get(REG_VENDOR_DATA);
|
fpga_reg_set(REG_VENDOR_DATA, data);
|
||||||
data <<= ((4 - block_size) * 8);
|
fpga_reg_set(REG_VENDOR_SCR,
|
||||||
for (int i = 0; i < block_size; i++) {
|
(LCMXO2_CFGTXDR << VENDOR_SCR_ADDRESS_BIT) |
|
||||||
*buffer++ = ((data >> 24) & 0xFF);
|
(type == CMD_DELAYED ? VENDOR_SCR_DELAY : 0) |
|
||||||
data <<= 8;
|
((type == CMD_TWO_OP ? 2 : 3) << VENDOR_SCR_LENGTH_BIT) |
|
||||||
length -= 1;
|
VENDOR_SCR_WRITE |
|
||||||
}
|
VENDOR_SCR_START
|
||||||
}
|
);
|
||||||
}
|
while (fpga_reg_get(REG_VENDOR_SCR) & VENDOR_SCR_BUSY);
|
||||||
|
#endif
|
||||||
static void lcmxo2_write_data (uint8_t *buffer, uint32_t length) {
|
}
|
||||||
while (length > 0) {
|
|
||||||
uint32_t block_size = (length > 4) ? 4 : length;
|
static void lcmxo2_finish_cmd (void) {
|
||||||
uint32_t data = 0;
|
#ifdef LCMXO2_I2C
|
||||||
for (int i = 0; i < block_size; i++) {
|
hw_i2c_raw(LCMXO2_I2C_ADDR_CFG, NULL, 0, I2C_STOP);
|
||||||
data = ((data << 8) | *buffer++);
|
#else
|
||||||
length -= 1;
|
lcmxo2_reg_set(LCMXO2_CFGCR, 0);
|
||||||
}
|
#endif
|
||||||
data <<= ((4 - block_size) * 8);
|
}
|
||||||
fpga_reg_set(REG_VENDOR_DATA, data);
|
|
||||||
fpga_reg_set(REG_VENDOR_SCR,
|
static void lcmxo2_read_data (uint8_t *buffer, uint32_t length) {
|
||||||
(LCMXO2_CFGTXDR << VENDOR_SCR_ADDRESS_BIT) |
|
#ifdef LCMXO2_I2C
|
||||||
((block_size - 1) << VENDOR_SCR_LENGTH_BIT) |
|
hw_i2c_raw(LCMXO2_I2C_ADDR_CFG, buffer, length, I2C_START | I2C_READ);
|
||||||
VENDOR_SCR_WRITE |
|
#else
|
||||||
VENDOR_SCR_START
|
while (length > 0) {
|
||||||
);
|
uint32_t block_size = (length > 4) ? 4 : length;
|
||||||
while (fpga_reg_get(REG_VENDOR_SCR) & VENDOR_SCR_BUSY);
|
fpga_reg_set(REG_VENDOR_SCR,
|
||||||
}
|
(LCMXO2_CFGRXDR << VENDOR_SCR_ADDRESS_BIT) |
|
||||||
}
|
((block_size - 1) << VENDOR_SCR_LENGTH_BIT) |
|
||||||
|
VENDOR_SCR_START
|
||||||
static bool lcmxo2_wait_busy (void) {
|
);
|
||||||
uint8_t status[4];
|
while (fpga_reg_get(REG_VENDOR_SCR) & VENDOR_SCR_BUSY);
|
||||||
do {
|
uint32_t data = fpga_reg_get(REG_VENDOR_DATA);
|
||||||
lcmxo2_execute_cmd(LSC_READ_STATUS, 0, CMD_NORMAL);
|
data <<= ((4 - block_size) * 8);
|
||||||
lcmxo2_read_data(status, 4);
|
for (int i = 0; i < block_size; i++) {
|
||||||
} while(status[2] & LSC_STATUS_1_BUSY);
|
*buffer++ = ((data >> 24) & 0xFF);
|
||||||
return status[2] & LSC_STATUS_1_FAIL;
|
data <<= 8;
|
||||||
}
|
length -= 1;
|
||||||
|
}
|
||||||
static bool lcmxo2_enable_flash (void) {
|
}
|
||||||
lcmxo2_execute_cmd(ISC_ENABLE_X, 0x080000, CMD_NORMAL);
|
#endif
|
||||||
return lcmxo2_wait_busy();
|
}
|
||||||
}
|
|
||||||
|
static void lcmxo2_write_data (uint8_t *buffer, uint32_t length) {
|
||||||
static void lcmxo2_disable_flash (void) {
|
#ifdef LCMXO2_I2C
|
||||||
lcmxo2_wait_busy();
|
hw_i2c_raw(LCMXO2_I2C_ADDR_CFG, buffer, length, I2C_WRITE);
|
||||||
lcmxo2_execute_cmd(ISC_DISABLE, 0, CMD_TWO_OP);
|
#else
|
||||||
lcmxo2_execute_cmd(ISC_NOOP, 0xFFFFFF, CMD_NORMAL);
|
while (length > 0) {
|
||||||
}
|
uint32_t block_size = (length > 4) ? 4 : length;
|
||||||
|
uint32_t data = 0;
|
||||||
static bool lcmxo2_erase_flash (void) {
|
for (int i = 0; i < block_size; i++) {
|
||||||
lcmxo2_execute_cmd(ISC_ERASE, ISC_ERASE_UFM | ISC_ERASE_CFG, CMD_NORMAL);
|
data = ((data << 8) | *buffer++);
|
||||||
return lcmxo2_wait_busy();
|
length -= 1;
|
||||||
}
|
}
|
||||||
|
data <<= ((4 - block_size) * 8);
|
||||||
static void lcmxo2_reset_flash_address (void) {
|
fpga_reg_set(REG_VENDOR_DATA, data);
|
||||||
lcmxo2_execute_cmd(LSC_INIT_ADDRESS, 0, CMD_NORMAL);
|
fpga_reg_set(REG_VENDOR_SCR,
|
||||||
}
|
(LCMXO2_CFGTXDR << VENDOR_SCR_ADDRESS_BIT) |
|
||||||
|
((block_size - 1) << VENDOR_SCR_LENGTH_BIT) |
|
||||||
static bool lcmxo2_write_flash_page (uint8_t *buffer) {
|
VENDOR_SCR_WRITE |
|
||||||
lcmxo2_execute_cmd(LSC_PROG_INCR_NV, 1, CMD_NORMAL);
|
VENDOR_SCR_START
|
||||||
lcmxo2_write_data(buffer, FLASH_PAGE_SIZE);
|
);
|
||||||
return lcmxo2_wait_busy();
|
while (fpga_reg_get(REG_VENDOR_SCR) & VENDOR_SCR_BUSY);
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
static void lcmxo2_read_flash_page (uint8_t *buffer) {
|
}
|
||||||
lcmxo2_execute_cmd(LSC_READ_INCR_NV, 1, CMD_DELAYED);
|
|
||||||
lcmxo2_read_data(buffer, FLASH_PAGE_SIZE);
|
static void lcmxo2_read_device_id (uint8_t *id) {
|
||||||
}
|
lcmxo2_execute_cmd(IDCODE_PUB, 0, CMD_NORMAL);
|
||||||
|
lcmxo2_read_data(id, DEVICE_ID_SIZE);
|
||||||
static void lcmxo2_program_done (void) {
|
lcmxo2_finish_cmd();
|
||||||
lcmxo2_execute_cmd(ISC_PROGRAM_DONE, 0, CMD_NORMAL);
|
}
|
||||||
lcmxo2_wait_busy();
|
|
||||||
}
|
static bool lcmxo2_wait_busy (void) {
|
||||||
|
uint8_t status[4];
|
||||||
static void lcmxo2_refresh (void) {
|
do {
|
||||||
lcmxo2_execute_cmd(LSC_REFRESH, 0, CMD_TWO_OP);
|
lcmxo2_execute_cmd(LSC_READ_STATUS, 0, CMD_NORMAL);
|
||||||
}
|
lcmxo2_read_data(status, 4);
|
||||||
|
lcmxo2_finish_cmd();
|
||||||
static vendor_error_t lcmxo2_fail (vendor_error_t error) {
|
} while(status[2] & LSC_STATUS_1_BUSY);
|
||||||
lcmxo2_disable_flash();
|
return status[2] & LSC_STATUS_1_FAIL;
|
||||||
lcmxo2_cleanup();
|
}
|
||||||
return error;
|
|
||||||
}
|
static bool lcmxo2_enable_flash (void) {
|
||||||
|
#ifdef LCMXO2_I2C
|
||||||
uint32_t vendor_flash_size (void) {
|
lcmxo2_execute_cmd(ISC_ENABLE, 0x080000, CMD_NORMAL);
|
||||||
return (FLASH_PAGE_SIZE * FLASH_NUM_PAGES);
|
#else
|
||||||
}
|
lcmxo2_execute_cmd(ISC_ENABLE_X, 0x080000, CMD_NORMAL);
|
||||||
|
#endif
|
||||||
vendor_error_t vendor_backup (uint32_t address, uint32_t *length) {
|
lcmxo2_finish_cmd();
|
||||||
uint8_t buffer[FLASH_PAGE_SIZE];
|
return lcmxo2_wait_busy();
|
||||||
|
}
|
||||||
*length = 0;
|
|
||||||
|
static void lcmxo2_disable_flash (void) {
|
||||||
lcmxo2_reset_bus();
|
lcmxo2_wait_busy();
|
||||||
if (lcmxo2_enable_flash()) {
|
lcmxo2_execute_cmd(ISC_DISABLE, 0, CMD_TWO_OP);
|
||||||
return lcmxo2_fail(VENDOR_ERROR_INIT);
|
lcmxo2_finish_cmd();
|
||||||
}
|
lcmxo2_execute_cmd(ISC_NOOP, 0xFFFFFF, CMD_NORMAL);
|
||||||
lcmxo2_reset_flash_address();
|
lcmxo2_finish_cmd();
|
||||||
for (int i = 0; i < (FLASH_PAGE_SIZE * FLASH_NUM_PAGES); i += FLASH_PAGE_SIZE) {
|
}
|
||||||
lcmxo2_read_flash_page(buffer);
|
|
||||||
fpga_mem_write(address + i, FLASH_PAGE_SIZE, buffer);
|
static bool lcmxo2_erase_flash (void) {
|
||||||
*length += FLASH_PAGE_SIZE;
|
lcmxo2_execute_cmd(ISC_ERASE, ISC_ERASE_UFM | ISC_ERASE_CFG, CMD_NORMAL);
|
||||||
}
|
lcmxo2_finish_cmd();
|
||||||
lcmxo2_disable_flash();
|
return lcmxo2_wait_busy();
|
||||||
lcmxo2_cleanup();
|
}
|
||||||
|
|
||||||
return VENDOR_OK;
|
static bool lcmxo2_erase_all (void) {
|
||||||
}
|
lcmxo2_execute_cmd(ISC_ERASE, ISC_ERASE_UFM | ISC_ERASE_CFG | ISC_ERASE_FEATURE, CMD_NORMAL);
|
||||||
|
lcmxo2_finish_cmd();
|
||||||
vendor_error_t vendor_update (uint32_t address, uint32_t length) {
|
return lcmxo2_wait_busy();
|
||||||
uint8_t buffer[FLASH_PAGE_SIZE];
|
}
|
||||||
uint8_t verify_buffer[FLASH_PAGE_SIZE];
|
|
||||||
|
static void lcmxo2_reset_flash_address (void) {
|
||||||
if (length == 0) {
|
lcmxo2_execute_cmd(LSC_INIT_ADDRESS, 0, CMD_NORMAL);
|
||||||
return VENDOR_ERROR_ARGS;
|
lcmxo2_finish_cmd();
|
||||||
}
|
}
|
||||||
if ((length % FLASH_PAGE_SIZE) != 0) {
|
|
||||||
return VENDOR_ERROR_ARGS;
|
static bool lcmxo2_write_flash_page (uint8_t *buffer) {
|
||||||
}
|
lcmxo2_execute_cmd(LSC_PROG_INCR_NV, 1, CMD_NORMAL);
|
||||||
if (length > (FLASH_PAGE_SIZE * FLASH_NUM_PAGES)) {
|
lcmxo2_write_data(buffer, FLASH_PAGE_SIZE);
|
||||||
return VENDOR_ERROR_ARGS;
|
lcmxo2_finish_cmd();
|
||||||
}
|
return lcmxo2_wait_busy();
|
||||||
|
}
|
||||||
lcmxo2_reset_bus();
|
|
||||||
if (lcmxo2_enable_flash()) {
|
static void lcmxo2_read_flash_page (uint8_t *buffer) {
|
||||||
return lcmxo2_fail(VENDOR_ERROR_INIT);
|
lcmxo2_execute_cmd(LSC_READ_INCR_NV, 1, CMD_DELAYED);
|
||||||
}
|
lcmxo2_read_data(buffer, FLASH_PAGE_SIZE);
|
||||||
if (lcmxo2_erase_flash()) {
|
lcmxo2_finish_cmd();
|
||||||
return lcmxo2_fail(VENDOR_ERROR_ERASE);
|
}
|
||||||
}
|
|
||||||
lcmxo2_reset_flash_address();
|
static void lcmxo2_program_done (void) {
|
||||||
for (int i = 0; i < length; i += FLASH_PAGE_SIZE) {
|
lcmxo2_execute_cmd(ISC_PROGRAM_DONE, 0, CMD_NORMAL);
|
||||||
fpga_mem_read(address + i, FLASH_PAGE_SIZE, buffer);
|
lcmxo2_finish_cmd();
|
||||||
if (lcmxo2_write_flash_page(buffer)) {
|
lcmxo2_wait_busy();
|
||||||
return lcmxo2_fail(VENDOR_ERROR_PROGRAM);
|
}
|
||||||
}
|
|
||||||
}
|
static void lcmxo2_write_featbits (uint8_t *buffer) {
|
||||||
lcmxo2_program_done();
|
lcmxo2_execute_cmd(LSC_PROG_FEABITS, 0, CMD_NORMAL);
|
||||||
lcmxo2_reset_flash_address();
|
lcmxo2_write_data(buffer, FEATBITS_SIZE);
|
||||||
for (int i = 0; i < length; i += FLASH_PAGE_SIZE) {
|
lcmxo2_finish_cmd();
|
||||||
lcmxo2_read_flash_page(buffer);
|
}
|
||||||
fpga_mem_read(address + i, FLASH_PAGE_SIZE, verify_buffer);
|
|
||||||
for (int x = 0; x < FLASH_PAGE_SIZE; x++) {
|
static void lcmxo2_read_featbits (uint8_t *buffer) {
|
||||||
if (buffer[x] != verify_buffer[x]) {
|
lcmxo2_execute_cmd(LSC_READ_FEABITS, 0, CMD_NORMAL);
|
||||||
return lcmxo2_fail(VENDOR_ERROR_VERIFY);
|
lcmxo2_read_data(buffer, FEATBITS_SIZE);
|
||||||
}
|
lcmxo2_finish_cmd();
|
||||||
}
|
}
|
||||||
}
|
|
||||||
lcmxo2_disable_flash();
|
static void lcmxo2_refresh (void) {
|
||||||
lcmxo2_cleanup();
|
lcmxo2_execute_cmd(LSC_REFRESH, 0, CMD_TWO_OP);
|
||||||
|
lcmxo2_finish_cmd();
|
||||||
return VENDOR_OK;
|
}
|
||||||
}
|
|
||||||
|
static vendor_error_t lcmxo2_fail (vendor_error_t error) {
|
||||||
vendor_error_t vendor_reconfigure (void) {
|
lcmxo2_disable_flash();
|
||||||
lcmxo2_reset_bus();
|
return error;
|
||||||
lcmxo2_refresh();
|
}
|
||||||
lcmxo2_cleanup();
|
|
||||||
|
uint32_t vendor_flash_size (void) {
|
||||||
return VENDOR_OK;
|
return (FLASH_PAGE_SIZE * FLASH_NUM_PAGES);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
vendor_error_t vendor_backup (uint32_t address, uint32_t *length) {
|
||||||
|
uint8_t buffer[FLASH_PAGE_SIZE];
|
||||||
|
|
||||||
|
*length = 0;
|
||||||
|
|
||||||
|
lcmxo2_reset_bus();
|
||||||
|
if (lcmxo2_enable_flash()) {
|
||||||
|
return lcmxo2_fail(VENDOR_ERROR_INIT);
|
||||||
|
}
|
||||||
|
lcmxo2_reset_flash_address();
|
||||||
|
for (int i = 0; i < (FLASH_PAGE_SIZE * FLASH_NUM_PAGES); i += FLASH_PAGE_SIZE) {
|
||||||
|
lcmxo2_read_flash_page(buffer);
|
||||||
|
fpga_mem_write(address + i, FLASH_PAGE_SIZE, buffer);
|
||||||
|
*length += FLASH_PAGE_SIZE;
|
||||||
|
}
|
||||||
|
lcmxo2_disable_flash();
|
||||||
|
|
||||||
|
return VENDOR_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
vendor_error_t vendor_update (uint32_t address, uint32_t length) {
|
||||||
|
uint8_t buffer[FLASH_PAGE_SIZE];
|
||||||
|
uint8_t verify_buffer[FLASH_PAGE_SIZE];
|
||||||
|
|
||||||
|
if (length == 0) {
|
||||||
|
return VENDOR_ERROR_ARGS;
|
||||||
|
}
|
||||||
|
if ((length % FLASH_PAGE_SIZE) != 0) {
|
||||||
|
return VENDOR_ERROR_ARGS;
|
||||||
|
}
|
||||||
|
if (length > (FLASH_PAGE_SIZE * FLASH_NUM_PAGES)) {
|
||||||
|
return VENDOR_ERROR_ARGS;
|
||||||
|
}
|
||||||
|
|
||||||
|
lcmxo2_reset_bus();
|
||||||
|
if (lcmxo2_enable_flash()) {
|
||||||
|
return lcmxo2_fail(VENDOR_ERROR_INIT);
|
||||||
|
}
|
||||||
|
if (lcmxo2_erase_flash()) {
|
||||||
|
return lcmxo2_fail(VENDOR_ERROR_ERASE);
|
||||||
|
}
|
||||||
|
lcmxo2_reset_flash_address();
|
||||||
|
for (int i = 0; i < length; i += FLASH_PAGE_SIZE) {
|
||||||
|
fpga_mem_read(address + i, FLASH_PAGE_SIZE, buffer);
|
||||||
|
if (lcmxo2_write_flash_page(buffer)) {
|
||||||
|
return lcmxo2_fail(VENDOR_ERROR_PROGRAM);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
lcmxo2_program_done();
|
||||||
|
lcmxo2_reset_flash_address();
|
||||||
|
for (int i = 0; i < length; i += FLASH_PAGE_SIZE) {
|
||||||
|
lcmxo2_read_flash_page(buffer);
|
||||||
|
fpga_mem_read(address + i, FLASH_PAGE_SIZE, verify_buffer);
|
||||||
|
for (int x = 0; x < FLASH_PAGE_SIZE; x++) {
|
||||||
|
if (buffer[x] != verify_buffer[x]) {
|
||||||
|
return lcmxo2_fail(VENDOR_ERROR_VERIFY);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
lcmxo2_disable_flash();
|
||||||
|
|
||||||
|
return VENDOR_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
vendor_error_t vendor_reconfigure (void) {
|
||||||
|
lcmxo2_reset_bus();
|
||||||
|
lcmxo2_refresh();
|
||||||
|
|
||||||
|
return VENDOR_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
typedef enum {
|
||||||
|
CMD_GET_PRIMER_ID = '?',
|
||||||
|
CMD_PROBE_FPGA = '#',
|
||||||
|
CMD_RESTART = '$',
|
||||||
|
CMD_GET_DEVICE_ID = 'I',
|
||||||
|
CMD_ENABLE_FLASH = 'E',
|
||||||
|
CMD_DISABLE_FLASH = 'D',
|
||||||
|
CMD_ERASE_ALL = 'X',
|
||||||
|
CMD_RESET_ADDRESS = 'A',
|
||||||
|
CMD_WRITE_PAGE = 'W',
|
||||||
|
CMD_READ_PAGE = 'R',
|
||||||
|
CMD_PROGRAM_DONE = 'F',
|
||||||
|
CMD_WRITE_FEATBITS = 'Q',
|
||||||
|
CMD_READ_FEATBITS = 'Y',
|
||||||
|
CMD_REFRESH = 'B',
|
||||||
|
} primer_cmd_e;
|
||||||
|
|
||||||
|
|
||||||
|
static bool primer_check_rx_length (primer_cmd_e cmd, size_t rx_length) {
|
||||||
|
switch (cmd) {
|
||||||
|
case CMD_WRITE_PAGE:
|
||||||
|
return (rx_length != FLASH_PAGE_SIZE);
|
||||||
|
case CMD_WRITE_FEATBITS:
|
||||||
|
return (rx_length != FEATBITS_SIZE);
|
||||||
|
default:
|
||||||
|
return (rx_length != 0);
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void vendor_initial_configuration (vendor_get_cmd_t get_cmd, vendor_send_response_t send_response) {
|
||||||
|
bool runninng = true;
|
||||||
|
primer_cmd_e cmd;
|
||||||
|
uint8_t buffer[256];
|
||||||
|
uint8_t rx_length;
|
||||||
|
uint8_t tx_length;
|
||||||
|
bool error;
|
||||||
|
|
||||||
|
lcmxo2_reset_bus();
|
||||||
|
|
||||||
|
while (runninng) {
|
||||||
|
cmd = get_cmd(buffer, &rx_length);
|
||||||
|
tx_length = 0;
|
||||||
|
error = false;
|
||||||
|
|
||||||
|
if (primer_check_rx_length(cmd, rx_length)) {
|
||||||
|
send_response(cmd, NULL, 0, true);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
switch (cmd) {
|
||||||
|
case CMD_GET_PRIMER_ID:
|
||||||
|
buffer[0] = 'M';
|
||||||
|
buffer[1] = 'X';
|
||||||
|
buffer[2] = 'O';
|
||||||
|
buffer[3] = '2';
|
||||||
|
tx_length = 4;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case CMD_PROBE_FPGA:
|
||||||
|
buffer[0] = fpga_id_get();
|
||||||
|
tx_length = 1;
|
||||||
|
error = (buffer[0] != FPGA_ID);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case CMD_RESTART:
|
||||||
|
runninng = false;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case CMD_GET_DEVICE_ID:
|
||||||
|
lcmxo2_read_device_id(buffer);
|
||||||
|
tx_length = 4;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case CMD_ENABLE_FLASH:
|
||||||
|
error = lcmxo2_enable_flash();
|
||||||
|
break;
|
||||||
|
|
||||||
|
case CMD_DISABLE_FLASH:
|
||||||
|
lcmxo2_disable_flash();
|
||||||
|
break;
|
||||||
|
|
||||||
|
case CMD_ERASE_ALL:
|
||||||
|
error = lcmxo2_erase_all();
|
||||||
|
break;
|
||||||
|
|
||||||
|
case CMD_RESET_ADDRESS:
|
||||||
|
lcmxo2_reset_flash_address();
|
||||||
|
break;
|
||||||
|
|
||||||
|
case CMD_WRITE_PAGE:
|
||||||
|
error = lcmxo2_write_flash_page(buffer);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case CMD_READ_PAGE:
|
||||||
|
lcmxo2_read_flash_page(buffer);
|
||||||
|
tx_length = FLASH_PAGE_SIZE;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case CMD_PROGRAM_DONE:
|
||||||
|
lcmxo2_program_done();
|
||||||
|
break;
|
||||||
|
|
||||||
|
case CMD_WRITE_FEATBITS:
|
||||||
|
lcmxo2_write_featbits(buffer);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case CMD_READ_FEATBITS:
|
||||||
|
lcmxo2_read_featbits(buffer);
|
||||||
|
tx_length = FEATBITS_SIZE;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case CMD_REFRESH:
|
||||||
|
lcmxo2_refresh();
|
||||||
|
hw_delay_ms(1000);
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
error = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
send_response(cmd, buffer, tx_length, error);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -3,11 +3,11 @@
|
|||||||
.fpu softvfp
|
.fpu softvfp
|
||||||
.thumb
|
.thumb
|
||||||
|
|
||||||
|
|
||||||
.section .text.Reset_Handler
|
.section .text.Reset_Handler
|
||||||
.type Reset_Handler, %function
|
.type Reset_Handler, %function
|
||||||
Reset_Handler:
|
Reset_Handler:
|
||||||
.global Reset_Handler
|
.global Reset_Handler
|
||||||
cpsid i
|
|
||||||
|
|
||||||
init_text:
|
init_text:
|
||||||
ldr r0, =_stext
|
ldr r0, =_stext
|
||||||
@ -51,8 +51,9 @@ boot:
|
|||||||
|
|
||||||
ldr r0, =_app_header
|
ldr r0, =_app_header
|
||||||
push {r0}
|
push {r0}
|
||||||
bl set_vector_table_offset
|
bl hw_set_vector_table
|
||||||
pop {r0}
|
pop {r0}
|
||||||
|
|
||||||
ldr r1, [r0, #0]
|
ldr r1, [r0, #0]
|
||||||
msr MSP, r1
|
msr MSP, r1
|
||||||
ldr r1, [r0, #4]
|
ldr r1, [r0, #4]
|
||||||
|
@ -4,17 +4,14 @@
|
|||||||
#include "update.h"
|
#include "update.h"
|
||||||
|
|
||||||
|
|
||||||
|
void no_valid_image (void) {
|
||||||
|
hw_loader_init();
|
||||||
|
hw_gpio_set(GPIO_ID_LED);
|
||||||
|
}
|
||||||
|
|
||||||
void loader (void) {
|
void loader (void) {
|
||||||
if (update_check()) {
|
if (update_check()) {
|
||||||
hw_loader_init();
|
hw_loader_init();
|
||||||
update_perform();
|
update_perform();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void no_valid_image (void) {
|
|
||||||
hw_gpio_set(GPIO_ID_LED);
|
|
||||||
}
|
|
||||||
|
|
||||||
void set_vector_table_offset (uint32_t offset) {
|
|
||||||
SCB->VTOR = (__IOM uint32_t) (offset);
|
|
||||||
}
|
|
||||||
|
53
sw/controller/src/primer.S
Normal file
53
sw/controller/src/primer.S
Normal file
@ -0,0 +1,53 @@
|
|||||||
|
.syntax unified
|
||||||
|
.cpu cortex-m0plus
|
||||||
|
.fpu softvfp
|
||||||
|
.thumb
|
||||||
|
|
||||||
|
|
||||||
|
.section .text.Reset_Handler
|
||||||
|
.type Reset_Handler, %function
|
||||||
|
Reset_Handler:
|
||||||
|
.global Reset_Handler
|
||||||
|
ldr r0, =_estack
|
||||||
|
msr msp, r0
|
||||||
|
|
||||||
|
init_bss:
|
||||||
|
ldr r2, =_sbss
|
||||||
|
ldr r4, =_ebss
|
||||||
|
movs r3, #0
|
||||||
|
b 2f
|
||||||
|
1:
|
||||||
|
str r3, [r2]
|
||||||
|
adds r2, r2, #4
|
||||||
|
2:
|
||||||
|
cmp r2, r4
|
||||||
|
bcc 1b
|
||||||
|
|
||||||
|
run:
|
||||||
|
ldr r0, =_header
|
||||||
|
bl hw_set_vector_table
|
||||||
|
bl primer
|
||||||
|
|
||||||
|
loop:
|
||||||
|
b loop
|
||||||
|
|
||||||
|
|
||||||
|
.section .text.Default_Handler, "ax", %progbits
|
||||||
|
Default_Handler:
|
||||||
|
.global Default_Handler
|
||||||
|
b Default_Handler
|
||||||
|
|
||||||
|
|
||||||
|
.section .isr_vector, "a", %progbits
|
||||||
|
.type g_pfnVectors, %object
|
||||||
|
g_pfnVectors:
|
||||||
|
.global g_pfnVectors
|
||||||
|
.word _estack
|
||||||
|
.word Reset_Handler
|
||||||
|
.word NMI_Handler
|
||||||
|
.word HardFault_Handler
|
||||||
|
|
||||||
|
.weak NMI_Handler
|
||||||
|
.thumb_set NMI_Handler, Default_Handler
|
||||||
|
.weak HardFault_Handler
|
||||||
|
.thumb_set HardFault_Handler, Default_Handler
|
83
sw/controller/src/primer.c
Normal file
83
sw/controller/src/primer.c
Normal file
@ -0,0 +1,83 @@
|
|||||||
|
#include <stdbool.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include "hw.h"
|
||||||
|
#include "vendor.h"
|
||||||
|
|
||||||
|
|
||||||
|
static const uint8_t primer_hello[] = "SC64 Primer\n";
|
||||||
|
static const uint8_t cmd_token[3] = { 'C', 'M', 'D' };
|
||||||
|
static const uint8_t rsp_token[3] = { 'R', 'S', 'P' };
|
||||||
|
static const uint8_t err_token[3] = { 'E', 'R', 'R' };
|
||||||
|
|
||||||
|
|
||||||
|
static void primer_send_hello (void) {
|
||||||
|
hw_uart_write((uint8_t *) (primer_hello), sizeof(primer_hello) - 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void primer_get_and_calculate_crc32 (uint8_t *buffer, uint8_t rx_length, uint32_t *crc32) {
|
||||||
|
hw_uart_read(buffer, rx_length);
|
||||||
|
*crc32 = hw_crc32_calculate(buffer, rx_length);
|
||||||
|
}
|
||||||
|
|
||||||
|
static uint8_t primer_get_command (uint8_t *buffer, uint8_t *rx_length) {
|
||||||
|
uint32_t calculated_crc32;
|
||||||
|
uint32_t received_crc32;
|
||||||
|
uint8_t token[4];
|
||||||
|
|
||||||
|
while (1) {
|
||||||
|
hw_crc32_reset();
|
||||||
|
|
||||||
|
primer_get_and_calculate_crc32(token, 4, &calculated_crc32);
|
||||||
|
if (memcmp(token, cmd_token, 3) != 0) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
primer_get_and_calculate_crc32(rx_length, 1, &calculated_crc32);
|
||||||
|
|
||||||
|
if (*rx_length > 0) {
|
||||||
|
primer_get_and_calculate_crc32(buffer, *rx_length, &calculated_crc32);
|
||||||
|
}
|
||||||
|
|
||||||
|
hw_uart_read((uint8_t *) (&received_crc32), sizeof(received_crc32));
|
||||||
|
if (calculated_crc32 == received_crc32) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return token[3];
|
||||||
|
}
|
||||||
|
|
||||||
|
static void primer_send_and_calculate_crc32 (uint8_t *buffer, uint8_t tx_length, uint32_t *crc32) {
|
||||||
|
hw_uart_write(buffer, tx_length);
|
||||||
|
*crc32 = hw_crc32_calculate(buffer, tx_length);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void primer_send_response (uint8_t cmd, uint8_t *buffer, uint8_t tx_length, bool error) {
|
||||||
|
uint32_t calculated_crc32;
|
||||||
|
uint8_t *token = (uint8_t *) (error ? err_token : rsp_token);
|
||||||
|
uint8_t length = (error ? 0 : tx_length);
|
||||||
|
|
||||||
|
hw_crc32_reset();
|
||||||
|
|
||||||
|
primer_send_and_calculate_crc32(token, 3, &calculated_crc32);
|
||||||
|
primer_send_and_calculate_crc32(&cmd, 1, &calculated_crc32);
|
||||||
|
|
||||||
|
primer_send_and_calculate_crc32(&length, 1, &calculated_crc32);
|
||||||
|
|
||||||
|
if ((!error) && (tx_length > 0)) {
|
||||||
|
primer_send_and_calculate_crc32(buffer, tx_length, &calculated_crc32);
|
||||||
|
}
|
||||||
|
|
||||||
|
hw_uart_write((uint8_t *) (&calculated_crc32), sizeof(calculated_crc32));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void primer (void) {
|
||||||
|
hw_primer_init();
|
||||||
|
|
||||||
|
primer_send_hello();
|
||||||
|
|
||||||
|
vendor_initial_configuration(primer_get_command, primer_send_response);
|
||||||
|
|
||||||
|
hw_reset(NULL);
|
||||||
|
}
|
@ -24,6 +24,7 @@ typedef enum {
|
|||||||
CHUNK_ID_MCU_DATA = 2,
|
CHUNK_ID_MCU_DATA = 2,
|
||||||
CHUNK_ID_FPGA_DATA = 3,
|
CHUNK_ID_FPGA_DATA = 3,
|
||||||
CHUNK_ID_BOOTLOADER_DATA = 4,
|
CHUNK_ID_BOOTLOADER_DATA = 4,
|
||||||
|
CHUNK_ID_PRIMER_DATA = 5,
|
||||||
} chunk_id_t;
|
} chunk_id_t;
|
||||||
|
|
||||||
|
|
||||||
@ -264,6 +265,9 @@ update_error_t update_prepare (uint32_t address, uint32_t length) {
|
|||||||
parameters.bootloader_address = data_address;
|
parameters.bootloader_address = data_address;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case CHUNK_ID_PRIMER_DATA:
|
||||||
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
return UPDATE_ERROR_UNKNOWN_CHUNK;
|
return UPDATE_ERROR_UNKNOWN_CHUNK;
|
||||||
}
|
}
|
||||||
@ -274,7 +278,7 @@ update_error_t update_prepare (uint32_t address, uint32_t length) {
|
|||||||
|
|
||||||
void update_start (void) {
|
void update_start (void) {
|
||||||
parameters.magic = UPDATE_MAGIC_START;
|
parameters.magic = UPDATE_MAGIC_START;
|
||||||
hw_loader_reset(¶meters);
|
hw_reset(¶meters);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool update_check (void) {
|
bool update_check (void) {
|
||||||
@ -317,5 +321,5 @@ void update_perform (void) {
|
|||||||
vendor_reconfigure();
|
vendor_reconfigure();
|
||||||
|
|
||||||
parameters.magic = 0;
|
parameters.magic = 0;
|
||||||
hw_loader_reset(¶meters);
|
hw_reset(¶meters);
|
||||||
}
|
}
|
||||||
|
@ -2,6 +2,7 @@
|
|||||||
#define VENDOR_H__
|
#define VENDOR_H__
|
||||||
|
|
||||||
|
|
||||||
|
#include <stdbool.h>
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
|
|
||||||
|
|
||||||
@ -14,11 +15,16 @@ typedef enum {
|
|||||||
VENDOR_ERROR_VERIFY,
|
VENDOR_ERROR_VERIFY,
|
||||||
} vendor_error_t;
|
} vendor_error_t;
|
||||||
|
|
||||||
|
typedef uint8_t vendor_get_cmd_t (uint8_t *buffer, uint8_t *rx_length);
|
||||||
|
typedef void vendor_send_response_t (uint8_t cmd, uint8_t *buffer, uint8_t tx_length, bool error);
|
||||||
|
|
||||||
|
|
||||||
uint32_t vendor_flash_size (void);
|
uint32_t vendor_flash_size (void);
|
||||||
vendor_error_t vendor_backup (uint32_t address, uint32_t *length);
|
vendor_error_t vendor_backup (uint32_t address, uint32_t *length);
|
||||||
vendor_error_t vendor_update (uint32_t address, uint32_t length);
|
vendor_error_t vendor_update (uint32_t address, uint32_t length);
|
||||||
vendor_error_t vendor_reconfigure (void);
|
vendor_error_t vendor_reconfigure (void);
|
||||||
|
|
||||||
|
void vendor_initial_configuration (vendor_get_cmd_t get_cmd, vendor_send_response_t send_response);
|
||||||
|
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
@ -134,6 +134,7 @@ class SC64UpdateData:
|
|||||||
__CHUNK_ID_MCU_DATA = 2
|
__CHUNK_ID_MCU_DATA = 2
|
||||||
__CHUNK_ID_FPGA_DATA = 3
|
__CHUNK_ID_FPGA_DATA = 3
|
||||||
__CHUNK_ID_BOOTLOADER_DATA = 4
|
__CHUNK_ID_BOOTLOADER_DATA = 4
|
||||||
|
__CHUNK_ID_PRIMER_DATA = 5
|
||||||
|
|
||||||
__data = b''
|
__data = b''
|
||||||
|
|
||||||
@ -172,6 +173,9 @@ class SC64UpdateData:
|
|||||||
def add_bootloader_data(self, data: bytes) -> None:
|
def add_bootloader_data(self, data: bytes) -> None:
|
||||||
self.__add_chunk(self.__CHUNK_ID_BOOTLOADER_DATA, data)
|
self.__add_chunk(self.__CHUNK_ID_BOOTLOADER_DATA, data)
|
||||||
|
|
||||||
|
def add_primer_data(self, data: bytes) -> None:
|
||||||
|
self.__add_chunk(self.__CHUNK_ID_PRIMER_DATA, data)
|
||||||
|
|
||||||
def get_update_data(self) -> bytes:
|
def get_update_data(self) -> bytes:
|
||||||
return self.__data
|
return self.__data
|
||||||
|
|
||||||
@ -183,6 +187,7 @@ if __name__ == "__main__":
|
|||||||
parser.add_argument('--mcu', metavar='mcu_path', required=False, help='path to MCU update data')
|
parser.add_argument('--mcu', metavar='mcu_path', required=False, help='path to MCU update data')
|
||||||
parser.add_argument('--fpga', metavar='fpga_path', required=False, help='path to FPGA update data')
|
parser.add_argument('--fpga', metavar='fpga_path', required=False, help='path to FPGA update data')
|
||||||
parser.add_argument('--boot', metavar='bootloader_path', required=False, help='path to N64 bootloader update data')
|
parser.add_argument('--boot', metavar='bootloader_path', required=False, help='path to N64 bootloader update data')
|
||||||
|
parser.add_argument('--primer', metavar='primer_path', required=False, help='path to MCU board bring-up data')
|
||||||
parser.add_argument('output', metavar='output_path', help='path to final update data')
|
parser.add_argument('output', metavar='output_path', help='path to final update data')
|
||||||
|
|
||||||
if (len(sys.argv) <= 1):
|
if (len(sys.argv) <= 1):
|
||||||
@ -218,6 +223,10 @@ if __name__ == "__main__":
|
|||||||
with open(args.boot, 'rb+') as f:
|
with open(args.boot, 'rb+') as f:
|
||||||
update.add_bootloader_data(f.read())
|
update.add_bootloader_data(f.read())
|
||||||
|
|
||||||
|
if (args.primer):
|
||||||
|
with open(args.primer, 'rb+') as f:
|
||||||
|
update.add_primer_data(f.read())
|
||||||
|
|
||||||
with open(args.output, 'wb+') as f:
|
with open(args.output, 'wb+') as f:
|
||||||
f.write(update.get_update_data())
|
f.write(update.get_update_data())
|
||||||
except JedecError as e:
|
except JedecError as e:
|
||||||
|
Loading…
Reference in New Issue
Block a user