......@@ -136,37 +136,22 @@ done:
* Read the interrupt flag register and handle all interrupts which the PMIC has
* sent. In most cases this will be the buttons.
*/
static void
pmic_poll_interrupts(TickType_t *button_start_tick, TickType_t duration)
static uint8_t pmic_poll_interrupts(void)
{
while (hwlock_acquire(HWLOCK_I2C, LOCK_WAIT) < 0) {
LOG_WARN("pmic", "Failed to acquire I2C. Retrying ...");
xTaskNotify(pmic_task_id, PMIC_NOTIFY_IRQ, eSetBits);
return;
vTaskDelay(pdMS_TO_TICKS(100));
}
uint8_t int_flag = MAX77650_getINT_GLBL();
hwlock_release(HWLOCK_I2C);
if (int_flag & MAX77650_INT_nEN_F) {
/* Button was pressed */
*button_start_tick = xTaskGetTickCount();
}
if (int_flag & MAX77650_INT_nEN_R) {
/* Button was released */
*button_start_tick = 0;
if (duration < pdMS_TO_TICKS(400)) {
return_to_menu();
} else {
LOG_WARN("pmic", "Resetting ...");
card10_reset();
}
}
/* TODO: Remove when all interrupts are handled */
if (int_flag & ~(MAX77650_INT_nEN_F | MAX77650_INT_nEN_R)) {
LOG_WARN("pmic", "Unhandled PMIC Interrupt: %x", int_flag);
}
return int_flag;
}
__attribute__((noreturn)) static void pmic_die(float u_batt)
......@@ -192,11 +177,15 @@ __attribute__((noreturn)) static void pmic_die(float u_batt)
for (int i = 0; i < 50000000; i++)
__NOP();
LOG_WARN("pmic", "Poweroff");
MAX77650_setSFT_RST(0x2);
/* We have some of headroom to keep the RTC going.
* The battery protection circuit will shut down
* the system at 3.0 V */
/* TODO: Wake-up when USB is attached again */
sleep_deepsleep();
card10_reset();
while (1)
__WFI();
;
}
/*
......@@ -291,7 +280,9 @@ static void vPmicTimerCb(TimerHandle_t xTimer)
void vPmicTask(void *pvParameters)
{
pmic_task_id = xTaskGetCurrentTaskHandle();
pmic_task_id = xTaskGetCurrentTaskHandle();
uint8_t interrupts = 0;
uint32_t reason = 0;
ADC_Init(0x9, NULL);
GPIO_Config(&gpio_cfg_adc0);
......@@ -314,26 +305,107 @@ void vPmicTask(void *pvParameters)
}
xTimerStart(pmic_timer, 0);
/* Clear all pending interrupts. */
pmic_poll_interrupts();
while (1) {
uint32_t reason;
if (button_start_tick == 0) {
reason = ulTaskNotifyTake(pdTRUE, portMAX_DELAY);
} else {
reason = ulTaskNotifyTake(pdTRUE, pdMS_TO_TICKS(100));
interrupts |= pmic_poll_interrupts();
if (interrupts == 0) {
reason |= ulTaskNotifyTake(pdTRUE, portMAX_DELAY);
}
TickType_t duration = xTaskGetTickCount() - button_start_tick;
/* New interrupts */
if (reason & PMIC_NOTIFY_IRQ) {
reason ^= PMIC_NOTIFY_IRQ;
interrupts |= pmic_poll_interrupts();
}
if (button_start_tick != 0 && duration > pdMS_TO_TICKS(1000)) {
LOG_WARN("pmic", "Poweroff");
MAX77650_setSFT_RST(0x2);
if (interrupts & MAX77650_INT_nEN_R) {
/* Ignored in this state */
/* This can happen if the button is pressed
* during boot and released now. */
interrupts ^= MAX77650_INT_nEN_R; /* Mark as handled. */
}
if (reason & PMIC_NOTIFY_IRQ) {
pmic_poll_interrupts(&button_start_tick, duration);
if (interrupts & MAX77650_INT_nEN_F) {
/* Button was pressed */
interrupts ^= MAX77650_INT_nEN_F; /* Mark as handled. */
button_start_tick = xTaskGetTickCount();
while (true) {
TickType_t duration =
xTaskGetTickCount() - button_start_tick;
if (duration > 1000) {
disp_forcelock();
epic_disp_clear(0x0000);
char buf[20];
sprintf(buf,
"Off in %d",
7 - (int)(duration + 500) /
1000);
epic_disp_print(
0,
0,
"Sleep zZz..",
0xffff,
0x0000
);
epic_disp_print(
0, 25, buf, 0xf000, 0x0000
);
epic_disp_print(
0,
50,
" Reset ->",
0xffff,
0x0000
);
epic_disp_update();
}
if (duration >= pdMS_TO_TICKS(1000)) {
if (epic_buttons_read(
BUTTON_RIGHT_TOP)) {
LOG_WARN(
"pmic",
"Resetting ..."
);
card10_reset();
}
}
if (interrupts & MAX77650_INT_nEN_R) {
/* Button is released */
interrupts ^=
MAX77650_INT_nEN_R; /* Mark as handled. */
if (duration < pdMS_TO_TICKS(1000)) {
return_to_menu();
}
if (duration > pdMS_TO_TICKS(1000)) {
LOG_WARN("pmic", "Poweroff");
sleep_deepsleep();
card10_reset();
}
break;
}
reason |= ulTaskNotifyTake(
pdTRUE, pdMS_TO_TICKS(200)
);
if (reason & PMIC_NOTIFY_IRQ) {
/* New interrupts */
reason ^= PMIC_NOTIFY_IRQ;
interrupts |= pmic_poll_interrupts();
}
}
}
if (reason & PMIC_NOTIFY_MONITOR) {
reason ^= PMIC_NOTIFY_MONITOR;
pmic_check_battery();
}
}
......
......@@ -9,6 +9,18 @@
#include <stdint.h>
uint64_t monotonic_offset = 0;
uint32_t epic_rtc_get_monotonic_seconds(void)
{
return epic_rtc_get_seconds() + monotonic_offset / 1000ULL;
}
uint64_t epic_rtc_get_monotonic_milliseconds(void)
{
return epic_rtc_get_milliseconds() + monotonic_offset;
}
uint32_t epic_rtc_get_seconds(void)
{
uint32_t sec, subsec;
......@@ -32,12 +44,31 @@ uint64_t epic_rtc_get_milliseconds(void)
while (RTC_GetTime(&sec, &subsec) == E_BUSY) {
vTaskDelay(pdMS_TO_TICKS(4));
}
return subsec * 1000ULL / 4096 + sec * 1000ULL;
// Without the bias of 999 (0.24 milliseconds), this decoding function is
// numerically unstable:
//
// Encoding 5 milliseconds into 20 subsecs (using the encoding function in
// epic_rtc_set_milliseconds) and decoding it without the bias of 999 yields
// 4 milliseconds.
//
// The following invariants should hold when encoding / decoding from and to
// milliseconds / subseconds:
//
// - 0 <= encode(ms) < 4096 for 0 <= ms < 1000
// - decode(encode(ms)) == ms for 0 <= ms < 1000
// - 0 <= decode(subsec) < 1000 for 0 <= subsec < 4096
//
// These invariants were proven experimentally.
return (subsec * 1000ULL + 999ULL) / 4096 + sec * 1000ULL;
}
void epic_rtc_set_milliseconds(uint64_t milliseconds)
{
uint32_t sec, subsec;
uint64_t old_milliseconds, diff;
old_milliseconds = epic_rtc_get_milliseconds();
sec = milliseconds / 1000;
subsec = (milliseconds % 1000);
......@@ -48,6 +79,9 @@ void epic_rtc_set_milliseconds(uint64_t milliseconds)
;
while (RTC_EnableRTCE(MXC_RTC) == E_BUSY)
;
diff = old_milliseconds - milliseconds;
monotonic_offset += diff;
}
void RTC_IRQHandler(void)
......
......@@ -121,6 +121,92 @@ void epic_uart_write_str(const char *str, intptr_t length)
}
}
static void serial_flush_from_isr(void)
{
uint8_t rx_data[32];
size_t received_bytes;
BaseType_t resched = pdFALSE;
BaseType_t woken = pdFALSE;
uint32_t basepri = __get_BASEPRI();
taskENTER_CRITICAL_FROM_ISR();
do {
received_bytes = xStreamBufferReceiveFromISR(
write_stream_buffer,
(void *)rx_data,
sizeof(rx_data),
&woken
);
resched |= woken;
if (received_bytes == 0) {
break;
}
/*
* The SDK-driver for UART is not reentrant
* which means we need to perform UART writes
* in a critical section.
*/
UART_Write(ConsoleUart, (uint8_t *)&rx_data, received_bytes);
} while (received_bytes > 0);
taskEXIT_CRITICAL_FROM_ISR(basepri);
portYIELD_FROM_ISR(&resched);
}
static void serial_flush_from_thread(void)
{
uint8_t rx_data[32];
size_t received_bytes;
do {
taskENTER_CRITICAL();
received_bytes = xStreamBufferReceive(
write_stream_buffer,
(void *)rx_data,
sizeof(rx_data),
0
);
taskEXIT_CRITICAL();
if (received_bytes == 0) {
break;
}
/*
* The SDK-driver for UART is not reentrant
* which means we need to perform UART writes
* in a critical section.
*/
taskENTER_CRITICAL();
UART_Write(ConsoleUart, (uint8_t *)&rx_data, received_bytes);
taskEXIT_CRITICAL();
cdcacm_write((uint8_t *)&rx_data, received_bytes);
ble_uart_write((uint8_t *)&rx_data, received_bytes);
} while (received_bytes > 0);
}
/*
* Flush all characters which are currently waiting to be printed.
*
* If this function is called from an ISR, it will only flush to hardware UART
* while a call from thread mode will flush to UART, CDC-ACM, and BLE Serial.
*/
void serial_flush(void)
{
if (xPortIsInsideInterrupt()) {
serial_flush_from_isr();
} else {
serial_flush_from_thread();
}
}
/*
* API-call to read a character from the queue.
*/
......@@ -217,9 +303,6 @@ void vSerialTask(void *pvParameters)
.callback = uart_callback,
};
uint8_t rx_data[20];
size_t received_bytes;
while (1) {
int ret = UART_ReadAsync(ConsoleUart, &read_req);
if (ret != E_NO_ERROR && ret != E_BUSY) {
......@@ -230,38 +313,7 @@ void vSerialTask(void *pvParameters)
ret = ulTaskNotifyTake(pdTRUE, portMAX_DELAY);
if (ret & SERIAL_WRITE_NOTIFY) {
do {
received_bytes = xStreamBufferReceive(
write_stream_buffer,
(void *)rx_data,
sizeof(rx_data),
0
);
if (received_bytes == 0) {
break;
}
/*
* The SDK-driver for UART is not reentrant
* which means we need to perform UART writes
* in a critical section.
*/
taskENTER_CRITICAL();
UART_Write(
ConsoleUart,
(uint8_t *)&rx_data,
received_bytes
);
taskEXIT_CRITICAL();
cdcacm_write(
(uint8_t *)&rx_data, received_bytes
);
ble_uart_write(
(uint8_t *)&rx_data, received_bytes
);
} while (received_bytes > 0);
serial_flush_from_thread();
}
if (ret & SERIAL_READ_NOTIFY) {
......
#include "epicardium.h"
#include "modules/modules.h"
#include "modules/log.h"
#include "card10.h"
#include "simo.h"
#include "lp.h"
#include "max86150.h"
#include "MAX77650-Arduino-Library.h"
#include "max32665.h"
#include "mxc_sys.h"
#include "mxc_pins.h"
#include <stdint.h>
/* Most code is taken and adapted rom EvKitExamples/LP/main.c */
static uint32_t old_clkcn;
static uint32_t old_perckcn0, old_perckcn1;
void GPIOWAKE_IRQHandler(void)
{
/* Nothing to do here */
}
static void switchToHIRC(void)
{
MXC_GCR->clkcn &= ~(MXC_S_GCR_CLKCN_PSC_DIV128);
MXC_GCR->clkcn |= MXC_S_GCR_CLKCN_PSC_DIV4;
MXC_GCR->clkcn |= MXC_F_GCR_CLKCN_HIRC_EN;
MXC_SETFIELD(
MXC_GCR->clkcn,
MXC_F_GCR_CLKCN_CLKSEL,
MXC_S_GCR_CLKCN_CLKSEL_HIRC
);
while (!(MXC_GCR->clkcn & MXC_F_GCR_CLKCN_CKRDY))
; /* Wait for the clock switch to occur */
/* Disable the now unused 96 MHz clock */
MXC_GCR->clkcn &= ~(MXC_F_GCR_CLKCN_HIRC96M_EN);
SystemCoreClockUpdate();
}
static void deepsleep(void)
{
SIMO_setVregO_B(810); /* Reduce VCOREB to 0.81 V */
LP_FastWakeupEnable();
LP_EnterDeepSleepMode();
SIMO_setVregO_B(1000); /* Restore VCOREB to 1 V */
}
static void turnOffClocks(void)
{
old_perckcn0 = MXC_GCR->perckcn0;
old_perckcn1 = MXC_GCR->perckcn1;
/* Allow the USB Switch to be turned off in deepsleep and backup modes. */
/* TODO: should this be the default setting? */
LP_USBSWLPDisable();
/* Disable all peripheral clocks except GPIO0 (needed for interrupt wakeup) */
MXC_GCR->perckcn0 = 0xFFFFFFFE;
MXC_GCR->perckcn1 = 0xFFFFFFFF;
}
static void turnOnClocks(void)
{
MXC_GCR->perckcn0 = old_perckcn0;
MXC_GCR->perckcn1 = old_perckcn1;
}
/*
* Move most GPIOs into a special low power state with the fact
* in mind that the external 3.3 V are switched off.
*
* E.g. this means that the SD card pins need to be pulled low
* to preven them from backfeeding into the 3.3 V rail via their
* external pull-up resistors.
*
* Pins needed to talk to the PMIC are left untouched.
* ECG AOUT and 32 kHz out as well.
*/
static void gpio_low_power(void)
{
/* clang-format off */
const gpio_cfg_t pins_low_power[] = {
{ PORT_0, PIN_0, GPIO_FUNC_IN, GPIO_PAD_PULL_UP }, // FLash
{ PORT_0, PIN_1, GPIO_FUNC_IN, GPIO_PAD_PULL_UP }, // Flash
{ PORT_0, PIN_2, GPIO_FUNC_IN, GPIO_PAD_PULL_UP }, // Flash
{ PORT_0, PIN_3, GPIO_FUNC_IN, GPIO_PAD_PULL_UP }, // Flash
{ PORT_0, PIN_4, GPIO_FUNC_IN, GPIO_PAD_PULL_UP }, // Flash
{ PORT_0, PIN_5, GPIO_FUNC_IN, GPIO_PAD_PULL_UP }, // Flash
{ PORT_0, PIN_6, GPIO_FUNC_OUT, GPIO_PAD_NONE }, // I2C 3.3V
{ PORT_0, PIN_7, GPIO_FUNC_OUT, GPIO_PAD_NONE }, // I2C 3.3V
{ PORT_0, PIN_8, GPIO_FUNC_OUT, GPIO_PAD_NONE }, // Motor
{ PORT_0, PIN_9, GPIO_FUNC_IN, GPIO_PAD_PULL_UP }, // UART TX
{ PORT_0, PIN_10, GPIO_FUNC_IN, GPIO_PAD_PULL_UP }, // UART RX
{ PORT_0, PIN_11, GPIO_FUNC_IN, GPIO_PAD_PULL_DOWN }, // BMA400 interrupt
// 0, 12: PMIC IRQ
{ PORT_0, PIN_13, GPIO_FUNC_IN, GPIO_PAD_NONE }, // BHI160 interrupt, not sure if PP
// 0, 14: PMIC I2C
// 0, 15: PMIC I2C
{ PORT_0, PIN_16, GPIO_FUNC_IN, GPIO_PAD_PULL_UP }, // PMIC AMUX
{ PORT_0, PIN_17, GPIO_FUNC_IN, GPIO_PAD_PULL_DOWN }, // SOA GPIO
// 0, 18: ECG AOUT
// 0, 19: 32 kHz
{ PORT_0, PIN_20, GPIO_FUNC_IN, GPIO_PAD_PULL_DOWN }, // Wristband 1
{ PORT_0, PIN_21, GPIO_FUNC_IN, GPIO_PAD_PULL_DOWN }, // Wristband 2
{ PORT_0, PIN_22, GPIO_FUNC_IN, GPIO_PAD_PULL_DOWN }, // Wristband 3
{ PORT_0, PIN_23, GPIO_FUNC_OUT, GPIO_PAD_NONE }, // IR-LED
{ PORT_0, PIN_24, GPIO_FUNC_OUT, GPIO_PAD_NONE }, // display SS
{ PORT_0, PIN_25, GPIO_FUNC_OUT, GPIO_PAD_NONE }, // display MOSI
{ PORT_0, PIN_26, GPIO_FUNC_IN, GPIO_PAD_PULL_DOWN }, // SOA GPIO
{ PORT_0, PIN_27, GPIO_FUNC_OUT, GPIO_PAD_NONE }, // display SCK
{ PORT_0, PIN_28, GPIO_FUNC_OUT, GPIO_PAD_NONE }, // Backlight
{ PORT_0, PIN_29, GPIO_FUNC_IN, GPIO_PAD_PULL_DOWN }, // Wristband 4
// 0, 30: PMIC power hold
{ PORT_0, PIN_31, GPIO_FUNC_OUT, GPIO_PAD_NONE }, // ECG switch
{ PORT_1, PIN_0, GPIO_FUNC_OUT, GPIO_PAD_NONE }, // SDHC
{ PORT_1, PIN_1, GPIO_FUNC_OUT, GPIO_PAD_NONE }, // SDHC
{ PORT_1, PIN_2, GPIO_FUNC_OUT, GPIO_PAD_NONE }, // SDHC
{ PORT_1, PIN_3, GPIO_FUNC_OUT, GPIO_PAD_NONE }, // SDHC
{ PORT_1, PIN_4, GPIO_FUNC_OUT, GPIO_PAD_NONE }, // SDHC
{ PORT_1, PIN_5, GPIO_FUNC_OUT, GPIO_PAD_NONE }, // SDHC
{ PORT_1, PIN_6, GPIO_FUNC_OUT, GPIO_PAD_NONE }, // display RS
{ PORT_1, PIN_7, GPIO_FUNC_IN, GPIO_PAD_PULL_UP }, // Portexpander interrupt
{ PORT_1, PIN_8, GPIO_FUNC_IN, GPIO_PAD_PULL_UP }, // ECG CS TODO: better OUT high
{ PORT_1, PIN_9, GPIO_FUNC_OUT, GPIO_PAD_NONE }, // ECG SDI
{ PORT_1, PIN_10, GPIO_FUNC_IN, GPIO_PAD_PULL_UP }, // ECG SDO
{ PORT_1, PIN_11, GPIO_FUNC_IN, GPIO_PAD_PULL_UP }, // ECG SCK
{ PORT_1, PIN_11, GPIO_FUNC_IN, GPIO_PAD_PULL_UP }, // ECG INT
{ PORT_1, PIN_13, GPIO_FUNC_IN, GPIO_PAD_NONE }, // PPG Interrupt
{ PORT_1, PIN_14, GPIO_FUNC_OUT, GPIO_PAD_NONE }, // RGB LEDs
{ PORT_1, PIN_15, GPIO_FUNC_OUT, GPIO_PAD_NONE }, // RGB LEDs
};
/* clang-format on */
const unsigned int num_pins =
(sizeof(pins_low_power) / sizeof(gpio_cfg_t));
int i;
for (i = 0; i < num_pins; i++) {
GPIO_OutClr(&pins_low_power[i]);
GPIO_Config(&pins_low_power[i]);
}
}
/*
* Go to deepsleep, turning off peripherals.
*
* This functions returns after waking up again.
* Currently the only wakeup source is an interrupt
* from the PMIC.
*
* Some peripherals and GPIOs are moved into a low
* power state before going to sleep. There is no guarantee
* that all peripherals will be moved to a low power state
*
* TODO: Move BHI160, BMA400, BME680, MAX30001 into a low
* power state.
*
* The state of the GPIOs and generally all peripherials
* on board is not restored after a wakeup.
*/
void sleep_deepsleep(void)
{
LOG_WARN("pmic", "Powersave");
epic_disp_backlight(0);
epic_leds_set_rocket(0, 0);
epic_leds_set_rocket(1, 0);
epic_leds_set_rocket(2, 0);
#if 1
/* This will fail if there is no
* harmonic board attached */
max86150_begin();
max86150_getINT1();
max86150_getINT2();
max86150_shutDown();
#endif
MAX77650_setEN_SBB2(0b100);
MAX77650_setSBIA_LPM(true);
core1_stop();
MAX77650_getINT_GLBL();
gpio_low_power();
turnOffClocks();
old_clkcn = MXC_GCR->clkcn;
switchToHIRC();
deepsleep();
/* Now wait for an interrupt to wake us up */
turnOnClocks();
MXC_GCR->clkcn = old_clkcn;
while (!(MXC_GCR->clkcn & MXC_F_GCR_CLKCN_CKRDY))
; /* Wait for the clock switch to occur */
SystemCoreClockUpdate();
MAX77650_setEN_SBB2(0b110);
}
......@@ -27,6 +27,7 @@ typedef unsigned int size_t;
enum stream_descriptor {
/** BHI160 */
SD_BHI160_ACCELEROMETER,
SD_BHI160_MAGNETOMETER,
SD_BHI160_ORIENTATION,
SD_BHI160_GYROSCOPE,
SD_MAX30001_ECG,
......
......@@ -6,7 +6,8 @@ static const gpio_cfg_t motor_pin = {
PORT_0, PIN_8, GPIO_FUNC_OUT, GPIO_PAD_NONE
};
static TimerHandle_t vibra_timer;
static StaticTimer_t vibra_timer_data;
static TimerHandle_t vibra_timer = NULL;
void epic_vibra_set(int status)
{
......@@ -25,8 +26,19 @@ void vTimerCallback()
void epic_vibra_vibrate(int millis)
{
int ticks = millis * (configTICK_RATE_HZ / 1000);
epic_vibra_set(1);
vibra_timer =
xTimerCreate("vibratimer", ticks, pdFALSE, 0, vTimerCallback);
xTimerStart(vibra_timer, 0);
if (vibra_timer == NULL) {
vibra_timer = xTimerCreateStatic(
"vibratimer",
ticks,
pdFALSE,
0,
vTimerCallback,
&vibra_timer_data
);
}
if (vibra_timer != NULL) {
epic_vibra_set(1);
xTimerChangePeriod(vibra_timer, ticks, 0);
}
}
This diff is collapsed.
......@@ -3,3 +3,33 @@ target remote localhost:3333
define reset
mon mww 0x40000004 0x80000000
end
# usage: task_backtrace <tskTCB*>
define task_backtrace
set $taskbt_task_ptr = $arg0
set $taskbt_stack_ptr = $taskbt_task_ptr->pxTopOfStack
set $taskbt_frame_offset = 9
if ((*(uint32_t*)($taskbt_stack_ptr + 8)) & 0x10 == 0)
echo FPU is on\n
set $taskbt_frame_offset += 16
else
echo FPU is off\n
end
set $taskbt_reg_lr = $lr
set $taskbt_reg_pc = $pc
set $taskbt_reg_sp = $sp
set $lr = *($taskbt_stack_ptr + $taskbt_frame_offset + 5)
set $pc = *($taskbt_stack_ptr + $taskbt_frame_offset + 6)
set $sp = $taskbt_stack_ptr + $taskbt_frame_offset + 8
bt
set $lr = $taskbt_reg_lr
set $pc = $taskbt_reg_pc
set $sp = $taskbt_reg_sp
end
alias tbt = task_backtrace
......@@ -184,7 +184,8 @@ DefaultHandler:
b .
.macro def_irq_handler handler_name
.weakref \handler_name, DefaultHandler
.weak \handler_name
\handler_name : b .
.endm
/*
......
......@@ -29,6 +29,10 @@ const gpio_cfg_t bhi_interrupt_pin = {
PORT_0, PIN_13, GPIO_FUNC_IN, GPIO_PAD_PULL_UP
};
static const gpio_cfg_t pwr_hold_pin = {
PORT_0, PIN_30, GPIO_FUNC_OUT, GPIO_PAD_NONE
};
void card10_init(void)
{
printf("card10 init...\n");
......@@ -41,6 +45,8 @@ void card10_init(void)
I2C_Init(MXC_I2C1_BUS0, I2C_FAST_MODE, NULL);
GPIO_Init();
GPIO_Config(&pwr_hold_pin);
GPIO_OutSet(&pwr_hold_pin);
pmic_init();
pmic_set_led(0, 0);
......
......@@ -22,7 +22,7 @@ void display_set_reset_pin(uint8_t state)
if (!portexpander_detected()) {
MAX77650_setDO(state ? true : false);
} else {
portexpander_out_put(PIN_4, state);
portexpander_out_put(PIN_4, state ? 0xFF : 0);
}
}
......
......@@ -340,7 +340,7 @@ void leds_update(void)
void leds_flashlight(bool power)
{
portexpander_out_put(PIN_7, (power) ? 0 : 1);
portexpander_out_put(PIN_7, (power) ? 0 : 0xFF);
}
void leds_set_gamma_table(uint8_t rgb_channel, uint8_t table[256])
......
#include "i2c.h"
#include "pmic.h"
#include "lp.h"
#include "MAX77650-Arduino-Library.h"
#include <stdint.h>
#include <stdio.h>
......@@ -45,7 +46,7 @@ void pmic_init(void)
//MAX77650_setTV_SBB2(0b110100); //Set output Voltage of SBB2 to 5.0V
MAX77650_setTV_SBB2(0b010010); //Set output Voltage of SBB2 to 3.3V
#endif
MAX77650_setADE_SBB2(0b0); //Disable Active Discharge at SBB2 Output
MAX77650_setADE_SBB2(0b1); //Enable Active Discharge at SBB2 Output
MAX77650_setEN_SBB2(
0b110); //Enable SBB2 is on irrespective of FPS whenever the on/off controller is in its "On via Software" or "On via On/Off Controller" states
......@@ -90,6 +91,8 @@ void pmic_init(void)
);
NVIC_EnableIRQ((IRQn_Type)MXC_GPIO_GET_IRQ(pmic_interrupt_pin.port));
/* Allow the PMIC to interrupt us in deepsleep */
LP_EnableGPIOWakeup((gpio_cfg_t *)&pmic_interrupt_pin);
/* Setup power button interrupt */
MAX77650_setINT_M_GLBL(~(MAX77650_INT_nEN_R | MAX77650_INT_nEN_F));
/* Clear existing interrupts */
......
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
......@@ -169,7 +169,6 @@ __weak void SystemInit(void)
MXC_GPIO0->vssel |= (1UL << 20) | (1UL << 21) | (1UL << 22) | (1UL << 29); // Wristband
MXC_GPIO0->vssel |= (1UL << 17) | (1UL << 23) | (1UL << 28); // GPIO to TOP
MXC_GPIO0->vssel |= (1UL << 24) | (1UL << 25) | (1UL << 26) | (1UL << 27); // SPI to TOP
MXC_GPIO0->vssel |= (1UL << 31); // ECG Switch
MXC_GPIO0->ps |= 0xFFFFFFFF;
MXC_GPIO0->pad_cfg1 |= 0xFFFFFFFF;
......@@ -178,7 +177,7 @@ __weak void SystemInit(void)
// All GPIO on port 1 to 1.8 V first
MXC_GPIO1->vssel = 0;
MXC_GPIO1->vssel |= (1UL << 0) | (1UL << 1) | (1UL << 2) | (1UL << 3) | (1UL << 4) | (1UL << 5); // SDHC
MXC_GPIO1->vssel |= (1 << 6) | (1 << 7); // GPIO to TOP
MXC_GPIO1->vssel |= (1 << 6); // GPIO to TOP
MXC_GPIO1->vssel |= (1 << 14) | (1 << 15); // GPIO for RGB LEDs
#if BOARD_EVKIT
......
import bhi160
import display
import utime
import buttons
disp = display.open()
sensor = 0
sensors = [
{"sensor": bhi160.BHI160Orientation(), "name": "Orientation"},
{"sensor": bhi160.BHI160Accelerometer(), "name": "Accelerometer"},
{"sensor": bhi160.BHI160Gyroscope(), "name": "Gyroscope"},
import color
import contextlib
import display
import itertools
import simple_menu
STATUS_COLORS = [
color.RED,
# Orange
color.RED * 0.5 + color.YELLOW * 0.5,
color.YELLOW,
color.GREEN,
]
while True:
# Read and print sample
samples = sensors[sensor]["sensor"].read()
if len(samples) > 0:
disp.clear()
sample = samples[0]
with contextlib.ExitStack() as cx:
disp = cx.enter_context(display.open())
color = [255, 0, 0]
if sample.status == 1:
color = [255, 128, 0]
elif sample.status == 2:
color = [255, 255, 0]
elif sample.status == 3:
color = [0, 200, 0]
args = {"sample_rate": 10, "sample_buffer_len": 20}
disp.print(sensors[sensor]["name"], posy=0)
disp.print("X: %f" % sample.x, posy=20, fg=color)
disp.print("Y: %f" % sample.y, posy=40, fg=color)
disp.print("Z: %f" % sample.z, posy=60, fg=color)
sensor_iter = itertools.cycle(
[
(cx.enter_context(bhi160.BHI160Orientation(**args)), "Orientation"),
(cx.enter_context(bhi160.BHI160Accelerometer(**args)), "Accel"),
(cx.enter_context(bhi160.BHI160Gyroscope(**args)), "Gyro"),
(cx.enter_context(bhi160.BHI160Magnetometer(**args)), "Magnetic"),
]
)
sensor, sensor_name = next(sensor_iter)
disp.update()
for ev in simple_menu.button_events(timeout=0.1):
# Pressing the bottom right button cycles through sensors
if ev == buttons.BOTTOM_RIGHT:
sensor, sensor_name = next(sensor_iter)
# Read button
v = buttons.read(buttons.BOTTOM_RIGHT)
if v == 0:
button_pressed = False
samples = sensor.read()
if not samples:
continue
if not button_pressed and v & buttons.BOTTOM_RIGHT != 0:
button_pressed = True
sensor = (sensor + 1) % len(sensors)
sample = samples[-1]
col = STATUS_COLORS[sample.status]
utime.sleep(0.1)
disp.clear()
disp.print("{:^11s}".format(sensor_name), posy=0, posx=3)
disp.print("X:{: 9.4f}".format(sample.x), posy=20, fg=col)
disp.print("Y:{: 9.4f}".format(sample.y), posy=40, fg=col)
disp.print("Z:{: 9.4f}".format(sample.z), posy=60, fg=col)
disp.update()
......@@ -20,10 +20,10 @@ def main():
while True:
sensor_data = bme680.get_data()
disp.clear()
disp.print("BME680 Sensor")
disp.print("{} C".format(str(sensor_data[0])), posy=20)
disp.print("{} rh".format(str(sensor_data[1])), posy=40)
disp.print("{} hPa".format(str(sensor_data[2])), posy=60)
disp.print("BME680", posx=38)
disp.print("{:7.2f} C".format(sensor_data[0]), posy=20)
disp.print("{:7.2f} rh".format(sensor_data[1]), posy=40)
disp.print("{:7.2f} hPa".format(sensor_data[2]), posy=60)
disp.update()
utime.sleep(10)
......