Statistics
| Branch: | Tag: | Revision:

amiro-lld / source / alld_pcal6524.c @ ef078306

History | View | Annotate | Download (11.949 KB)

1
/*
2
AMiRo-LLD is a compilation of low-level hardware drivers for the Autonomous Mini Robot (AMiRo) platform.
3
Copyright (C) 2016..2019  Thomas Schöpping et al.
4

5
This program is free software: you can redistribute it and/or modify
6
it under the terms of the GNU Lesser General Public License as published by
7
the Free Software Foundation, either version 3 of the License, or
8
(at your option) any later version.
9

10
This program is distributed in the hope that it will be useful,
11
but WITHOUT ANY WARRANTY; without even the implied warranty of
12
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13
GNU Lesser General Public License for more details.
14

15
You should have received a copy of the GNU Lesser General Public License
16
along with this program.  If not, see <http://www.gnu.org/licenses/>.
17
*/
18

    
19
/**
20
 * @file    alld_pcal6524.c
21
 * @brief   GPIO extender function implementations.
22
 *
23
 * @addtogroup lld_gpioext
24
 * @{
25
 */
26

    
27
#include <alld_pcal6524.h>
28

    
29
#if defined(AMIROLLD_CFG_USE_PCAL6524) || defined(__DOXYGEN__)
30

    
31
#include <string.h>
32

    
33
/******************************************************************************/
34
/* LOCAL DEFINITIONS                                                          */
35
/******************************************************************************/
36

    
37
#define _MAXIMUM_GROUP_SIZE           6
38

    
39
/******************************************************************************/
40
/* EXPORTED VARIABLES                                                         */
41
/******************************************************************************/
42

    
43
/******************************************************************************/
44
/* LOCAL TYPES                                                                */
45
/******************************************************************************/
46

    
47
/******************************************************************************/
48
/* LOCAL VARIABLES                                                            */
49
/******************************************************************************/
50

    
51
/******************************************************************************/
52
/* LOCAL FUNCTIONS                                                            */
53
/******************************************************************************/
54

    
55
/******************************************************************************/
56
/* EXPORTED FUNCTIONS                                                         */
57
/******************************************************************************/
58

    
59
/**
60
 * @brief   Returns the size of the group for a specified command.
61
 *
62
 * @param[in] cmd   Command to retrieve the group size for.
63
 *
64
 * @return    The size of the group in bytes.
65
 */
66
inline uint8_t pcal6524_lld_cmd_groupsize(const pcal6524_lld_cmd_t cmd)
67
{
68
  switch (cmd) {
69
    case PCAL6524_LLD_CMD_OUTPUTCONFIGURATION:
70
    case PCAL6524_LLD_CMD_SWITCHDEBOUNCECOUNT:
71
      return 1;
72
    case PCAL6524_LLD_CMD_SWITCHDEBOUNCEENABLE_P0:
73
    case PCAL6524_LLD_CMD_SWITCHDEBOUNCEENABLE_P1:
74
      return 2;
75
    case PCAL6524_LLD_CMD_INPUT_P0:
76
    case PCAL6524_LLD_CMD_INPUT_P1:
77
    case PCAL6524_LLD_CMD_INPUT_P2:
78
    case PCAL6524_LLD_CMD_OUTPUT_P0:
79
    case PCAL6524_LLD_CMD_OUTPUT_P1:
80
    case PCAL6524_LLD_CMD_OUTPUT_P2:
81
    case PCAL6524_LLD_CMD_POLARITYINVERSION_P0:
82
    case PCAL6524_LLD_CMD_POLARITYINVERSION_P1:
83
    case PCAL6524_LLD_CMD_POLARITYINVERSION_P2:
84
    case PCAL6524_LLD_CMD_CONFIGURATION_P0:
85
    case PCAL6524_LLD_CMD_CONFIGURATION_P1:
86
    case PCAL6524_LLD_CMD_CONFIGURATION_P2:
87
    case PCAL6524_LLD_CMD_INPUTLATCH_P0:
88
    case PCAL6524_LLD_CMD_INPUTLATCH_P1:
89
    case PCAL6524_LLD_CMD_INPUTLATCH_P2:
90
    case PCAL6524_LLD_CMD_PUPDENABLE_P0:
91
    case PCAL6524_LLD_CMD_PUPDENABLE_P1:
92
    case PCAL6524_LLD_CMD_PUPDENABLE_P2:
93
    case PCAL6524_LLD_CMD_PUPDSELECTION_P0:
94
    case PCAL6524_LLD_CMD_PUPDSELECTION_P1:
95
    case PCAL6524_LLD_CMD_PUPDSELECTION_P2:
96
    case PCAL6524_LLD_CMD_INTERRUPTMASK_P0:
97
    case PCAL6524_LLD_CMD_INTERRUPTMASK_P1:
98
    case PCAL6524_LLD_CMD_INTERRUPTMASK_P2:
99
    case PCAL6524_LLD_CMD_INTERRUPTSTATUS_P0:
100
    case PCAL6524_LLD_CMD_INTERRUPTSTATUS_P1:
101
    case PCAL6524_LLD_CMD_INTERRUPTSTATUS_P2:
102
    case PCAL6524_LLD_CMD_INTERRUPTCLEAR_P0:
103
    case PCAL6524_LLD_CMD_INTERRUPTCLEAR_P1:
104
    case PCAL6524_LLD_CMD_INTERRUPTCLEAR_P2:
105
    case PCAL6524_LLD_CMD_INPUTSTATUS_P0:
106
    case PCAL6524_LLD_CMD_INPUTSTATUS_P1:
107
    case PCAL6524_LLD_CMD_INPUTSTATUS_P2:
108
    case PCAL6524_LLD_CMD_INDIVIDUALPINOUTPUTCONFIGURATION_P0:
109
    case PCAL6524_LLD_CMD_INDIVIDUALPINOUTPUTCONFIGURATION_P1:
110
    case PCAL6524_LLD_CMD_INDIVIDUALPINOUTPUTCONFIGURATION_P2:
111
      return 3;
112
    case PCAL6524_LLD_CMD_OUTPUTDRIVESTRENGTH_P0A:
113
    case PCAL6524_LLD_CMD_OUTPUTDRIVESTRENGTH_P0B:
114
    case PCAL6524_LLD_CMD_OUTPUTDRIVESTRENGTH_P1A:
115
    case PCAL6524_LLD_CMD_OUTPUTDRIVESTRENGTH_P1B:
116
    case PCAL6524_LLD_CMD_OUTPUTDRIVESTRENGTH_P2A:
117
    case PCAL6524_LLD_CMD_OUTPUTDRIVESTRENGTH_P2B:
118
    case PCAL6524_LLD_CMD_INTERRUPTEDGE_P0A:
119
    case PCAL6524_LLD_CMD_INTERRUPTEDGE_P0B:
120
    case PCAL6524_LLD_CMD_INTERRUPTEDGE_P1A:
121
    case PCAL6524_LLD_CMD_INTERRUPTEDGE_P1B:
122
    case PCAL6524_LLD_CMD_INTERRUPTEDGE_P2A:
123
    case PCAL6524_LLD_CMD_INTERRUPTEDGE_P2B:
124
      return 6;
125
  }
126
  // must never occur
127
  apalDbgAssert(false);
128
  return 0;
129
}
130

    
131
/*============================================================================*/
132
/* general register access                                                    */
133
/*============================================================================*/
134

    
135
// Reading the ID is currently not supported, since the required I²C sequence can not trivially executed via periphAL and ChibiOS/HAL.
136
///**
137
// * @brief   Read device ID and manufacturer information.
138
// *
139
// * @param[in]   pcal6524d   The PCAL6524 driver to use.
140
// * @param[out]  info        Pointer where to store the information data.
141
// * @param[in]   timeout     Timeout for the function to return.
142
// *
143
// * @return    Indicator whether the function call was successful or a timeout occurred.
144
// */
145
//inline apalExitStatus_t
146
//pcal6524_lld_read_id(const PCAL6524Driver* const pcal6524d, pcal6524_lld_deviceid_t* const info, const apalTime_t timeout)
147
//{
148
//  apalDbgAssert(pcal6524d != NULL && pcal6524d->i2cd != NULL);
149
//  apalDbgAssert(info != NULL);
150
//
151
//  const uint8_t txbuf = (uint8_t)pcal6524d->addr;
152
//  return apalI2CMasterTransmit(pcal6524d->i2cd, PCAL6524_LLD_I2C_ADDR_DEVICEID, &txbuf, 1, info->raw, sizeof(info->raw), timeout);
153
//}
154

    
155
/**
156
 * @brief   Read 8bit data from any register.
157
 *
158
 * @param[in]   pcal6524d       The PCAL6524 driver to use.
159
 * @param[in]   reg             Command register to read.
160
 * @param[out]  data            Pointer to store the register data to.
161
 * @param[in]   timeout         Timeout for the function to return (in microseconds).
162
 *
163
 * @return    Indicator whether the function call was successful or a timeout occurred.
164
 */
165
inline apalExitStatus_t
166
pcal6524_lld_read_reg(const PCAL6524Driver* const pcal6524d, const pcal6524_lld_cmd_t reg, uint8_t* const data, const apalTime_t timeout)
167
{
168
  apalDbgAssert(pcal6524d != NULL && pcal6524d->i2cd != NULL);
169
  apalDbgAssert(data != NULL);
170

    
171
  const uint8_t txbuf = (uint8_t)reg;
172
  return apalI2CMasterTransmit(pcal6524d->i2cd, pcal6524d->addr, &txbuf, 1, data, 1, timeout);
173
}
174

    
175
/**
176
 * @brief   Write 8bit data to any (writable) register.
177
 *
178
 * @param[in]   pcal6524d       The PCAL6524 driver to use.
179
 * @param[in]   reg             Command register to write to.
180
 * @param[in]   data            Data to transmit.
181
 * @param[in]   timeout         Timout for the function to return (in microseconds).
182
 *
183
 * @return    Indicator whether the function call was successful or a timeout occurred.
184
 */
185
inline apalExitStatus_t
186
pcal6524_lld_write_reg(const PCAL6524Driver* const pcal6524d, const pcal6524_lld_cmd_t reg, const uint8_t data, const apalTime_t timeout)
187
{
188
  apalDbgAssert(pcal6524d != NULL && pcal6524d->i2cd != NULL);
189

    
190
  uint8_t txbuf[2] = { (uint8_t)reg, data };
191
  return apalI2CMasterTransmit(pcal6524d->i2cd, pcal6524d->addr, txbuf, 2, NULL, 0, timeout);
192
}
193

    
194
/**
195
 * @brief   Read register group starting with an arbitrary register.
196
 *
197
 * @param[in]   pcal6524d   The PCAL6524 driver to use.
198
 * @param[in]   reg         Command register to start at.
199
 * @param[out]  data        Pointer to store rhe group data to.
200
 *                          The reqired number of bytes depends on the group.
201
 * @param[in]   timeout     Timeout for the function to return (in microseconds).
202
 *
203
 * @return    Indicator whether the function call was successful or a timeout occurred.
204
 */
205
inline apalExitStatus_t
206
pcal6524_lld_read_group(const PCAL6524Driver* const pcal6524d, const pcal6524_lld_cmd_t reg, uint8_t* const data, const apalTime_t timeout)
207
{
208
  apalDbgAssert(pcal6524d != NULL && pcal6524d->i2cd != NULL);
209
  apalDbgAssert(data != NULL);
210

    
211
  const uint8_t txbuf = (uint8_t)reg;
212
  return apalI2CMasterTransmit(pcal6524d->i2cd, pcal6524d->addr, &txbuf, 1, data, pcal6524_lld_cmd_groupsize(reg), timeout);
213
}
214

    
215
/**
216
 * @brief   Write register group data to any (writable) register.
217
 *
218
 * @param[in]   pcal6524d       The PCAL6524 driver to use.
219
 * @param[in]   reg             Command register to start at.
220
 * @param[in]   data            Data to transmit.
221
 *                              The reqired number of bytes depends on the group.
222
 * @param[in]   timeout         Timout for the function to return (in microseconds).
223
 *
224
 * @return    Indicator whether the function call was successful or a timeout occurred.
225
 */
226
inline apalExitStatus_t
227
pcal6524_lld_write_group(const PCAL6524Driver* const pcal6524d, const pcal6524_lld_cmd_t reg, const uint8_t* const data, const apalTime_t timeout)
228
{
229
  apalDbgAssert(pcal6524d != NULL && pcal6524d->i2cd != NULL);
230
  apalDbgAssert(data != NULL);
231

    
232
  uint8_t txbuf[_MAXIMUM_GROUP_SIZE + 1] = {(uint8_t)reg};
233
  memcpy(&txbuf[1], data, pcal6524_lld_cmd_groupsize(reg));
234
  return apalI2CMasterTransmit(pcal6524d->i2cd, pcal6524d->addr, txbuf, pcal6524_lld_cmd_groupsize(reg) + 1, NULL, 0, timeout);
235
}
236

    
237
/**
238
 * @brief   Read multiple registers continously, starting at an arbitrary one.
239
 *
240
 * @param[in]   pcal6524d   The PCAL6524 driver to use.
241
 * @param[in]   reg         Command register to start at.
242
 * @param[out]  data        Pointer to store the group data to.
243
 * @param[in]   length      Number of registers/bytes to read.
244
 * @param[in]   timeout     Timeout for the function to return (in microseconds).
245
 *
246
 * @return    Indicator whether the function call was successful or a timeout occurred.
247
 */
248
inline apalExitStatus_t
249
pcal6524_lld_read_continuous(const PCAL6524Driver* const pcal6524d, const pcal6524_lld_cmd_t reg, uint8_t* const data, const uint8_t length, const apalTime_t timeout)
250
{
251
  apalDbgAssert(pcal6524d != NULL && pcal6524d->i2cd != NULL);
252
  apalDbgAssert(data != NULL);
253
  apalDbgAssert(length <= PCAL6524_LLD_NUM_REGISTERS);
254

    
255
  uint8_t txbuf = (uint8_t)reg | PCAL6524_LLD_CMD_AUTOINCREMENT;
256
  return apalI2CMasterTransmit(pcal6524d->i2cd, pcal6524d->addr, &txbuf, 1, data, length, timeout);
257
}
258

    
259
/**
260
 * @brief   Write multiple registers continously, starting at an arbitrary one.
261
 *
262
 * @param[in]   pcal6524d   The PCAL6524 driver to use.
263
 * @param[in]   reg         Command register to start at.
264
 * @param[in]   data        Pointer to the data to write.
265
 * @param[in]   length      Number of registers/bytes to write.
266
 * @param[in]   timeout     Timeout for the function to return (in microseconds).
267
 *
268
 * @return    Indicator whether the function call was successful or a timeout occurred.
269
 */
270
inline apalExitStatus_t
271
pcal6524_lld_write_continuous(const PCAL6524Driver* const pcal6524d, const pcal6524_lld_cmd_t reg, const uint8_t* const data, const uint8_t length, const apalTime_t timeout)
272
{
273
  apalDbgAssert(pcal6524d != NULL && pcal6524d->i2cd != NULL);
274
  apalDbgAssert(data != NULL);
275
  apalDbgAssert(length <= PCAL6524_LLD_NUM_REGISTERS);
276

    
277
  uint8_t txbuf[PCAL6524_LLD_NUM_REGISTERS + 1] = {(uint8_t)reg | PCAL6524_LLD_CMD_AUTOINCREMENT};
278
  memcpy(&txbuf[1], data, length);
279
  return apalI2CMasterTransmit(pcal6524d->i2cd, pcal6524d->addr, txbuf, length + 1, NULL, 0, timeout);
280
}
281

    
282
#endif /* defined(AMIROLLD_CFG_USE_PCAL6524) */
283

    
284
/** @} */