circuitpython/stmhal/main.c

607 lines
17 KiB
C
Raw Normal View History

#include <stdio.h>
#include <string.h>
#include <stm32f4xx_hal.h>
2014-03-12 17:59:33 -04:00
#include <stm32f4xx_hal_gpio.h>
#if 0
#include <stm32f4xx.h>
#include <stm32f4xx_rcc.h>
#include <stm32f4xx_syscfg.h>
#include <stm32f4xx_gpio.h>
#include <stm32f4xx_exti.h>
#include <stm32f4xx_tim.h>
#include <stm32f4xx_pwr.h>
#include <stm32f4xx_rtc.h>
#include <stm32f4xx_usart.h>
#include <stm32f4xx_rng.h>
#include <usbd_storage_msd.h>
#include <stm_misc.h>
#endif
#include "std.h"
#if 0
#include "misc.h"
#include "ff.h"
#include "mpconfig.h"
#include "qstr.h"
#include "nlr.h"
#include "misc.h"
#include "lexer.h"
#include "lexerfatfs.h"
#include "parse.h"
#include "obj.h"
#include "parsehelper.h"
#include "compile.h"
#include "runtime0.h"
#include "runtime.h"
#include "gc.h"
#include "gccollect.h"
#include "systick.h"
#include "pendsv.h"
#include "pyexec.h"
#include "led.h"
#include "servo.h"
#include "lcd.h"
#include "storage.h"
#include "sdcard.h"
#include "accel.h"
#include "usb.h"
#include "timer.h"
#include "pybwlan.h"
#include "usrsw.h"
#include "rtc.h"
#include "file.h"
#include "pin.h"
#include "exti.h"
#include "pybmodule.h"
#endif
int errno;
#if 0
static FATFS fatfs0;
#if MICROPY_HW_HAS_SDCARD
static FATFS fatfs1;
#endif
#endif
#if 0
void flash_error(int n) {
for (int i = 0; i < n; i++) {
led_state(PYB_LED_R1, 1);
led_state(PYB_LED_R2, 0);
sys_tick_delay_ms(250);
led_state(PYB_LED_R1, 0);
led_state(PYB_LED_R2, 1);
sys_tick_delay_ms(250);
}
led_state(PYB_LED_R2, 0);
}
void __fatal_error(const char *msg) {
#if MICROPY_HW_HAS_LCD
lcd_print_strn("\nFATAL ERROR:\n", 14);
lcd_print_strn(msg, strlen(msg));
#endif
for (;;) {
flash_error(1);
}
}
#endif
#if 0
STATIC mp_obj_t pyb_config_source_dir = MP_OBJ_NULL;
STATIC mp_obj_t pyb_config_main = MP_OBJ_NULL;
STATIC mp_obj_t pyb_source_dir(mp_obj_t source_dir) {
if (MP_OBJ_IS_STR(source_dir)) {
pyb_config_source_dir = source_dir;
}
return mp_const_none;
}
MP_DEFINE_CONST_FUN_OBJ_1(pyb_source_dir_obj, pyb_source_dir);
STATIC mp_obj_t pyb_main(mp_obj_t main) {
if (MP_OBJ_IS_STR(main)) {
pyb_config_main = main;
}
return mp_const_none;
}
MP_DEFINE_CONST_FUN_OBJ_1(pyb_main_obj, pyb_main);
void fatality(void) {
led_state(PYB_LED_R1, 1);
led_state(PYB_LED_G1, 1);
led_state(PYB_LED_R2, 1);
led_state(PYB_LED_G2, 1);
}
static const char fresh_boot_py[] =
"# boot.py -- run on boot-up\n"
"# can run arbitrary Python, but best to keep it minimal\n"
"\n"
"pyb.source_dir('/src')\n"
"pyb.main('main.py')\n"
"#pyb.usb_usr('VCP')\n"
"#pyb.usb_msd(True, 'dual partition')\n"
"#pyb.flush_cache(False)\n"
"#pyb.error_log('error.txt')\n"
;
static const char fresh_main_py[] =
"# main.py -- put your code here!\n"
;
static const char *help_text =
"Welcome to Micro Python!\n\n"
"This is a *very* early version of Micro Python and has minimal functionality.\n\n"
"Specific commands for the board:\n"
" pyb.info() -- print some general information\n"
" pyb.gc() -- run the garbage collector\n"
" pyb.repl_info(<val>) -- enable/disable printing of info after each command\n"
" pyb.delay(<n>) -- wait for n milliseconds\n"
" pyb.udelay(<n>) -- wait for n microseconds\n"
" pyb.Led(<n>) -- create Led object for LED n (n=1,2)\n"
" Led methods: on(), off()\n"
" pyb.Servo(<n>) -- create Servo object for servo n (n=1,2,3,4)\n"
" Servo methods: angle(<x>)\n"
" pyb.switch() -- return True/False if switch pressed or not\n"
" pyb.accel() -- get accelerometer values\n"
" pyb.rand() -- get a 16-bit random number\n"
" pyb.gpio(<port>) -- get port value (port='A4' for example)\n"
" pyb.gpio(<port>, <val>) -- set port value, True or False, 1 or 0\n"
" pyb.ADC(<port>) -- make an analog port object (port='C0' for example)\n"
" ADC methods: read()\n"
;
// get some help about available functions
static mp_obj_t pyb_help(void) {
printf("%s", help_text);
return mp_const_none;
}
#endif
2014-03-12 17:59:33 -04:00
void led_init(void) {
/* GPIO structure */
GPIO_InitTypeDef GPIO_InitStructure;
/* Configure I/O speed, mode, output type and pull */
GPIO_InitStructure.Pin = GPIO_PIN_13 | GPIO_PIN_14 | GPIO_PIN_15;
GPIO_InitStructure.Mode = GPIO_MODE_OUTPUT_PP;
GPIO_InitStructure.Pull = GPIO_NOPULL;
GPIO_InitStructure.Speed = GPIO_SPEED_LOW;
GPIO_InitStructure.Alternate = 0; // unused
/* initialize */
HAL_GPIO_Init(GPIOA, &GPIO_InitStructure);
}
void led_state(int led_id, int state) {
HAL_GPIO_WritePin(GPIOA, 1 << (13 + led_id), state);
}
/**
* @brief System Clock Configuration
* The system Clock is configured as follow :
* System Clock source = PLL (HSE)
* SYSCLK(Hz) = 168000000
* HCLK(Hz) = 168000000
* AHB Prescaler = 1
* APB1 Prescaler = 4
* APB2 Prescaler = 2
* HSE Frequency(Hz) = 8000000
* PLL_M = 8
* PLL_N = 336
* PLL_P = 2
* PLL_Q = 7
* VDD(V) = 3.3
* Main regulator output voltage = Scale1 mode
* Flash Latency(WS) = 5
* @param None
* @retval None
*/
static void SystemClock_Config(void) {
RCC_ClkInitTypeDef RCC_ClkInitStruct;
RCC_OscInitTypeDef RCC_OscInitStruct;
/* Enable Power Control clock */
__PWR_CLK_ENABLE();
/* The voltage scaling allows optimizing the power consumption when the device is
clocked below the maximum system frequency, to update the voltage scaling value
regarding system frequency refer to product datasheet. */
__HAL_PWR_VOLTAGESCALING_CONFIG(PWR_REGULATOR_VOLTAGE_SCALE1);
/* Enable HSE Oscillator and activate PLL with HSE as source */
RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSE;
RCC_OscInitStruct.HSEState = RCC_HSE_ON;
RCC_OscInitStruct.PLL.PLLState = RCC_PLL_ON;
RCC_OscInitStruct.PLL.PLLSource = RCC_PLLSOURCE_HSE;
RCC_OscInitStruct.PLL.PLLM = 8;
RCC_OscInitStruct.PLL.PLLN = 336;
RCC_OscInitStruct.PLL.PLLP = RCC_PLLP_DIV2;
RCC_OscInitStruct.PLL.PLLQ = 7;
if(HAL_RCC_OscConfig(&RCC_OscInitStruct) != HAL_OK)
{
/* Initialization Error */
for (;;) {
}
}
/* Select PLL as system clock source and configure the HCLK, PCLK1 and PCLK2
clocks dividers */
RCC_ClkInitStruct.ClockType = (RCC_CLOCKTYPE_SYSCLK | RCC_CLOCKTYPE_HCLK | RCC_CLOCKTYPE_PCLK1 | RCC_CLOCKTYPE_PCLK2);
RCC_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_PLLCLK;
RCC_ClkInitStruct.AHBCLKDivider = RCC_SYSCLK_DIV1;
RCC_ClkInitStruct.APB1CLKDivider = RCC_HCLK_DIV4;
RCC_ClkInitStruct.APB2CLKDivider = RCC_HCLK_DIV2;
if(HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_5) != HAL_OK)
{
/* Initialization Error */
for (;;) {
}
}
// Make SysTick interrupt have the highest priority
// This is needed so that SysTick runs in all ISRs.
NVIC_SetPriority(SysTick_IRQn, 0);
2014-03-12 17:59:33 -04:00
}
int main(void) {
// TODO disable JTAG
/* STM32F4xx HAL library initialization:
- Configure the Flash prefetch, instruction and Data caches
- Configure the Systick to generate an interrupt each 1 msec
- Set NVIC Group Priority to 4
- Global MSP (MCU Support Package) initialization
*/
HAL_Init();
2014-03-12 17:59:33 -04:00
// set the system clock to be HSE
SystemClock_Config();
// enable GPIO clocks
__GPIOA_CLK_ENABLE();
__GPIOB_CLK_ENABLE();
__GPIOC_CLK_ENABLE();
__GPIOD_CLK_ENABLE();
// enable the CCM RAM
__CCMDATARAMEN_CLK_ENABLE();
// some test code to flash LEDs
led_init();
led_state(0, 1);
led_state(1, 0);
led_state(2, 1);
for (;;) {
HAL_Delay(500);
led_state(1, 1);
HAL_Delay(500);
led_state(1, 0);
}
#if 0
_fatal_error("done");
#endif
#if 0
#if MICROPY_HW_HAS_SDCARD
{
// configure SDIO pins to be high to start with (apparently makes it more robust)
// FIXME this is not making them high, it just makes them outputs...
GPIO_InitTypeDef GPIO_InitStructure;
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_8 | GPIO_Pin_9 | GPIO_Pin_10 | GPIO_Pin_11 | GPIO_Pin_12;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_25MHz;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_OUT;
GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;
GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL;
GPIO_Init(GPIOC, &GPIO_InitStructure);
// Configure PD.02 CMD line
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_2;
GPIO_Init(GPIOD, &GPIO_InitStructure);
}
#endif
#if defined(NETDUINO_PLUS_2)
{
GPIO_InitTypeDef GPIO_InitStructure;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_25MHz;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_OUT;
GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;
GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL;
#if MICROPY_HW_HAS_SDCARD
// Turn on the power enable for the sdcard (PB1)
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_1;
GPIO_Init(GPIOB, &GPIO_InitStructure);
GPIO_WriteBit(GPIOB, GPIO_Pin_1, Bit_SET);
#endif
// Turn on the power for the 5V on the expansion header (PB2)
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_2;
GPIO_Init(GPIOB, &GPIO_InitStructure);
GPIO_WriteBit(GPIOB, GPIO_Pin_2, Bit_SET);
}
#endif
// basic sub-system init
sys_tick_init();
pendsv_init();
led_init();
#if MICROPY_HW_ENABLE_RTC
rtc_init();
#endif
// turn on LED to indicate bootup
led_state(PYB_LED_G1, 1);
// more sub-system init
#if MICROPY_HW_HAS_SDCARD
sdcard_init();
#endif
storage_init();
// uncomment these 2 lines if you want REPL on USART_6 (or another usart) as well as on USB VCP
//pyb_usart_global_debug = PYB_USART_YA;
//usart_init(pyb_usart_global_debug, 115200);
int first_soft_reset = true;
soft_reset:
// GC init
gc_init(&_heap_start, &_heap_end);
// Micro Python init
qstr_init();
rt_init();
mp_obj_t def_path[3];
def_path[0] = MP_OBJ_NEW_QSTR(MP_QSTR_0_colon__slash_);
def_path[1] = MP_OBJ_NEW_QSTR(MP_QSTR_0_colon__slash_src);
def_path[2] = MP_OBJ_NEW_QSTR(MP_QSTR_0_colon__slash_lib);
sys_path = mp_obj_new_list(3, def_path);
exti_init();
#if MICROPY_HW_HAS_SWITCH
switch_init();
#endif
#if MICROPY_HW_HAS_LCD
// LCD init (just creates class, init hardware by calling LCD())
lcd_init();
#endif
#if MICROPY_HW_ENABLE_SERVO
// servo
servo_init();
#endif
#if MICROPY_HW_ENABLE_TIMER
// timer
timer_init();
#endif
#if MICROPY_HW_ENABLE_RNG
// RNG
RCC_AHB2PeriphClockCmd(RCC_AHB2Periph_RNG, ENABLE);
RNG_Cmd(ENABLE);
#endif
pin_map_init();
// add some functions to the builtin Python namespace
rt_store_name(MP_QSTR_help, rt_make_function_n(0, pyb_help));
rt_store_name(MP_QSTR_open, rt_make_function_n(2, pyb_io_open));
// we pre-import the pyb module
// probably shouldn't do this, so we are compatible with CPython
rt_store_name(MP_QSTR_pyb, (mp_obj_t)&pyb_module);
// check if user switch held (initiates reset of filesystem)
bool reset_filesystem = false;
#if MICROPY_HW_HAS_SWITCH
if (switch_get()) {
reset_filesystem = true;
for (int i = 0; i < 50; i++) {
if (!switch_get()) {
reset_filesystem = false;
break;
}
sys_tick_delay_ms(10);
}
}
#endif
// local filesystem init
{
// try to mount the flash
FRESULT res = f_mount(&fatfs0, "0:", 1);
if (!reset_filesystem && res == FR_OK) {
// mount sucessful
} else if (reset_filesystem || res == FR_NO_FILESYSTEM) {
// no filesystem, so create a fresh one
// TODO doesn't seem to work correctly when reset_filesystem is true...
// LED on to indicate creation of LFS
led_state(PYB_LED_R2, 1);
uint32_t stc = sys_tick_counter;
res = f_mkfs("0:", 0, 0);
if (res == FR_OK) {
// success creating fresh LFS
} else {
__fatal_error("could not create LFS");
}
// create src directory
res = f_mkdir("0:/src");
// ignore result from mkdir
// create empty main.py
FIL fp;
f_open(&fp, "0:/src/main.py", FA_WRITE | FA_CREATE_ALWAYS);
UINT n;
f_write(&fp, fresh_main_py, sizeof(fresh_main_py) - 1 /* don't count null terminator */, &n);
// TODO check we could write n bytes
f_close(&fp);
// keep LED on for at least 200ms
sys_tick_wait_at_least(stc, 200);
led_state(PYB_LED_R2, 0);
} else {
__fatal_error("could not access LFS");
}
}
// make sure we have a /boot.py
{
FILINFO fno;
FRESULT res = f_stat("0:/boot.py", &fno);
if (res == FR_OK) {
if (fno.fattrib & AM_DIR) {
// exists as a directory
// TODO handle this case
// see http://elm-chan.org/fsw/ff/img/app2.c for a "rm -rf" implementation
} else {
// exists as a file, good!
}
} else {
// doesn't exist, create fresh file
// LED on to indicate creation of boot.py
led_state(PYB_LED_R2, 1);
uint32_t stc = sys_tick_counter;
FIL fp;
f_open(&fp, "0:/boot.py", FA_WRITE | FA_CREATE_ALWAYS);
UINT n;
f_write(&fp, fresh_boot_py, sizeof(fresh_boot_py) - 1 /* don't count null terminator */, &n);
// TODO check we could write n bytes
f_close(&fp);
// keep LED on for at least 200ms
sys_tick_wait_at_least(stc, 200);
led_state(PYB_LED_R2, 0);
}
}
// run /boot.py
if (!pyexec_file("0:/boot.py")) {
flash_error(4);
}
if (first_soft_reset) {
#if MICROPY_HW_HAS_MMA7660
// MMA accel: init and reset address to zero
accel_init();
#endif
}
// turn boot-up LED off
led_state(PYB_LED_G1, 0);
#if MICROPY_HW_HAS_SDCARD
// if an SD card is present then mount it on 1:/
if (sdcard_is_present()) {
FRESULT res = f_mount(&fatfs1, "1:", 1);
if (res != FR_OK) {
printf("[SD] could not mount SD card\n");
} else {
if (first_soft_reset) {
// use SD card as medium for the USB MSD
usbd_storage_select_medium(USBD_STORAGE_MEDIUM_SDCARD);
}
}
}
#endif
#ifdef USE_HOST_MODE
// USB host
pyb_usb_host_init();
#elif defined(USE_DEVICE_MODE)
// USB device
pyb_usb_dev_init(PYB_USB_DEV_VCP_MSC);
#endif
// run main script
{
vstr_t *vstr = vstr_new();
vstr_add_str(vstr, "0:/");
if (pyb_config_source_dir == MP_OBJ_NULL) {
vstr_add_str(vstr, "src");
} else {
vstr_add_str(vstr, mp_obj_str_get_str(pyb_config_source_dir));
}
vstr_add_char(vstr, '/');
if (pyb_config_main == MP_OBJ_NULL) {
vstr_add_str(vstr, "main.py");
} else {
vstr_add_str(vstr, mp_obj_str_get_str(pyb_config_main));
}
if (!pyexec_file(vstr_str(vstr))) {
flash_error(3);
}
vstr_free(vstr);
}
#if MICROPY_HW_HAS_MMA7660
// HID example
if (0) {
uint8_t data[4];
data[0] = 0;
data[1] = 1;
data[2] = -2;
data[3] = 0;
for (;;) {
#if MICROPY_HW_HAS_SWITCH
if (switch_get()) {
data[0] = 0x01; // 0x04 is middle, 0x02 is right
} else {
data[0] = 0x00;
}
#else
data[0] = 0x00;
#endif
accel_start(0x4c /* ACCEL_ADDR */, 1);
accel_send_byte(0);
accel_restart(0x4c /* ACCEL_ADDR */, 0);
for (int i = 0; i <= 1; i++) {
int v = accel_read_ack() & 0x3f;
if (v & 0x20) {
v |= ~0x1f;
}
data[1 + i] = v;
}
accel_read_nack();
usb_hid_send_report(data);
sys_tick_delay_ms(15);
}
}
#endif
#if MICROPY_HW_HAS_WLAN
// wifi
pyb_wlan_init();
pyb_wlan_start();
#endif
pyexec_repl();
printf("PYB: sync filesystems\n");
storage_flush();
printf("PYB: soft reboot\n");
first_soft_reset = false;
goto soft_reset;
#endif
}