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

Merge 'Implement portexpander button callbacks'

See merge request !73
parents 0ba05918 a858261f
Branches
Tags
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