Statistics
| Branch: | Tag: | Revision:

amiro-lld / source / PCAL6524 / v1 / alld_PCAL5624_v1.c @ b6364b51

History | View | Annotate | Download (11.959 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_PCAL6524) && (AMIROLLD_CFG_PCAL6524 == 1)) || 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
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
//apalExitStatus_t pcal6524_lld_read_id(const PCAL6524Driver* const pcal6524d, pcal6524_lld_deviceid_t* const info, const apalTime_t timeout)
146
//{
147
//  apalDbgAssert(pcal6524d != NULL && pcal6524d->i2cd != NULL);
148
//  apalDbgAssert(info != NULL);
149
//
150
//  const uint8_t txbuf = (uint8_t)pcal6524d->addr;
151
//  return apalI2CMasterTransmit(pcal6524d->i2cd, PCAL6524_LLD_I2C_ADDR_DEVICEID, &txbuf, 1, info->raw, sizeof(info->raw), timeout);
152
//}
153

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

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

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

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

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

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

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

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

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

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

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

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

    
275
#endif /* defined(AMIROLLD_CFG_PCAL6524) && (AMIROLLD_CFG_PCAL6524 == 1) */
276

    
277
/** @} */