Skip to content
Snippets Groups Projects

Compare revisions

Changes are shown as if the source revision was being merged into the target revision. Learn more about comparing revisions.

Source

Select target project
No results found
Select Git revision
  • add_menu_vibration
  • blinkisync-as-preload
  • ch3/api-speed-eval2
  • ch3/dual-core
  • ch3/genapi-refactor
  • ch3/leds-api
  • ch3/splashscreen
  • dualcore
  • dx/flatten-config-module
  • dx/meh-bdf-to-stm
  • freertos-btle
  • genofire/ble-follow-py
  • koalo/bhi160-works-but-dirty
  • koalo/factory-reset
  • koalo/wip/i2c-for-python
  • master
  • msgctl/faultscreen
  • msgctl/textbuffer_api
  • plaetzchen/ios-workaround
  • rahix/bhi
  • rahix/bluetooth-app-favorite
  • rahix/bma
  • rahix/user-space-ctx
  • renze/hatchery_apps
  • renze/safe_mode
  • schleicher-test
  • schneider/212-reset-hardware-when-entering-repl
  • schneider/ancs
  • schneider/ble-buffers
  • schneider/ble-central
  • schneider/ble-ecg-stream-visu
  • schneider/ble-fixes-2020-3
  • schneider/ble-mini-demo
  • schneider/ble-stability
  • schneider/ble-stability-new-phy
  • schneider/bonding
  • schneider/bonding-fail-if-full
  • schneider/bootloader-update-9a0d158
  • schneider/deepsleep
  • schneider/deepsleep2
  • schneider/deepsleep4
  • schneider/default-main
  • schneider/freertos-list-debug
  • schneider/fundamental-test
  • schneider/iaq-python
  • schneider/ir
  • schneider/max30001
  • schneider/max30001-epicaridum
  • schneider/max30001-pycardium
  • schneider/maxim-sdk-update
  • schneider/mp-exception-print
  • schneider/mp-for-old-bl
  • schneider/png
  • schneider/schleicher-test
  • schneider/sdk-0.2.1-11
  • schneider/sdk-0.2.1-7
  • schneider/sleep-display
  • schneider/spo2-playground
  • schneider/stream-locks
  • schneider/v1.17-changelog
  • bootloader-v1
  • release-1
  • v0.0
  • v1.0
  • v1.1
  • v1.10
  • v1.11
  • v1.12
  • v1.13
  • v1.14
  • v1.15
  • v1.16
  • v1.17
  • v1.18
  • v1.2
  • v1.3
  • v1.4
  • v1.5
  • v1.6
  • v1.7
  • v1.8
  • v1.9
82 results

Target

Select target project
  • card10/firmware
  • annejan/firmware
  • astro/firmware
  • fpletz/firmware
  • gerd/firmware
  • fleur/firmware
  • swym/firmware
  • l/firmware
  • uberardy/firmware
  • wink/firmware
  • madonius/firmware
  • mot/firmware
  • filid/firmware
  • q3k/firmware
  • hauke/firmware
  • Woazboat/firmware
  • pink/firmware
  • mossmann/firmware
  • omniskop/firmware
  • zenox/firmware
  • trilader/firmware
  • Danukeru/firmware
  • shoragan/firmware
  • zlatko/firmware
  • sistason/firmware
  • datenwolf/firmware
  • bene/firmware
  • amedee/firmware
  • martinling/firmware
  • griffon/firmware
  • chris007/firmware
  • adisbladis/firmware
  • dbrgn/firmware
  • jelly/firmware
  • rnestler/firmware
  • mh/firmware
  • ln/firmware
  • penguineer/firmware
  • monkeydom/firmware
  • jens/firmware
  • jnaulty/firmware
  • jeffmakes/firmware
  • marekventur/firmware
  • pete/firmware
  • h2obrain/firmware
  • DooMMasteR/firmware
  • jackie/firmware
  • prof_r/firmware
  • Draradech/firmware
  • Kartoffel/firmware
  • hinerk/firmware
  • abbradar/firmware
  • JustTB/firmware
  • LuKaRo/firmware
  • iggy/firmware
  • ente/firmware
  • flgr/firmware
  • Lorphos/firmware
  • matejo/firmware
  • ceddral7/firmware
  • danb/firmware
  • joshi/firmware
  • melle/firmware
  • fitch/firmware
  • deurknop/firmware
  • sargon/firmware
  • markus/firmware
  • kloenk/firmware
  • lucaswerkmeister/firmware
  • derf/firmware
  • meh/firmware
  • dx/card10-firmware
  • torben/firmware
  • yuvadm/firmware
  • AndyBS/firmware
  • klausdieter1/firmware
  • katzenparadoxon/firmware
  • xiretza/firmware
  • ole/firmware
  • techy/firmware
  • thor77/firmware
  • TilCreator/firmware
  • fuchsi/firmware
  • dos/firmware
  • yrlf/firmware
  • PetePriority/firmware
  • SuperVirus/firmware
  • sur5r/firmware
  • tazz/firmware
  • Alienmaster/firmware
  • flo_h/firmware
  • baldo/firmware
  • mmu_man/firmware
  • Foaly/firmware
  • sodoku/firmware
  • Guinness/firmware
  • ssp/firmware
  • led02/firmware
  • Stormwind/firmware
  • arist/firmware
  • coon/firmware
  • mdik/firmware
  • pippin/firmware
  • royrobotiks/firmware
  • zigot83/firmware
  • mo_k/firmware
106 results
Select Git revision
Loading items
Show changes
Showing
with 642 additions and 180 deletions
#pragma once
#include "FreeRTOS.h"
#include "os/mutex.h"
/* ---------- Dispatcher --------------------------------------------------- */
void vApiDispatcher(void *pvParameters);
void dispatcher_mutex_init(void);
extern struct mutex api_mutex;
extern TaskHandle_t dispatcher_task_id;
/* ---------- Lifecycle ---------------------------------------------------- */
void vLifecycleTask(void *pvParameters);
void return_to_menu(void);
/* ---------- Migration ---------------------------------------------------- */
void migration_delete_app_launchers(void);
epicardium/version-splash.png

15 KiB

...@@ -3,27 +3,33 @@ ...@@ -3,27 +3,33 @@
******************************************************************************/ ******************************************************************************/
/***** Includes *****/ /***** Includes *****/
#include "pmic.h"
#include "leds.h"
#include "card10.h" #include "card10.h"
#include "leds.h"
#include "pmic.h"
#include "gfx.h"
#include "display.h" #include "display.h"
#include "gfx.h"
#include "tmr_utils.h" #include "tmr_utils.h"
#include <stdio.h> #include <Heart.h>
#include <stdint.h> #include <stdint.h>
#include <stdio.h>
#include <string.h> #include <string.h>
#include <Heart.h>
int main(void) int main(void)
{ {
card10_init(); card10_init();
card10_diag(); card10_diag();
gfx_copy_region_raw( gfx_copy_region(
&display_screen, 0, 0, 160, 80, 2, (const void *)(Heart) &display_screen,
0,
0,
160,
80,
GFX_RGB565,
(const void *)(Heart)
); );
gfx_update(&display_screen); gfx_update(&display_screen);
......
...@@ -401,11 +401,11 @@ int main(void) ...@@ -401,11 +401,11 @@ int main(void)
uint32_t ecgFIFO, readECGSamples, idx, ETAG[32], status; uint32_t ecgFIFO, readECGSamples, idx, ETAG[32], status;
int16_t ecgSample[32]; int16_t ecgSample[32];
const int EINT_STATUS_MASK = 1 << 23; const uint32_t EINT_STATUS_MASK = 1 << 23;
const int FIFO_OVF_MASK = 0x7; const uint32_t FIFO_OVF_MASK = 0x7;
const int FIFO_VALID_SAMPLE_MASK = 0x0; const uint32_t FIFO_VALID_SAMPLE_MASK = 0x0;
const int FIFO_FAST_SAMPLE_MASK = 0x1; const uint32_t FIFO_FAST_SAMPLE_MASK = 0x1;
const int ETAG_BITS_MASK = 0x7; const uint32_t ETAG_BITS_MASK = 0x7;
while (1) { while (1) {
#if 1 #if 1
......
...@@ -30,8 +30,14 @@ int main(void) ...@@ -30,8 +30,14 @@ int main(void)
card10_init(); card10_init();
card10_diag(); card10_diag();
gfx_copy_region_raw( gfx_copy_region(
&display_screen, 0, 0, 160, 80, 2, (const void *)(Heart) &display_screen,
0,
0,
160,
80,
GFX_RGB565,
(const void *)(Heart)
); );
gfx_update(&display_screen); gfx_update(&display_screen);
......
...@@ -37,22 +37,22 @@ int main(void) ...@@ -37,22 +37,22 @@ int main(void)
gfx_line(&display_screen, 100, 10, 70, 40, 2, yellow); gfx_line(&display_screen, 100, 10, 70, 40, 2, yellow);
gfx_circle(&display_screen, 85, 25, 22, 2, green); gfx_circle(&display_screen, 85, 25, 22, 2, green);
gfx_copy_region_raw( gfx_copy_region(
&display_screen, &display_screen,
120, 120,
0, 0,
40, 40,
40, 40,
2, GFX_RGB565,
(const void *)(gImage_40X40) (const void *)(gImage_40X40)
); );
gfx_copy_region_raw( gfx_copy_region(
&display_screen, &display_screen,
0, 0,
0, 0,
160, 160,
80, 80,
2, GFX_RGB565,
(const void *)(gImage_160X80) (const void *)(gImage_160X80)
); );
gfx_update(&display_screen); gfx_update(&display_screen);
......
...@@ -3,3 +3,33 @@ target remote localhost:3333 ...@@ -3,3 +3,33 @@ target remote localhost:3333
define reset define reset
mon mww 0x40000004 0x80000000 mon mww 0x40000004 0x80000000
end 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
...@@ -24,6 +24,9 @@ void fade() ...@@ -24,6 +24,9 @@ void fade()
/* /*
* main() is called when l0dable is loaded and executed. * main() is called when l0dable is loaded and executed.
*
* When main() returns, card10 goes back to the menu. A non-zero return value
* can be used to signal some kind of failure during l0dable execution.
*/ */
int main(void) int main(void)
{ {
......
...@@ -157,12 +157,9 @@ Reset_Handler: ...@@ -157,12 +157,9 @@ Reset_Handler:
ldr r0, =main ldr r0, =main
blx r0 blx r0
/* /* C code done, return to menu. Return code is what main() returned. */
* C code done, spin forever. ldr r4, =epic_exit
* TODO(q3k): let epicardium know we're done. blx r4
*/
.spin:
bl .spin
/* /*
* Used by __libc_init_array. * Used by __libc_init_array.
...@@ -190,15 +187,6 @@ DefaultHandler: ...@@ -190,15 +187,6 @@ DefaultHandler:
/* /*
* Declare all default ISRs. * Declare all default ISRs.
*/ */
def_irq_handler NMI_Handler
def_irq_handler HardFault_Handler
def_irq_handler MemManage_Handler
def_irq_handler BusFault_Handler
def_irq_handler UsageFault_Handler
def_irq_handler SVC_Handler
def_irq_handler DebugMon_Handler
def_irq_handler PendSV_Handler
def_irq_handler PF_IRQHandler def_irq_handler PF_IRQHandler
def_irq_handler WDT0_IRQHandler def_irq_handler WDT0_IRQHandler
def_irq_handler RTC_IRQHandler def_irq_handler RTC_IRQHandler
......
...@@ -128,3 +128,25 @@ uint32_t _sbrk(int incr) ...@@ -128,3 +128,25 @@ uint32_t _sbrk(int incr)
brk += incr; brk += incr;
return (uint32_t)prev_brk; return (uint32_t)prev_brk;
} }
void HardFault_Handler(void)
{
/*
* We pray that we're not currently in an API call and attempt
* returning. This is okay because a HardFault during an API call is
* extremely unlikely.
*
* In the future, we could improve this by "finishing" an ongoing API
* call before firing epic_exit().
*/
epic_exit(255);
}
/* Alias all other exception handlers to the HardFault_Handler. */
void NMI_Handler(void) __attribute__((alias("HardFault_Handler")));
void MemManage_Handler(void) __attribute__((alias("HardFault_Handler")));
void BusFault_Handler(void) __attribute__((alias("HardFault_Handler")));
void UsageFault_Handler(void) __attribute__((alias("HardFault_Handler")));
void SVC_Handler(void) __attribute__((alias("HardFault_Handler")));
void DebugMon_Handler(void) __attribute__((alias("HardFault_Handler")));
void PendSV_Handler(void) __attribute__((alias("HardFault_Handler")));
...@@ -29,6 +29,10 @@ const gpio_cfg_t bhi_interrupt_pin = { ...@@ -29,6 +29,10 @@ const gpio_cfg_t bhi_interrupt_pin = {
PORT_0, PIN_13, GPIO_FUNC_IN, GPIO_PAD_PULL_UP 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) void card10_init(void)
{ {
printf("card10 init...\n"); printf("card10 init...\n");
...@@ -41,6 +45,8 @@ void card10_init(void) ...@@ -41,6 +45,8 @@ void card10_init(void)
I2C_Init(MXC_I2C1_BUS0, I2C_FAST_MODE, NULL); I2C_Init(MXC_I2C1_BUS0, I2C_FAST_MODE, NULL);
GPIO_Init(); GPIO_Init();
GPIO_Config(&pwr_hold_pin);
GPIO_OutSet(&pwr_hold_pin);
pmic_init(); pmic_init();
pmic_set_led(0, 0); pmic_set_led(0, 0);
...@@ -54,16 +60,11 @@ void card10_init(void) ...@@ -54,16 +60,11 @@ void card10_init(void)
TMR_Delay(MXC_TMR0, MSEC(1000), 0); TMR_Delay(MXC_TMR0, MSEC(1000), 0);
// Enable 32 kHz output // Enable 32 kHz output
while (RTC_SquareWave( while (RTC_SquareWave(MXC_RTC, SQUARE_WAVE_ENABLED, F_32KHZ, NULL) ==
MXC_RTC, E_BUSY)
SQUARE_WAVE_ENABLED,
F_32KHZ,
NOISE_IMMUNE_MODE,
NULL) == E_BUSY
)
; ;
/* If we don't have a valid time yet, set it to 2019-01-01 */ /* If we don't have a valid time yet, set it to 2019-01-01 */
if (RTC_GetSecond() < 1546300800UL) { if (RTC_GetSecond() < 1546300800L) {
while (RTC_Init(MXC_RTC, 1546300800UL, 0, NULL) == E_BUSY) while (RTC_Init(MXC_RTC, 1546300800UL, 0, NULL) == E_BUSY)
; ;
} }
...@@ -78,6 +79,7 @@ void card10_init(void) ...@@ -78,6 +79,7 @@ void card10_init(void)
spi17y_master_cfg.ss0 = Enable; spi17y_master_cfg.ss0 = Enable;
spi17y_master_cfg.ss1 = Disable; spi17y_master_cfg.ss1 = Disable;
spi17y_master_cfg.ss2 = Disable; spi17y_master_cfg.ss2 = Disable;
spi17y_master_cfg.num_io = 2;
if (SPI_Init(SPI0, 0, SPI_SPEED, spi17y_master_cfg) != 0) { if (SPI_Init(SPI0, 0, SPI_SPEED, spi17y_master_cfg) != 0) {
printf("Error configuring SPI\n"); printf("Error configuring SPI\n");
while (1) while (1)
...@@ -215,9 +217,10 @@ void core1_stop(void) ...@@ -215,9 +217,10 @@ void core1_stop(void)
void card10_poll(void) void card10_poll(void)
{ {
pmic_poll(); pmic_poll();
portexpander_poll();
} }
void card10_reset(void) void __attribute__((noreturn)) card10_reset(void)
{ {
printf("Resetting ...\n"); printf("Resetting ...\n");
/* /*
...@@ -228,6 +231,9 @@ void card10_reset(void) ...@@ -228,6 +231,9 @@ void card10_reset(void)
__asm volatile("nop"); __asm volatile("nop");
} }
MXC_GCR->rstr0 = MXC_F_GCR_RSTR0_SYSTEM; MXC_GCR->rstr0 = MXC_F_GCR_RSTR0_SYSTEM;
while (1)
__WFI();
} }
void GPIO0_IRQHandler(void) void GPIO0_IRQHandler(void)
......
...@@ -15,5 +15,5 @@ void core1_start(void *isr); ...@@ -15,5 +15,5 @@ void core1_start(void *isr);
void core1_stop(void); void core1_stop(void);
void card10_poll(void); void card10_poll(void);
void card10_reset(void); void card10_reset(void) __attribute__((noreturn));
#endif #endif
...@@ -4,83 +4,25 @@ ...@@ -4,83 +4,25 @@
#include "textbuffer.h" #include "textbuffer.h"
#include "gpio.h" #include "gpio.h"
#include "tmr.h"
#include "portexpander.h" #include "portexpander.h"
#include "MAX77650-Arduino-Library.h" #include "MAX77650-Arduino-Library.h"
#include <stdint.h> #include <stdint.h>
#include <stdio.h> #include <stdio.h>
/***** Globals *****/ /***** Globals *****/
const gpio_cfg_t DEV_DC_PIN = { PORT_1, PIN_6, GPIO_FUNC_OUT, GPIO_PAD_NONE }; const gpio_cfg_t DEV_DC_PIN = { PORT_1, PIN_6, GPIO_FUNC_OUT, GPIO_PAD_NONE };
struct gfx_region display_screen; struct gfx_region display_screen;
struct txt_buffer display_textb; struct txt_buffer display_textb;
// Parameters for PWM output
#define PORT_PWM PORT_0 // port
#define PIN_PWM PIN_28 // pin
#define FREQ 200 // (Hz)
//#define DUTY_CYCLE 75 // (%)
#define DUTY_CYCLE 20 // (%)
#define PWM_TIMER MXC_TMR4 // must change PORT_PWM and PIN_PWM if changed
/***** Functions *****/ /***** Functions *****/
void PWM_Output(void)
{
// Declare variables
gpio_cfg_t gpio_pwm; // to configure GPIO
tmr_cfg_t tmr; // to congigure timer
tmr_pwm_cfg_t tmr_pwm; // for configure PWM
unsigned int period_ticks = PeripheralClock / FREQ;
unsigned int duty_ticks = period_ticks * DUTY_CYCLE / 100;
// Congfigure GPIO port and pin for PWM
gpio_pwm.func = GPIO_FUNC_ALT4;
gpio_pwm.port = PORT_PWM;
gpio_pwm.mask = PIN_PWM;
gpio_pwm.pad = GPIO_PAD_PULL_DOWN;
if (GPIO_Config(&gpio_pwm) != E_NO_ERROR) {
printf("Failed GPIO_Config for pwm.\n");
}
/*
Steps for configuring a timer for PWM mode:
1. Disable the timer
2. Set the prescale value
3. Configure the timer for PWM mode
4. Set polarity, pwm parameters
5. Enable Timer
*/
TMR_Disable(PWM_TIMER);
TMR_Init(PWM_TIMER, TMR_PRES_1, 0);
tmr.mode = TMR_MODE_PWM;
tmr.cmp_cnt = period_ticks;
tmr.pol = 0;
TMR_Config(PWM_TIMER, &tmr);
tmr_pwm.pol = 1;
tmr_pwm.per_cnt = period_ticks;
tmr_pwm.duty_cnt = duty_ticks;
if (TMR_PWMConfig(PWM_TIMER, &tmr_pwm) != E_NO_ERROR) {
printf("Failed TMR_PWMConfig.\n");
}
TMR_Enable(PWM_TIMER);
printf("PWM started.\n");
}
void display_set_reset_pin(uint8_t state) void display_set_reset_pin(uint8_t state)
{ {
if (!portexpander_detected()) { if (!portexpander_detected()) {
MAX77650_setDO(state ? true : false); MAX77650_setDO(state ? true : false);
} else { } else {
portexpander_set(4, state); portexpander_out_put(PIN_4, state ? 0xFF : 0);
} }
} }
...@@ -95,8 +37,7 @@ void display_init(void) ...@@ -95,8 +37,7 @@ void display_init(void)
GPIO_Config(&DEV_DC_PIN); GPIO_Config(&DEV_DC_PIN);
PWM_Output(); LCD_SetBacklight(20);
LCD_SetBacklight(500);
LCD_Init(); LCD_Init();
display_screen = gfx_screen(LCD_framebuffer()); display_screen = gfx_screen(LCD_framebuffer());
......
...@@ -206,6 +206,13 @@ void leds_prep(uint8_t led, uint8_t r, uint8_t g, uint8_t b) ...@@ -206,6 +206,13 @@ void leds_prep(uint8_t led, uint8_t r, uint8_t g, uint8_t b)
leds[led][2] = b; leds[led][2] = b;
} }
void leds_get_rgb(uint8_t led, uint8_t *rgb)
{
rgb[0] = leds[led][0];
rgb[1] = leds[led][1];
rgb[2] = leds[led][2];
}
#if 0 #if 0
//don't use, is buggy //don't use, is buggy
void leds_set_autodim(uint8_t led, uint8_t r, uint8_t g, uint8_t b) void leds_set_autodim(uint8_t led, uint8_t r, uint8_t g, uint8_t b)
...@@ -278,10 +285,7 @@ static uint8_t power_pin_conversion(uint8_t group) ...@@ -278,10 +285,7 @@ static uint8_t power_pin_conversion(uint8_t group)
static void power_all(void) static void power_all(void)
{ {
for (int i = 0; i < 3; i++) { portexpander_out_clr(PIN_0 | PIN_1 | PIN_2);
portexpander_prep(i, 0);
}
portexpander_update();
} }
void leds_update_power(void) void leds_update_power(void)
...@@ -294,14 +298,14 @@ void leds_update_power(void) ...@@ -294,14 +298,14 @@ void leds_update_power(void)
if (new_groups == active_groups) { if (new_groups == active_groups) {
return; return;
} }
for (int i = 0; i < 3; i++) {
if (i < new_groups) { uint8_t out_val = 0;
portexpander_prep(power_pin_conversion(i), 0); for (int i = new_groups; i < 3; ++i) {
} else { out_val |= (1 << power_pin_conversion(i));
portexpander_prep(power_pin_conversion(i), 1);
}
} }
portexpander_update();
portexpander_out_put(PIN_0 | PIN_1 | PIN_2, out_val);
if (active_groups < new_groups) { if (active_groups < new_groups) {
for (int i = 0; i < powerup_wait_cycles; i++) { for (int i = 0; i < powerup_wait_cycles; i++) {
__NOP(); __NOP();
...@@ -336,7 +340,7 @@ void leds_update(void) ...@@ -336,7 +340,7 @@ void leds_update(void)
void leds_flashlight(bool power) void leds_flashlight(bool power)
{ {
portexpander_set(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]) void leds_set_gamma_table(uint8_t rgb_channel, uint8_t table[256])
......
...@@ -6,6 +6,7 @@ ...@@ -6,6 +6,7 @@
void leds_set_dim_top(uint8_t value); void leds_set_dim_top(uint8_t value);
void leds_set_dim_bottom(uint8_t value); void leds_set_dim_bottom(uint8_t value);
void leds_prep(uint8_t led, uint8_t r, uint8_t g, uint8_t b); void leds_prep(uint8_t led, uint8_t r, uint8_t g, uint8_t b);
void leds_get_rgb(uint8_t led, uint8_t * rgb);
void leds_prep_hsv(uint8_t led, float h, float s, float v); void leds_prep_hsv(uint8_t led, float h, float s, float v);
void leds_update_power(void); void leds_update_power(void);
void leds_update(void); void leds_update(void);
......
...@@ -40,6 +40,10 @@ ...@@ -40,6 +40,10 @@
#include "portexpander.h" #include "portexpander.h"
#include "MAX77650-Arduino-Library.h" #include "MAX77650-Arduino-Library.h"
#include <stddef.h> #include <stddef.h>
static const uint8_t expander_pins[] = { 5, 0x0, 3, 6 };
static pb_callback pb_callbacks[4] = { NULL };
/******************************************************************************/ /******************************************************************************/
int PB_Init(void) int PB_Init(void)
{ {
...@@ -59,24 +63,71 @@ int PB_Init(void) ...@@ -59,24 +63,71 @@ int PB_Init(void)
return retval; return retval;
} }
static void pe_pb_callback(gpio_int_pol_t edge_type, void *cbdata)
{
unsigned int pb = (unsigned int)cbdata;
if (pb_callbacks[pb - 1]) {
pb_callbacks[pb - 1](pb, edge_type == GPIO_INT_FALLING);
}
}
static void gpio_pb_callback(void *cbdata)
{
unsigned int pb = (unsigned int)cbdata;
if (pb_callbacks[pb - 1]) {
int level = GPIO_InGet(&pb_pin[pb - 1]);
pb_callbacks[pb - 1](pb, !level);
}
}
/******************************************************************************/ /******************************************************************************/
int PB_RegisterCallback(unsigned int pb, pb_callback callback) int PB_RegisterCallback(unsigned int pb, pb_callback callback)
{ {
MXC_ASSERT(pb < num_pbs); MXC_ASSERT((pb > 0) && (pb <= num_pbs));
if (pb == 2) {
return E_INVALID;
}
pb_callbacks[pb - 1] = callback;
uint8_t mask = (1 << expander_pins[pb - 1]);
// TODO: portexpander support
if (callback) { if (callback) {
if (portexpander_detected()) {
// Register callback
portexpander_register_callback(
mask, pe_pb_callback, (void *)pb
);
// Configure and enable interrupt
portexpander_int_config(mask, GPIO_INT_BOTH);
portexpander_int_enable(mask);
} else {
// Register callback // Register callback
GPIO_RegisterCallback(&pb_pin[pb], callback, (void *)pb); GPIO_RegisterCallback(
&pb_pin[pb - 1], gpio_pb_callback, (void *)pb
);
// Configure and enable interrupt // Configure and enable interrupt
GPIO_IntConfig(&pb_pin[pb], GPIO_INT_EDGE, GPIO_INT_FALLING); GPIO_IntConfig(
GPIO_IntEnable(&pb_pin[pb]); &pb_pin[pb - 1], GPIO_INT_EDGE, GPIO_INT_BOTH
NVIC_EnableIRQ((IRQn_Type)MXC_GPIO_GET_IRQ(pb_pin[pb].port)); );
GPIO_IntEnable(&pb_pin[pb - 1]);
NVIC_EnableIRQ((IRQn_Type)MXC_GPIO_GET_IRQ(
pb_pin[pb - 1].port)
);
}
} else { } else {
if (portexpander_detected()) {
// Disable interrupt and clear callback // Disable interrupt and clear callback
GPIO_IntDisable(&pb_pin[pb]); portexpander_int_disable(mask);
GPIO_RegisterCallback(&pb_pin[pb], NULL, NULL); portexpander_register_callback(mask, NULL, NULL);
} else {
// Disable interrupt and clear callback
GPIO_IntDisable(&pb_pin[pb - 1]);
GPIO_RegisterCallback(&pb_pin[pb - 1], NULL, NULL);
}
} }
return E_NO_ERROR; return E_NO_ERROR;
...@@ -85,25 +136,46 @@ int PB_RegisterCallback(unsigned int pb, pb_callback callback) ...@@ -85,25 +136,46 @@ int PB_RegisterCallback(unsigned int pb, pb_callback callback)
//****************************************************************************** //******************************************************************************
void PB_IntEnable(unsigned int pb) void PB_IntEnable(unsigned int pb)
{ {
// TODO: portexpander support MXC_ASSERT((pb > 0) && (pb <= num_pbs));
MXC_ASSERT(pb < num_pbs); if (pb == 2) {
GPIO_IntEnable(&pb_pin[pb]); return;
}
if (portexpander_detected()) {
portexpander_int_enable((1 << expander_pins[pb - 1]));
} else {
GPIO_IntEnable(&pb_pin[pb - 1]);
}
} }
//****************************************************************************** //******************************************************************************
void PB_IntDisable(unsigned int pb) void PB_IntDisable(unsigned int pb)
{ {
// TODO: portexpander support MXC_ASSERT((pb > 0) && (pb <= num_pbs));
MXC_ASSERT(pb < num_pbs); if (pb == 2) {
GPIO_IntDisable(&pb_pin[pb]); return;
}
if (portexpander_detected()) {
portexpander_int_disable((1 << expander_pins[pb - 1]));
} else {
GPIO_IntDisable(&pb_pin[pb - 1]);
}
} }
//****************************************************************************** //******************************************************************************
void PB_IntClear(unsigned int pb) void PB_IntClear(unsigned int pb)
{ {
// TODO: portexpander support MXC_ASSERT((pb > 0) && (pb <= num_pbs));
MXC_ASSERT(pb < num_pbs); if (pb == 2) {
GPIO_IntClr(&pb_pin[pb]); return;
}
if (portexpander_detected()) {
portexpander_int_clr((1 << expander_pins[pb - 1]));
} else {
GPIO_IntClr(&pb_pin[pb - 1]);
}
} }
//****************************************************************************** //******************************************************************************
...@@ -116,8 +188,8 @@ int PB_Get(unsigned int pb) ...@@ -116,8 +188,8 @@ int PB_Get(unsigned int pb)
case 3: case 3:
case 4: case 4:
if (portexpander_detected()) { if (portexpander_detected()) {
uint8_t port = portexpander_get(); return portexpander_in_get(
return (port & (1 << expander_pins[pb - 1])) == 0; (1 << expander_pins[pb - 1])) == 0;
} else { } else {
return GPIO_InGet(&pb_pin[pb - 1]) == 0; return GPIO_InGet(&pb_pin[pb - 1]) == 0;
} }
......
/**
* @file pb.h
* @brief Pushbutton driver header file.
*/
/* ****************************************************************************
* Copyright (C) 2016 Maxim Integrated Products, Inc., All Rights Reserved.
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included
* in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
* IN NO EVENT SHALL MAXIM INTEGRATED BE LIABLE FOR ANY CLAIM, DAMAGES
* OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
* ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
* OTHER DEALINGS IN THE SOFTWARE.
*
* Except as contained in this notice, the name of Maxim Integrated
* Products, Inc. shall not be used except as stated in the Maxim Integrated
* Products, Inc. Branding Policy.
*
* The mere transfer of this software does not imply any licenses
* of trade secrets, proprietary technology, copyrights, patents,
* trademarks, maskwork rights, or any other form of intellectual
* property whatsoever. Maxim Integrated Products, Inc. retains all
* ownership rights.
*
* $Date: 2018-10-31 15:32:51 +0000 (Wed, 31 Oct 2018) $
* $Revision: 38826 $
*
*************************************************************************** */
#ifndef _PB_H_
#define _PB_H_
#include "gpio.h"
#include <stdbool.h>
#ifdef __cplusplus
extern "C" {
#endif
/**
* @ingroup bsp
* @defgroup pushbutton_evkit Push button driver board support
* @{
*/
/* **** Global Variables **** */
extern const gpio_cfg_t pb_pin[];
extern const unsigned int num_pbs;
/* **** Function Prototypes **** */
/**
* @brief Initialize all push buttons.
* @return \c #E_NO_ERROR Push buttons initialized successfully.
* @return "Error Code" @ref MXC_Error_Codes "Error Code" if unsuccessful.
*
*/
int PB_Init(void);
/**
* Type alias @c pb_callback for the push button callback.
* @details The function is of type:
* @code
* void pb_callback(unsigned int pb, bool falling)
* @endcode
* To receive notification of a push button event, define a callback
* function and pass it as a pointer to the PB_RegisterCallback(unsigned int pb, pb_callback callback) function.
* @param pb push button index that triggered the callback.
*/
typedef void (*pb_callback)(unsigned int pb, bool falling);
/**
* @brief Register or Unregister a callback handler for events on the @p pb push button.
* @details
* - Calling this function with a pointer to a function @p callback, configures the pushbutton @p pb and enables the
* interrupt to handle the push button events.
* - Calling this function with a <tt>NULL</tt> pointer will disable the interrupt and unregister the
* callback function.
* @p pb must be a value between 0 and \c num_pbs.
*
* @param pb push button index to receive event callbacks.
* @param callback Callback function pointer of type @c pb_callback
* @return #E_NO_ERROR if configured and callback registered successfully.
* @return "Error Code" @ref MXC_Error_Codes "Error Code" if unsuccessful.
*/
int PB_RegisterCallback(unsigned int pb, pb_callback callback);
/**
* @brief Register or Unregister a callback handler for rising and falling events on the @p pb push button.
* @details
* - Calling this function with a pointer to a function @p callback, configures the pushbutton @p pb and enables the
* interrupt to handle the push button events.
* - Calling this function with a <tt>NULL</tt> pointer will disable the interrupt and unregister the
* callback function.
* @p pb must be a value between 0 and \c num_pbs.
*
* @param pb push button index to receive event callbacks.
* @param callback Callback function pointer of type @c pb_callback
* @return #E_NO_ERROR if configured and callback registered successfully.
* @return "Error Code" @ref MXC_Error_Codes "Error Code" if unsuccessful.
*/
int PB_RegisterRiseFallCallback(unsigned int pb, pb_callback callback);
/**
* @brief Enable a callback interrupt.
* @note PB_RegisterCallback must be called prior to enabling the callback interrupt.
* @param pb push button index value between 0 and \c num_pbs.
*/
void PB_IntEnable(unsigned int pb);
/**
* @brief Disable a callback interrupt.
* @param pb push button index
*/
void PB_IntDisable(unsigned int pb);
/**
* @brief Clear a callback interrupt.
* @param pb push button index value between 0 and \c num_pbs.
*/
void PB_IntClear(unsigned int pb);
/**
* @brief Get the current state of the push button.
* @param pb push button index value between 0 and \c num_pbs.
* @return TRUE The button is pressed.
* @return FALSE The button is not pressed.
*/
int PB_Get(unsigned int pb);
/**@}*/
#ifdef __cplusplus
}
#endif
#endif /* _PB_H_ */
#include "i2c.h" #include "i2c.h"
#include "pmic.h" #include "pmic.h"
#include "lp.h"
#include "MAX77650-Arduino-Library.h" #include "MAX77650-Arduino-Library.h"
#include <stdint.h> #include <stdint.h>
#include <stdio.h> #include <stdio.h>
#include <errno.h>
static const gpio_cfg_t pmic_interrupt_pin = { static const gpio_cfg_t pmic_interrupt_pin = {
PORT_0, PIN_12, GPIO_FUNC_IN, GPIO_PAD_PULL_UP PORT_0, PIN_12, GPIO_FUNC_IN, GPIO_PAD_PULL_UP
...@@ -44,7 +46,7 @@ void pmic_init(void) ...@@ -44,7 +46,7 @@ void pmic_init(void)
//MAX77650_setTV_SBB2(0b110100); //Set output Voltage of SBB2 to 5.0V //MAX77650_setTV_SBB2(0b110100); //Set output Voltage of SBB2 to 5.0V
MAX77650_setTV_SBB2(0b010010); //Set output Voltage of SBB2 to 3.3V MAX77650_setTV_SBB2(0b010010); //Set output Voltage of SBB2 to 3.3V
#endif #endif
MAX77650_setADE_SBB2(0b0); //Disable Active Discharge at SBB2 Output MAX77650_setADE_SBB2(0b1); //Enable Active Discharge at SBB2 Output
MAX77650_setEN_SBB2( 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 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
...@@ -89,6 +91,8 @@ void pmic_init(void) ...@@ -89,6 +91,8 @@ void pmic_init(void)
); );
NVIC_EnableIRQ((IRQn_Type)MXC_GPIO_GET_IRQ(pmic_interrupt_pin.port)); 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 */ /* Setup power button interrupt */
MAX77650_setINT_M_GLBL(~(MAX77650_INT_nEN_R | MAX77650_INT_nEN_F)); MAX77650_setINT_M_GLBL(~(MAX77650_INT_nEN_R | MAX77650_INT_nEN_F));
/* Clear existing interrupts */ /* Clear existing interrupts */
...@@ -123,6 +127,20 @@ void pmic_set_button_callback(pmic_button_callback_fn cb) ...@@ -123,6 +127,20 @@ void pmic_set_button_callback(pmic_button_callback_fn cb)
pmic_button_callback = cb; pmic_button_callback = cb;
} }
int pmic_get_led(uint8_t led)
{
if (led == 0) {
return MAX77650_getBRT_LED0();
}
if (led == 1) {
return MAX77650_getBRT_LED1();
}
if (led == 2) {
return MAX77650_getBRT_LED2();
}
return -EINVAL;
}
void pmic_set_led(uint8_t led, uint8_t val) void pmic_set_led(uint8_t led, uint8_t val)
{ {
if (led == 0) { if (led == 0) {
......
...@@ -21,6 +21,7 @@ ...@@ -21,6 +21,7 @@
void pmic_init(void); void pmic_init(void);
void pmic_set_led(uint8_t led, uint8_t val); void pmic_set_led(uint8_t led, uint8_t val);
int pmic_get_led(uint8_t led);
void pmic_poll(void); void pmic_poll(void);
/* weak, so it can be overwritten by applications */ /* weak, so it can be overwritten by applications */
......
/* PCAL6408A I2C port expander */
/* **** Includes **** */
#include "portexpander.h" #include "portexpander.h"
#include "mxc_config.h"
#include "mxc_assert.h"
#include "i2c.h" #include "i2c.h"
#include <stdio.h> #include <stdio.h>
...@@ -7,10 +12,7 @@ ...@@ -7,10 +12,7 @@
#include <string.h> #include <string.h>
#include <stdbool.h> #include <stdbool.h>
// PCAL6408A I2C port expander /* **** Definitions **** */
static bool detected = false;
static uint8_t output_state;
/* clang-format off */ /* clang-format off */
#define PE_ADDR 0x42 #define PE_ADDR 0x42
...@@ -40,95 +42,295 @@ static uint8_t output_state; ...@@ -40,95 +42,295 @@ static uint8_t output_state;
#define PE_INPUT_MASK ((uint8_t)0b01101000) // 3, 5, 6 = input #define PE_INPUT_MASK ((uint8_t)0b01101000) // 3, 5, 6 = input
/* **** Globals **** */
static bool detected = false;
static volatile bool interrupt_pending;
static uint8_t type_state = 0xFF;
static uint8_t output_state = 0xFF;
static uint8_t pull_enable_state = 0x00;
static uint8_t pull_selection_state = 0xFF;
static uint8_t int_mask_state = 0xFF;
static gpio_int_pol_t int_edge_config[8] = { 0 };
static pe_callback callbacks[8] = { NULL };
static void *cbparam[8] = { NULL };
const gpio_cfg_t pe_int_pin = { PORT_1, PIN_7, GPIO_FUNC_IN, GPIO_PAD_PULL_UP };
static const portexpander_cfg_t pe_pin_config[] = {
{ PE_INPUT_MASK, GPIO_FUNC_IN, GPIO_PAD_PULL_UP },
{ ~PE_INPUT_MASK, GPIO_FUNC_OUT, GPIO_PAD_PULL_UP },
};
/* **** Functions **** */
static int portexpander_write(uint8_t command, uint8_t data) static int portexpander_write(uint8_t command, uint8_t data)
{ {
uint8_t i2c_data[2] = { command, data }; uint8_t i2c_data[2] = { command, data };
return I2C_MasterWrite(MXC_I2C1_BUS0, PE_ADDR, i2c_data, 2, 0); return I2C_MasterWrite(MXC_I2C1_BUS0, PE_ADDR, i2c_data, 2, 0);
} }
/* ************************************************************************** */
static int portexpander_read(uint8_t command, uint8_t *data) static int portexpander_read(uint8_t command, uint8_t *data)
{ {
I2C_MasterWrite(MXC_I2C1_BUS0, PE_ADDR, &command, 1, 1); I2C_MasterWrite(MXC_I2C1_BUS0, PE_ADDR, &command, 1, 1);
return I2C_MasterRead(MXC_I2C1_BUS0, PE_ADDR, data, 1, 0); return I2C_MasterRead(MXC_I2C1_BUS0, PE_ADDR, data, 1, 0);
} }
void portexpander_init(void) /* ************************************************************************** */
int portexpander_init(void)
{ {
int ret; int ret;
// Enable pull-ups for buttons (type defaults to pull-up) // Set _all_ outputs to open-drain to support the high side p-channel transistors.
ret = portexpander_write(PE_C_PULL_ENABLE, PE_INPUT_MASK); ret = portexpander_write(PE_C_OUTPUT_PORT_CONFIG, PE_OUT_OPEN_DRAIN);
if (ret != 2) { if (ret != 2) {
printf("portexpander NOT detected\n"); printf("portexpander NOT detected\n");
detected = false; detected = false;
return; return E_NO_DEVICE;
} }
detected = true; detected = true;
// Set _all_ outputs to open-drain to support the high side p-channel transistors. // Set outputs to high
portexpander_write(PE_C_OUTPUT_PORT_CONFIG, PE_OUT_OPEN_DRAIN); portexpander_out_set(~PE_INPUT_MASK);
// Enable pull-ups for buttons
// Enable outputs for the transistors, the LED and the LCD reset // Enable outputs for the transistors, the LED and the LCD reset
portexpander_write(PE_C_CONFIG, PE_INPUT_MASK); for (size_t i = 0; i < sizeof(pe_pin_config) / sizeof(pe_pin_config[0]);
i++) {
ret = portexpander_config(&pe_pin_config[i]);
MXC_ASSERT(ret == E_NO_ERROR);
}
// Set outputs to high (i.e. open-drain) // Latch inputs so we can figure out whether an interrupt was caused by a rising or falling edge
output_state = ~PE_INPUT_MASK; portexpander_write(PE_C_INPUT_LATCH, PE_INPUT_MASK);
portexpander_write(PE_C_OUTPUT_PORT, output_state);
// Configure interrupt GPIO
MXC_ASSERT(GPIO_Config(&pe_int_pin) == E_NO_ERROR);
// Configure and enable portexpander interrupt
GPIO_RegisterCallback(
&pe_int_pin, &portexpander_interrupt_callback, NULL
);
MXC_ASSERT(
GPIO_IntConfig(&pe_int_pin, GPIO_INT_EDGE, GPIO_INT_FALLING) ==
E_NO_ERROR);
GPIO_IntEnable(&pe_int_pin);
NVIC_EnableIRQ((IRQn_Type)MXC_GPIO_GET_IRQ(pe_int_pin.port));
return E_SUCCESS;
}
/* ************************************************************************** */
int portexpander_config(const portexpander_cfg_t *cfg)
{
// Set the GPIO type
switch (cfg->func) {
case GPIO_FUNC_IN:
type_state |= cfg->mask;
break;
case GPIO_FUNC_OUT:
type_state &= ~cfg->mask;
break;
default:
return E_BAD_PARAM;
}
if (portexpander_write(PE_C_CONFIG, type_state) != 2) {
return E_NO_DEVICE;
}
switch (cfg->pad) {
case GPIO_PAD_NONE:
pull_enable_state &= ~cfg->mask;
break;
case GPIO_PAD_PULL_UP:
pull_selection_state |= cfg->mask;
pull_enable_state |= cfg->mask;
break;
case GPIO_PAD_PULL_DOWN:
pull_selection_state &= ~cfg->mask;
pull_enable_state |= cfg->mask;
break;
default:
return E_BAD_PARAM;
} }
uint8_t portexpander_get(void) portexpander_write(PE_C_PULL_SEL, pull_selection_state);
portexpander_write(PE_C_PULL_ENABLE, pull_enable_state);
return E_NO_ERROR;
}
/* ************************************************************************** */
uint8_t portexpander_in_get(uint8_t mask)
{ {
// Reading the input port clears interrupts, so we need to check them here to avoid losing information
portexpander_poll();
uint8_t buf = 0xFF; uint8_t buf = 0xFF;
if (detected) { if (detected) {
portexpander_read(PE_C_INPUT_PORT, &buf); portexpander_read(PE_C_INPUT_PORT, &buf);
} }
return buf; return buf & mask;
} }
/* ************************************************************************** */
bool portexpander_detected(void) bool portexpander_detected(void)
{ {
return detected; return detected;
} }
void portexpander_set(uint8_t pin, uint8_t value) /* ************************************************************************** */
void portexpander_out_set(uint8_t mask)
{ {
if (detected && pin < 8) { if (detected) {
if (value) { output_state |= mask;
output_state |= (1 << pin); portexpander_write(PE_C_OUTPUT_PORT, output_state);
} else { }
output_state &= ~(1 << pin);
} }
/* ************************************************************************** */
void portexpander_out_clr(uint8_t mask)
{
if (detected) {
output_state &= ~mask;
portexpander_write(PE_C_OUTPUT_PORT, output_state); portexpander_write(PE_C_OUTPUT_PORT, output_state);
} }
} }
void portexpander_prep(uint8_t pin, uint8_t value) /* ************************************************************************** */
uint8_t portexpander_out_get(uint8_t mask)
{ {
if (pin < 8) { return output_state & mask;
if (value) {
output_state |= (1 << pin);
} else {
output_state &= ~(1 << pin);
} }
/* ************************************************************************** */
void portexpander_out_put(uint8_t mask, uint8_t val)
{
if (detected) {
output_state = (output_state & ~mask) | (val & mask);
portexpander_write(PE_C_OUTPUT_PORT, output_state);
} }
} }
void portexpander_update(void) /* ************************************************************************** */
void portexpander_out_toggle(uint8_t mask)
{ {
if (detected) { if (detected) {
output_state ^= mask;
portexpander_write(PE_C_OUTPUT_PORT, output_state); portexpander_write(PE_C_OUTPUT_PORT, output_state);
} }
} }
void portexpander_set_mask(uint8_t mask, uint8_t values) /* ************************************************************************** */
void portexpander_int_config(uint8_t mask, gpio_int_pol_t edge)
{ {
if (detected) { if (detected) {
output_state &= ~(mask & ~values); for (uint8_t pin = 0; pin < 8; ++pin) {
output_state |= mask & values; if (mask & (1 << pin)) {
portexpander_write(PE_C_OUTPUT_PORT, output_state); int_edge_config[pin] = edge;
}
}
}
}
/* ************************************************************************** */
void portexpander_int_enable(uint8_t mask)
{
if (detected) {
int_mask_state &= ~mask;
portexpander_write(PE_C_INT_MASK, int_mask_state);
}
}
/* ************************************************************************** */
void portexpander_int_disable(uint8_t mask)
{
if (detected) {
int_mask_state |= mask;
portexpander_write(PE_C_INT_MASK, int_mask_state);
}
}
/* ************************************************************************** */
uint8_t portexpander_int_status()
{
uint8_t buf = 0;
if (detected) {
portexpander_read(PE_C_INT_STATUS, &buf);
}
return buf;
}
/* ************************************************************************** */
void portexpander_int_clr(uint8_t mask)
{
if (detected) {
uint8_t tmp_mask = int_mask_state | mask;
// Setting an interrupt mask clears the corresponding interrupt
portexpander_write(PE_C_INT_MASK, tmp_mask);
portexpander_write(PE_C_INT_MASK, int_mask_state);
}
}
/* ************************************************************************** */
int portexpander_register_callback(
uint8_t mask, pe_callback callback, void *cbdata
) {
if (!detected) {
return E_NO_DEVICE;
}
for (uint8_t pin = 0; pin < 8; ++pin) {
if (mask & (1 << pin)) {
callbacks[pin] = callback;
cbparam[pin] = cbdata;
}
}
return E_NO_ERROR;
}
/* ************************************************************************** */
__attribute__((weak)) void portexpander_interrupt_callback(void *_)
{
GPIO_IntDisable(&pe_int_pin);
GPIO_IntClr(&pe_int_pin);
interrupt_pending = true;
}
/* ************************************************************************** */
void portexpander_poll()
{
if (detected && interrupt_pending) {
interrupt_pending = false;
uint8_t caused_by = portexpander_int_status();
// Port read resets interrupts
uint8_t port_levels = portexpander_in_get(0xFF);
GPIO_IntEnable(&pe_int_pin);
for (uint8_t pin = 0; pin < 8; ++pin) {
if ((caused_by & (1 << pin)) && callbacks[pin]) {
gpio_int_pol_t edge_type =
(port_levels & (1 << pin) ?
GPIO_INT_RISING :
GPIO_INT_FALLING);
if ((int_edge_config[pin] == GPIO_INT_BOTH) ||
(edge_type == int_edge_config[pin])) {
callbacks[pin](edge_type, cbparam[pin]);
}
}
}
} }
} }