Skip to content
GitLab
Menu
Projects
Groups
Snippets
Help
Help
Support
Community forum
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
Menu
Open sidebar
Stefan Haun
firmware
Commits
ee7f15a0
Commit
ee7f15a0
authored
Sep 05, 2019
by
Rahix
Browse files
Merge 'Implement portexpander button callbacks'
See merge request
card10/firmware!73
parents
0ba05918
a858261f
Changes
8
Hide whitespace changes
Inline
Side-by-side
epicardium/modules/buttons.c
View file @
ee7f15a0
...
...
@@ -26,7 +26,7 @@ uint8_t epic_buttons_read(uint8_t mask)
* Not using PB_Get() here as that performs one I2C transcation
* per button.
*/
uint8_t
pin_status
=
~
portexpander_get
();
uint8_t
pin_status
=
~
portexpander_
in_
get
(
0xFF
);
hwlock_release
(
HWLOCK_I2C
);
...
...
lib/card10/card10.c
View file @
ee7f15a0
...
...
@@ -215,6 +215,7 @@ void core1_stop(void)
void
card10_poll
(
void
)
{
pmic_poll
();
portexpander_poll
();
}
void
card10_reset
(
void
)
...
...
lib/card10/display.c
View file @
ee7f15a0
...
...
@@ -22,7 +22,7 @@ void display_set_reset_pin(uint8_t state)
if
(
!
portexpander_detected
())
{
MAX77650_setDO
(
state
?
true
:
false
);
}
else
{
portexpander_
set
(
4
,
state
);
portexpander_
out_put
(
PIN_
4
,
state
);
}
}
...
...
lib/card10/leds.c
View file @
ee7f15a0
...
...
@@ -285,10 +285,7 @@ static uint8_t power_pin_conversion(uint8_t group)
static
void
power_all
(
void
)
{
for
(
int
i
=
0
;
i
<
3
;
i
++
)
{
portexpander_prep
(
i
,
0
);
}
portexpander_update
();
portexpander_out_clr
(
PIN_0
|
PIN_1
|
PIN_2
);
}
void
leds_update_power
(
void
)
...
...
@@ -301,14 +298,14 @@ void leds_update_power(void)
if
(
new_groups
==
active_groups
)
{
return
;
}
for
(
int
i
=
0
;
i
<
3
;
i
++
)
{
if
(
i
<
new_groups
)
{
portexpander_prep
(
power_pin_conversion
(
i
),
0
);
}
else
{
portexpander_prep
(
power_pin_conversion
(
i
),
1
);
}
uint8_t
out_val
=
0
;
for
(
int
i
=
new_groups
;
i
<
3
;
++
i
)
{
out_val
|=
(
1
<<
power_pin_conversion
(
i
));
}
portexpander_update
();
portexpander_out_put
(
PIN_0
|
PIN_1
|
PIN_2
,
out_val
);
if
(
active_groups
<
new_groups
)
{
for
(
int
i
=
0
;
i
<
powerup_wait_cycles
;
i
++
)
{
__NOP
();
...
...
@@ -343,7 +340,7 @@ void leds_update(void)
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
])
...
...
lib/card10/pb.c
View file @
ee7f15a0
...
...
@@ -40,6 +40,10 @@
#include
"portexpander.h"
#include
"MAX77650-Arduino-Library.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
)
{
...
...
@@ -59,24 +63,71 @@ int PB_Init(void)
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
)
{
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
)
{
// Register callback
GPIO_RegisterCallback
(
&
pb_pin
[
pb
],
callback
,
(
void
*
)
pb
);
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
GPIO_RegisterCallback
(
&
pb_pin
[
pb
-
1
],
gpio_pb_callback
,
(
void
*
)
pb
);
// Configure and enable interrupt
GPIO_IntConfig
(
&
pb_pin
[
pb
],
GPIO_INT_EDGE
,
GPIO_INT_FALLING
);
GPIO_IntEnable
(
&
pb_pin
[
pb
]);
NVIC_EnableIRQ
((
IRQn_Type
)
MXC_GPIO_GET_IRQ
(
pb_pin
[
pb
].
port
));
// Configure and enable interrupt
GPIO_IntConfig
(
&
pb_pin
[
pb
-
1
],
GPIO_INT_EDGE
,
GPIO_INT_BOTH
);
GPIO_IntEnable
(
&
pb_pin
[
pb
-
1
]);
NVIC_EnableIRQ
((
IRQn_Type
)
MXC_GPIO_GET_IRQ
(
pb_pin
[
pb
-
1
].
port
)
);
}
}
else
{
// Disable interrupt and clear callback
GPIO_IntDisable
(
&
pb_pin
[
pb
]);
GPIO_RegisterCallback
(
&
pb_pin
[
pb
],
NULL
,
NULL
);
if
(
portexpander_detected
())
{
// Disable interrupt and clear callback
portexpander_int_disable
(
mask
);
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
;
...
...
@@ -85,25 +136,46 @@ int PB_RegisterCallback(unsigned int pb, pb_callback callback)
//******************************************************************************
void
PB_IntEnable
(
unsigned
int
pb
)
{
// TODO: portexpander support
MXC_ASSERT
(
pb
<
num_pbs
);
GPIO_IntEnable
(
&
pb_pin
[
pb
]);
MXC_ASSERT
((
pb
>
0
)
&&
(
pb
<=
num_pbs
));
if
(
pb
==
2
)
{
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
)
{
// TODO: portexpander support
MXC_ASSERT
(
pb
<
num_pbs
);
GPIO_IntDisable
(
&
pb_pin
[
pb
]);
MXC_ASSERT
((
pb
>
0
)
&&
(
pb
<=
num_pbs
));
if
(
pb
==
2
)
{
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
)
{
// TODO: portexpander support
MXC_ASSERT
(
pb
<
num_pbs
);
GPIO_IntClr
(
&
pb_pin
[
pb
]);
MXC_ASSERT
((
pb
>
0
)
&&
(
pb
<=
num_pbs
));
if
(
pb
==
2
)
{
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)
case
3
:
case
4
:
if
(
portexpander_detected
())
{
uint8_t
port
=
portexpander_get
(
);
return
(
port
&
(
1
<<
expander_pins
[
pb
-
1
]))
==
0
;
return
portexpander_
in_
get
(
(
1
<<
expander_pins
[
pb
-
1
]))
==
0
;
}
else
{
return
GPIO_InGet
(
&
pb_pin
[
pb
-
1
])
==
0
;
}
...
...
lib/card10/pb.h
0 → 100644
View file @
ee7f15a0
/**
* @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_ */
lib/card10/portexpander.c
View file @
ee7f15a0
/* PCAL6408A I2C port expander */
/* **** Includes **** */
#include
"portexpander.h"
#include
"mxc_config.h"
#include
"mxc_assert.h"
#include
"i2c.h"
#include
<stdio.h>
...
...
@@ -7,10 +12,7 @@
#include
<string.h>
#include
<stdbool.h>
// PCAL6408A I2C port expander
static
bool
detected
=
false
;
static
uint8_t
output_state
;
/* **** Definitions **** */
/* clang-format off */
#define PE_ADDR 0x42
...
...
@@ -40,95 +42,296 @@ static uint8_t output_state;
#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
)
{
uint8_t
i2c_data
[
2
]
=
{
command
,
data
};
return
I2C_MasterWrite
(
MXC_I2C1_BUS0
,
PE_ADDR
,
i2c_data
,
2
,
0
);
}
/* ************************************************************************** */
static
int
portexpander_read
(
uint8_t
command
,
uint8_t
*
data
)
{
I2C_MasterWrite
(
MXC_I2C1_BUS0
,
PE_ADDR
,
&
command
,
1
,
1
);
return
I2C_MasterRead
(
MXC_I2C1_BUS0
,
PE_ADDR
,
data
,
1
,
0
);
}
void
portexpander_init
(
void
)
/* ************************************************************************** */
int
portexpander_init
(
void
)
{
int
ret
;
// Enable pull-ups for buttons (type defaults to pull-up)
ret
=
portexpander_write
(
PE_C_PULL_ENABLE
,
PE_INPUT_MASK
);
// Set _all_ outputs to open-drain to support the high side p-channel transistors.
ret
=
portexpander_write
(
PE_C_OUTPUT_PORT_CONFIG
,
PE_OUT_OPEN_DRAIN
);
if
(
ret
!=
2
)
{
printf
(
"portexpander NOT detected
\n
"
);
detected
=
false
;
return
;
return
E_NO_DEVICE
;
}
detected
=
true
;
// Set
_all_
outputs to
open-drain to support the high side p-channel transistors.
portexpander_
write
(
PE_C_OUTPUT_PORT_CONFIG
,
PE_OUT_OPEN_DRAIN
);
// Set outputs to
high
portexpander_
out_set
(
~
PE_INPUT_MASK
);
// Enable pull-ups for buttons
// 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
);
}
// Latch inputs so we can figure out whether an interrupt was caused by a rising or falling edge
portexpander_write
(
PE_C_INPUT_LATCH
,
PE_INPUT_MASK
);
// 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
;
}
// Set outputs to high (i.e. open-drain)
output_state
=
~
PE_INPUT_MASK
;
portexpander_write
(
PE_C_OUTPUT_PORT
,
output_state
);
/* ************************************************************************** */
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
;
}
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_get
(
void
)
/* ************************************************************************** */
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
;
if
(
detected
)
{
portexpander_read
(
PE_C_INPUT_PORT
,
&
buf
);
}
return
buf
;
return
buf
&
mask
;
}
/* ************************************************************************** */
bool
portexpander_detected
(
void
)
{
return
detected
;
}
void
portexpander_set
(
uint8_t
pin
,
uint8_t
value
)
/* ************************************************************************** */
void
portexpander_out_set
(
uint8_t
mask
)
{
if
(
detected
&&
pin
<
8
)
{
if
(
value
)
{
output_state
|=
(
1
<<
pin
);
}
else
{
output_state
&=
~
(
1
<<
pin
);
}
if
(
detected
)
{
output_state
|=
mask
;
portexpander_write
(
PE_C_OUTPUT_PORT
,
output_state
);
}
}
void
portexpander_prep
(
uint8_t
pin
,
uint8_t
value
)
/* ************************************************************************** */
void
portexpander_out_clr
(
uint8_t
mask
)
{
if
(
pin
<
8
)
{
if
(
value
)
{
output_state
|=
(
1
<<
pin
);
}
else
{
output_state
&=
~
(
1
<<
pin
);
}
if
(
detected
)
{
output_state
&=
~
mask
;
portexpander_write
(
PE_C_OUTPUT_PORT
,
output_state
);
}
}
void
portexpander_update
(
void
)
/* ************************************************************************** */
uint8_t
portexpander_out_get
(
uint8_t
mask
)
{
return
output_state
&
mask
;
}
/* ************************************************************************** */
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_set_mask
(
uint8_t
mask
,
uint8_t
values
)
/* ************************************************************************** */
void
portexpander_out_toggle
(
uint8_t
mask
)
{
if
(
detected
)
{
output_state
&=
~
(
mask
&
~
values
);
output_state
|=
mask
&
values
;
output_state
^=
mask
;
portexpander_write
(
PE_C_OUTPUT_PORT
,
output_state
);
}
}
/* ************************************************************************** */
void
portexpander_int_config
(
uint8_t
mask
,
gpio_int_pol_t
edge
)
{
if
(
detected
)
{
for
(
uint8_t
pin
=
0
;
pin
<
8
;
++
pin
)
{
if
(
mask
&
(
1
<<
pin
))
{
int_edge_config
[
pin
]
=
edge
;
}
}