blob: 5997f2419a728333e3a1f6e99eef17a93e362e4c (
plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
|
/***************************************************************************
* __________ __ ___.
* Open \______ \ ____ ____ | | _\_ |__ _______ ___
* Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
* Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
* Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
* \/ \/ \/ \/ \/
* $Id$
*
* Copyright (C) 2008 by Jens Arnold
*
* All files in this archive are subject to the GNU General Public License.
* See the file COPYING in the source tree root for full license agreement.
*
* This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
* KIND, either express or implied.
*
****************************************************************************/
#include "config.h"
#include "adc.h"
#include "i2c-coldfire.h"
#include "system.h"
#define ADC_I2C_ADDR 0xa0
/* The M3 ADC is hooked exclusively to the secondary I²C bus, and requires
* very slow transfers (I²C clock <= 16kHz). So we start one 4-byte read
* transfer each tick, and handle it via an ISR. At 11MHz, one transfer
* takes too long to be started every tick, but it seems we have to live
* with that. */
static unsigned char adc_data[NUM_ADC_CHANNELS] IBSS_ATTR;
static volatile bool data_ready = false;
static void adc_tick(void)
{
if ((MBSR2 & IBB) == 0) /* Bus is free */
{
MBCR2 |= (MSTA|TXAK|MTX); /* Generate START and prepare for write */
MBDR2 = ADC_I2C_ADDR|1; /* Send address */
}
}
void IIC2(void) __attribute__((interrupt_handler));
void IIC2(void)
{
static int bytenum = 0;
MBSR2 &= ~IIF; /* Clear interrupt flag */
if (MBSR2 & IAL) /* Arbitration lost - shouldn't never happen */
{
MBSR2 &= ~IAL; /* Clear flag */
MBCR2 &= ~MSTA; /* STOP */
}
else if (MBCR2 & MTX) /* Address phase */
{
if (MBSR2 & RXAK) /* No ACK received */
{
MBCR2 &= ~MSTA; /* STOP */
return;
}
MBCR2 &= ~(MTX|TXAK); /* Switch to RX mode, enable TX ack generation */
MBDR2; /* Dummy read */
bytenum = 0;
}
else
{
switch (bytenum)
{
case 2:
MBCR2 |= TXAK; /* Don't ACK the last byte */
break;
case 3:
MBCR2 &= ~MSTA; /* STOP before reading the last value */
data_ready = true; /* Simplification - the last byte is a dummy. */
break;
}
adc_data[bytenum++] = MBDR2;
}
}
unsigned short adc_read(int channel)
{
return adc_data[channel];
}
void adc_init(void)
{
MFDR2 = 0x1f; /* I²C clock = SYSCLK / 3840 */
MBCR2 = IEN; /* Enable interface */
MBSR2 = 0; /* Clear flags */
MBCR2 = (IEN|IIEN); /* Enable interrupts */
or_l( 0x04000000, &INTPRI8); /* INT62 - Priority 4 */
tick_add_task(adc_tick);
while (!data_ready)
sleep(1); /* Ensure valid readings when adc_init returns */
}
/* The ADC (most probably the PIC12F675) obviously has a slow and buggy I²C
* implementation. If a transfer is stopped prematurely, it often locks up
* and doesn't react anymore until the unit is power cycled. */
void adc_close(void)
{
tick_remove_task(adc_tick);
while (MBSR2 & IBB) /* Wait for an ongoing transfer to finish */
sleep(1);
}
|