Statistics
| Branch: | Tag: | Revision:

amiro-lld / drivers / PCAL6524 / v1 / alld_PCAL6524.c @ 72369edc

History | View | Annotate | Download (11.792 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
#include <string.h>
30

    
31
/******************************************************************************/
32
/* LOCAL DEFINITIONS                                                          */
33
/******************************************************************************/
34

    
35
#define MAXIMUM_GROUP_SIZE                      6
36

    
37
/******************************************************************************/
38
/* EXPORTED VARIABLES                                                         */
39
/******************************************************************************/
40

    
41
/******************************************************************************/
42
/* LOCAL TYPES                                                                */
43
/******************************************************************************/
44

    
45
/******************************************************************************/
46
/* LOCAL VARIABLES                                                            */
47
/******************************************************************************/
48

    
49
/******************************************************************************/
50
/* LOCAL FUNCTIONS                                                            */
51
/******************************************************************************/
52

    
53
/******************************************************************************/
54
/* EXPORTED FUNCTIONS                                                         */
55
/******************************************************************************/
56

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

    
129
/*============================================================================*/
130
/* general register access                                                    */
131
/*============================================================================*/
132

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

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

    
167
  const uint8_t txbuf = (uint8_t)reg;
168
  return apalI2CMasterTransmit(pcal6524d->i2cd, pcal6524d->addr, &txbuf, 1, data, 1, timeout);
169
}
170

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

    
185
  uint8_t txbuf[2] = { (uint8_t)reg, data };
186
  return apalI2CMasterTransmit(pcal6524d->i2cd, pcal6524d->addr, txbuf, 2, NULL, 0, timeout);
187
}
188

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

    
205
  const uint8_t txbuf = (uint8_t)reg;
206
  return apalI2CMasterTransmit(pcal6524d->i2cd, pcal6524d->addr, &txbuf, 1, data, pcal6524_lld_cmd_groupsize(reg), timeout);
207
}
208

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

    
225
  uint8_t txbuf[MAXIMUM_GROUP_SIZE + 1] = {(uint8_t)reg};
226
  memcpy(&txbuf[1], data, pcal6524_lld_cmd_groupsize(reg));
227
  return apalI2CMasterTransmit(pcal6524d->i2cd, pcal6524d->addr, txbuf, pcal6524_lld_cmd_groupsize(reg) + 1, NULL, 0, timeout);
228
}
229

    
230
/**
231
 * @brief   Read multiple registers continously, starting at an arbitrary one.
232
 *
233
 * @param[in]   pcal6524d   The PCAL6524 driver to use.
234
 * @param[in]   reg         Command register to start at.
235
 * @param[out]  data        Pointer to store the group data to.
236
 * @param[in]   length      Number of registers/bytes to read.
237
 * @param[in]   timeout     Timeout for the function to return (in microseconds).
238
 *
239
 * @return    Indicator whether the function call was successful or a timeout occurred.
240
 */
241
apalExitStatus_t 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)
242
{
243
  apalDbgAssert(pcal6524d != NULL && pcal6524d->i2cd != NULL);
244
  apalDbgAssert(data != NULL);
245
  apalDbgAssert(length <= PCAL6524_LLD_NUM_REGISTERS);
246

    
247
  uint8_t txbuf = (uint8_t)reg | PCAL6524_LLD_CMD_AUTOINCREMENT;
248
  return apalI2CMasterTransmit(pcal6524d->i2cd, pcal6524d->addr, &txbuf, 1, data, length, timeout);
249
}
250

    
251
/**
252
 * @brief   Write multiple registers continously, starting at an arbitrary one.
253
 *
254
 * @param[in]   pcal6524d   The PCAL6524 driver to use.
255
 * @param[in]   reg         Command register to start at.
256
 * @param[in]   data        Pointer to the data to write.
257
 * @param[in]   length      Number of registers/bytes to write.
258
 * @param[in]   timeout     Timeout for the function to return (in microseconds).
259
 *
260
 * @return    Indicator whether the function call was successful or a timeout occurred.
261
 */
262
apalExitStatus_t 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)
263
{
264
  apalDbgAssert(pcal6524d != NULL && pcal6524d->i2cd != NULL);
265
  apalDbgAssert(data != NULL);
266
  apalDbgAssert(length <= PCAL6524_LLD_NUM_REGISTERS);
267

    
268
  uint8_t txbuf[PCAL6524_LLD_NUM_REGISTERS + 1] = {(uint8_t)reg | PCAL6524_LLD_CMD_AUTOINCREMENT};
269
  memcpy(&txbuf[1], data, length);
270
  return apalI2CMasterTransmit(pcal6524d->i2cd, pcal6524d->addr, txbuf, length + 1, NULL, 0, timeout);
271
}
272

    
273
/** @} */
274