Skip to content
Snippets Groups Projects
Commit ee7f15a0 authored by rahix's avatar rahix
Browse files

Merge 'Implement portexpander button callbacks'

See merge request card10/firmware!73
parents 0ba05918 a858261f
No related branches found
No related tags found
No related merge requests found
...@@ -26,7 +26,7 @@ uint8_t epic_buttons_read(uint8_t mask) ...@@ -26,7 +26,7 @@ uint8_t epic_buttons_read(uint8_t mask)
* Not using PB_Get() here as that performs one I2C transcation * Not using PB_Get() here as that performs one I2C transcation
* per button. * per button.
*/ */
uint8_t pin_status = ~portexpander_get(); uint8_t pin_status = ~portexpander_in_get(0xFF);
hwlock_release(HWLOCK_I2C); hwlock_release(HWLOCK_I2C);
......
...@@ -215,6 +215,7 @@ void core1_stop(void) ...@@ -215,6 +215,7 @@ void core1_stop(void)
void card10_poll(void) void card10_poll(void)
{ {
pmic_poll(); pmic_poll();
portexpander_poll();
} }
void card10_reset(void) void card10_reset(void)
......
...@@ -22,7 +22,7 @@ void display_set_reset_pin(uint8_t state) ...@@ -22,7 +22,7 @@ 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);
} }
} }
......
...@@ -285,10 +285,7 @@ static uint8_t power_pin_conversion(uint8_t group) ...@@ -285,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)
...@@ -301,14 +298,14 @@ void leds_update_power(void) ...@@ -301,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();
...@@ -343,7 +340,7 @@ void leds_update(void) ...@@ -343,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 : 1);
} }
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])
......
...@@ -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_ */
/* 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,296 @@ static uint8_t output_state; ...@@ -40,95 +42,296 @@ 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 (int i = 0; i < sizeof(pe_pin_config) / sizeof(pe_pin_config[0]);
i++) {
MXC_ASSERT(
portexpander_config(&pe_pin_config[i]) == 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_ENABLE, 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]);
}
}
}
} }
} }
#ifndef PORTEXPANDER_H #ifndef PORTEXPANDER_H
#define PORTEXPANDER_H #define PORTEXPANDER_H
#include "mxc_config.h"
#include <stdint.h> #include <stdint.h>
#include <stdbool.h> #include <stdbool.h>
void portexpander_init(void); /**
uint8_t portexpander_get(void); * Structure type for configuring the portexpander.
void portexpander_set(uint8_t pin, uint8_t value); */
void portexpander_set_mask(uint8_t mask, uint8_t values); typedef struct {
void portexpander_prep(uint8_t pin, uint8_t value); uint8_t mask; /**< Pin mask (multiple pins may be set) */
void portexpander_update(void); gpio_func_t func; /**< Function type */
gpio_pad_t pad; /**< Pad type */
} portexpander_cfg_t;
typedef void (*pe_callback)(gpio_int_pol_t edge_type, void *cbdata);
int portexpander_init(void);
bool portexpander_detected(void); bool portexpander_detected(void);
int portexpander_config(const portexpander_cfg_t *cfg);
uint8_t portexpander_in_get(uint8_t mask);
void portexpander_out_set(uint8_t mask);
void portexpander_out_clr(uint8_t mask);
void portexpander_out_put(uint8_t mask, uint8_t val);
void portexpander_out_toggle(uint8_t mask);
uint8_t portexpander_out_get(uint8_t mask);
void portexpander_int_config(uint8_t mask, gpio_int_pol_t edge);
void portexpander_int_enable(uint8_t mask);
void portexpander_int_disable(uint8_t mask);
uint8_t portexpander_int_status();
void portexpander_int_clr(uint8_t mask);
int portexpander_register_callback(uint8_t mask, pe_callback callback, void *cbdata);
void portexpander_poll();
void portexpander_interrupt_callback(void *_);
#endif #endif
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment