Subversion Repositories idreammicro-avr

Rev

Rev 31 | Rev 36 | Go to most recent revision | Details | Compare with Previous | Last modification | View Log | RSS feed

Rev Author Line No. Line
30 jlesech 1
/**************************************************************************//**
2
 * \brief MCP23008 library
3
 * \author Copyright (C) 2012  Julien Le Sech - www.idreammicro.com
4
 * \version 1.0
5
 * \date 201201025
6
 *
7
 * This file is part of the iDreamMicro library.
8
 *
9
 * This library is free software: you can redistribute it and/or modify it under
10
 * the terms of the GNU Lesser General Public License as published by the Free
11
 * Software Foundation, either version 3 of the License, or (at your option) any
12
 * later version.
13
 *
14
 * This library is distributed in the hope that it will be useful, but WITHOUT
15
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
16
 * FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
17
 * details.
18
 *
19
 * You should have received a copy of the GNU Lesser General Public License
20
 * along with this program. If not, see http://www.gnu.org/licenses/
21
 ******************************************************************************/
22
 
23
/**************************************************************************//**
24
 * \file mcp23008.c
25
 ******************************************************************************/
26
 
27
/******************************************************************************
28
 * Header file inclusions.
29
 ******************************************************************************/
30
 
31
#include <mcp23008/mcp23008.h>
32
 
33
#include <twi/twi.h>
34
#include <useful/bits.h>
35
 
36
#include <stdint.h>
37
 
38
/******************************************************************************
39
 * Private macros.
40
 ******************************************************************************/
41
 
31 jlesech 42
/**************************************************************************//**
43
 * \def     MCP23008__ADDRESS
32 jlesech 44
 * \brief   MCP23008 address on TWI bus (doesn't include hardware address).
31 jlesech 45
 * This value is given by the datasheet.
46
 ******************************************************************************/
47
#define MCP23008__ADDRESS       0x20
30 jlesech 48
 
31 jlesech 49
/**************************************************************************//**
50
 * \def     MCP23008__REG_IODIR
51
 * \brief   I/O direction register.
52
 ******************************************************************************/
53
#define MCP23008__REG_IODIR     0x00
30 jlesech 54
 
31 jlesech 55
/**************************************************************************//**
56
 * \def     MCP23008__REG_IPOL
57
 * \brief   Input polarity register.
58
 ******************************************************************************/
59
#define MCP23008__REG_IPOL      0x01
30 jlesech 60
 
31 jlesech 61
/**************************************************************************//**
62
 * \def     MCP23008__REG_GPINTEN
63
 * \brief   Interrupt on change control register.
64
 ******************************************************************************/
65
#define MCP23008__REG_GPINTEN   0x02
66
 
67
/**************************************************************************//**
68
 * \def     MCP23008__REG_DEFVAL
69
 * \brief   Default compare register for interrupt on change.
70
 ******************************************************************************/
71
#define MCP23008__REG_DEFVAL    0x03
72
 
73
/**************************************************************************//**
74
 * \def     MCP23008__REG_INTCON
75
 * \brief   Interrupt control register.
76
 ******************************************************************************/
77
#define MCP23008__REG_INTCON    0x04
78
 
79
/**************************************************************************//**
80
 * \def     MCP23008__REG_IOCON
81
 * \brief   Configuration register.
82
 ******************************************************************************/
83
#define MCP23008__REG_IOCON     0x05
84
 
85
/**************************************************************************//**
86
 * \def     MCP23008__REG_GPPU
87
 * \brief   Pull-up resistor configuration register.
88
 ******************************************************************************/
89
#define MCP23008__REG_GPPU      0x06
90
 
91
/**************************************************************************//**
92
 * \def     MCP23008__REG_INTF
93
 * \brief   Interrupt flag register.
94
 ******************************************************************************/
95
#define MCP23008__REG_INTF      0x07
96
 
97
/**************************************************************************//**
98
 * \def     MCP23008__REG_INTCAP
99
 * \brief   Interrupt capture register.
100
 ******************************************************************************/
101
#define MCP23008__REG_INTCAP    0x08
102
 
103
/**************************************************************************//**
104
 * \def     MCP23008__REG_GPIO
105
 * \brief   Port register.
106
 ******************************************************************************/
107
#define MCP23008__REG_GPIO      0x09
108
 
109
/**************************************************************************//**
110
 * \def     MCP23008__REG_OLAT
111
 * \brief   Output latch register.
112
 ******************************************************************************/
113
#define MCP23008__REG_OLAT      0x0A
114
 
115
/**************************************************************************//**
116
 * \def     MCP23008__CLOCK_RATE
117
 * \brief   MCP23008 frequency in Hertz.
118
 * On ATmega, can be 100 kHz or 400 Khz.
119
 ******************************************************************************/
120
#define MCP23008__CLOCK_RATE    400000
121
 
30 jlesech 122
/******************************************************************************
123
 * Private function prototypes.
124
 ******************************************************************************/
125
 
126
/**************************************************************************//**
31 jlesech 127
 * \fn static uint8_t mcp23008__read_register(uint8_t address)
30 jlesech 128
 *
31 jlesech 129
 * \brief Read MCP23008 register value.
130
 *
131
 * \param   address Address of the register to read value.
30 jlesech 132
 ******************************************************************************/
133
static
134
uint8_t
135
mcp23008__read_register
136
(
137
    uint8_t address
138
);
139
 
140
/**************************************************************************//**
31 jlesech 141
 * \fn static void mcp23008__write_register(uint8_t address, uint8_t value)
30 jlesech 142
 *
31 jlesech 143
 * \brief Write MCP23008 register value.
144
 *
145
 * \param address   Address of the register to write value.
146
 * \param value     Value to write.
30 jlesech 147
 ******************************************************************************/
148
static
149
void
150
mcp23008__write_register
151
(
31 jlesech 152
    uint8_t address,
153
    uint8_t value
30 jlesech 154
);
155
 
156
/******************************************************************************
157
 * Private variable declarations.
158
 ******************************************************************************/
159
 
160
static uint8_t mcp23008__twi_address = 0;
161
 
162
/******************************************************************************
163
 * Public function definitions.
164
 ******************************************************************************/
165
 
166
/**************************************************************************//**
167
 * \fn void mcp23008__initialize(uint8_t hardware_address)
168
 *
169
 * \brief Initialize MCP23008.
170
 *
31 jlesech 171
 * \param hardware_address  Hardware address defined by pins A0 to A2.
30 jlesech 172
 ******************************************************************************/
173
void
174
mcp23008__initialize
175
(
176
    uint8_t hardware_address
177
){
178
    // Initialize TWI.
179
    twi__initialize(MCP23008__CLOCK_RATE);
180
 
181
    // Compute MCP23008 TWI address.
182
    mcp23008__twi_address = (MCP23008__ADDRESS | hardware_address) << 1;
183
 
184
    twi__start();
185
    twi__send_slaw(mcp23008__twi_address);
186
    twi__send_data(MCP23008__REG_IODIR);
187
    twi__send_data(0xFF);
188
    twi__send_data(0x00);
189
    twi__send_data(0x00);
190
    twi__send_data(0x00);
191
    twi__send_data(0x00);
192
    twi__send_data(0x00);
193
    twi__send_data(0x00);
194
    twi__send_data(0x00);
195
    twi__send_data(0x00);
196
    twi__send_data(0x00);
197
    twi__stop();
198
}
199
 
200
/**************************************************************************//**
31 jlesech 201
 * \fn void mcp23008__configure pin(
202
 * mcp23008__gpio_t         pin,
203
 * mcp23008__direction_t    direction)
30 jlesech 204
 *
31 jlesech 205
 * \brief Configure pin direction.
206
 *
207
 * \param pin       Pin to configure.
208
 * \param direction Pin direction.
30 jlesech 209
 ******************************************************************************/
210
void
211
mcp23008__configure_pin
212
(
213
 
31 jlesech 214
    mcp23008__gpio_t        pin,
215
    mcp23008__direction_t   direction
30 jlesech 216
){
217
    uint8_t port_configuration = mcp23008__read_register(MCP23008__REG_IODIR);
218
 
219
    if (MCP23008__DIRECTION__INPUT == direction)
220
    {
221
        BIT__SET(port_configuration, pin);
222
    }
223
    else
224
    {
225
        BIT__RST(port_configuration, pin);
226
    }
227
 
228
    mcp23008__write_register(MCP23008__REG_IODIR, port_configuration);
229
}
230
 
231
/**************************************************************************//**
31 jlesech 232
 * \fn void mcp23008__configure_port(mcp23008__direction_t direction)
30 jlesech 233
 *
31 jlesech 234
 * \brief Configure port direction.
235
 *
236
 * \param direction Port direction.
30 jlesech 237
 ******************************************************************************/
238
void
239
mcp23008__configure_port
240
(
241
    mcp23008__direction_t direction
242
){
243
    mcp23008__write_register(MCP23008__REG_IODIR, direction);
244
}
245
 
246
/**************************************************************************//**
31 jlesech 247
 * \fn mcp23008__level_t mcp23008__get_pin_level(mcp23008__gpio_t pin)
30 jlesech 248
 *
31 jlesech 249
 * \brief Get pin level.
250
 *
251
 * \param pin   Pin to get level.
252
 *
253
 * \return Pin level.
30 jlesech 254
 ******************************************************************************/
255
mcp23008__level_t
256
mcp23008__get_pin_level
257
(
258
    mcp23008__gpio_t pin
259
){
260
    uint8_t port_value = mcp23008__read_register(MCP23008__REG_GPIO);
261
 
262
    mcp23008__level_t level = BIT__TST(port_value, pin);
263
 
264
    return level;
265
}
266
 
267
/**************************************************************************//**
31 jlesech 268
 * \fn void mcp23008__set_pin_level(
269
 * mcp23008__gpio_t     pin,
270
 * mcp23008__level_t    level)
30 jlesech 271
 *
31 jlesech 272
 * \brief Set pin level.
273
 *
274
 * \param pin   Pin to set level.
275
 * \param level Level to set.
30 jlesech 276
 ******************************************************************************/
277
void
278
mcp23008__set_pin_level
279
(
280
    mcp23008__gpio_t    pin,
281
    mcp23008__level_t   level
282
){
283
    uint8_t port_value = mcp23008__read_register(MCP23008__REG_GPIO);
284
 
285
    if (MCP23008__LEVEL__HIGH == level)
286
    {
287
        BIT__SET(port_value, pin);
288
    }
289
    else
290
    {
291
        BIT__RST(port_value, pin);
292
    }
293
 
294
    mcp23008__write_register(MCP23008__REG_GPIO, port_value);
295
}
296
 
297
/**************************************************************************//**
31 jlesech 298
 * \fn uin8_t mcp23008__get_port_value(void)
30 jlesech 299
 *
31 jlesech 300
 * \brief Get port value.
301
 *
302
 * \return Port value.
30 jlesech 303
 ******************************************************************************/
304
uint8_t
305
mcp23008__get_port_value
306
(
307
    void
308
){
309
    uint8_t value = mcp23008__read_register(MCP23008__REG_GPIO);
310
 
311
    return value;
312
}
313
 
314
/**************************************************************************//**
31 jlesech 315
 * \fn void mcp23008__set_port_value(uint8_t value)
30 jlesech 316
 *
31 jlesech 317
 * \brief Set port value.
318
 *
319
 * \param value Value to set.
30 jlesech 320
 ******************************************************************************/
321
void
322
mcp23008__set_port_value
323
(
324
    uint8_t value
325
){
326
    mcp23008__write_register(MCP23008__REG_GPIO, value);
327
}
328
 
329
/******************************************************************************
330
 * Private function definitions.
331
 ******************************************************************************/
332
 
333
/**************************************************************************//**
31 jlesech 334
 * \fn static uint8_t mcp23008__read_register(uint8_t address)
30 jlesech 335
 *
31 jlesech 336
 * \brief Read MCP23008 register value.
337
 *
338
 * \param   address Address of the register to read value.
30 jlesech 339
 ******************************************************************************/
340
static
341
uint8_t
342
mcp23008__read_register
343
(
344
    uint8_t address
345
){
346
    uint8_t value = 0;
347
 
348
    twi__start();
349
    twi__send_slaw(mcp23008__twi_address);
350
    twi__send_data(address);
351
    twi__stop();
352
 
353
    twi__start();
354
    twi__send_slar(mcp23008__twi_address);
355
    twi__receive_data_nack(&value);
356
    twi__stop();
357
 
358
    return value;
359
}
360
 
361
/**************************************************************************//**
31 jlesech 362
 * \fn static void mcp23008__write_register(uint8_t address, uint8_t value)
30 jlesech 363
 *
31 jlesech 364
 * \brief Write MCP23008 register value.
365
 *
366
 * \param address   Address of the register to write value.
367
 * \param value     Value to write.
30 jlesech 368
 ******************************************************************************/
369
static
370
void
371
mcp23008__write_register
372
(
31 jlesech 373
    uint8_t address,
374
    uint8_t value
30 jlesech 375
){
376
    twi__start();
377
    twi__send_slaw(mcp23008__twi_address);
378
    twi__send_data(address);
379
    twi__send_data(value);
380
    twi__stop();
381
}