-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathpython_io.cpp
executable file
·300 lines (243 loc) · 10.3 KB
/
python_io.cpp
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
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
#include "python_io.h"
PythonIO::PythonIO()
{
rSPIControl = 0x1D8;
rSPIStatus = 0x1D9;
rSPIData0 = 0x1DA;
rSPIData1 = 0x1DB;
rSPIData2 = 0x1DC;
rSPIData3 = 0x1DD;
rHWMoniterIndex = 0xC70;
rHWMoniterData = 0xC71;
iopl(3); //Allow us access to ALL ports. We will need root permission and it should
//be noted that This is moderately dangerous, however we will be careful.
//I promise.
//Init_Onboard_Digital();
initPWM();
initDigitalIO(0xFFFFFFFF);//Set everything to inputs for now
}
unsigned char PythonIO::getDigital(char io_byte)
{
//****NB****
//THIS ENTIRE METHOD IS SPECIFIC TO THE REV6 BOARD
//PORTA and PORTB are swapped!!!!
unsigned char gpio_address, chip_address, tmp_var;
if(bitof(0, io_byte))
gpio_address = 0x12; //GPIO bank B = 0x13
else
gpio_address = 0x13; //GPIO bank A = 0x12
if(bitof(1, io_byte))
outb( CHIP1, rSPIControl ); //Dig I/O chip 1 (see ref manual for bitwise breakdown)
else
outb( CHIP0, rSPIControl ); //Dig I/O chip 0 (see ref manual for bitwise breakdown)
outb( BUSCONFIG, rSPIStatus ); //irq3, 8.3MHz, int disabled, shift Msb
outb( 0x00, rSPIData1 ); //We're not acctually writing anything to the bank so its irrellevant
outb( gpio_address, rSPIData2 ); //Choose the GPIO bank on the chip
outb( 0x41, rSPIData3 ); //The R/W bit (bit 0) should be 1 == read
waitOnTransaction();
tmp_var = inb(rSPIData1);
return tmp_var;
}
void PythonIO::setDigital(char io_byte, unsigned char _data)
{
//****NB****
//THIS ENTIRE METHOD IS SPECIFIC TO THE REV6 BOARD
char gpio_address, chip_address;
if(bitof(0, io_byte))
gpio_address = 0x12; //GPIO bank B = 0x13
else
gpio_address = 0x13; //GPIO bank A = 0x12
if(bitof(1, io_byte))
outb( CHIP1, rSPIControl ); //Dig I/O chip 1 (see ref manual for bitwise breakdown)
else
outb( CHIP0, rSPIControl ); //Dig I/O chip 0 (see ref manual for bitwise breakdown)
outb( BUSCONFIG, rSPIStatus ); //irq3, 8.3MHz, int disabled, shift Msb
outb( _data, rSPIData1); //Data to write to the bank
outb( gpio_address, rSPIData2); //Choose the GPIO bank on the chip
outb( WRITECMD, rSPIData3); //The R/W bit (bit 0) should be 0 == Write
waitOnTransaction();
}
//Actually only a 12 bit number but we wrap it in an unsigned short
unsigned short PythonIO::getAnalog(char io_pin)
{
word analog_value;
io_pin = io_pin << 3; //We bit shift it because it is supposed to write the address in pins 5-3
outb( 0x35, rSPIControl ); //A/D chip select with 32bit frame for single sample,see ref manual
outb( BUSCONFIG, rSPIStatus ); //irq3, 8.3MHz, int disabled, shift Msb
outb( 0x00, rSPIData2 ); //Unread data so value doesn't matter
outb(io_pin, rSPIData3); //Initiate the transaction by writing the port value
waitOnTransaction();
analog_value.lsb = inb(rSPIData0);
analog_value.msb = inb(rSPIData1);
return analog_value.value;
//Alt single instruction
//return inw(rSPIData0);
}
//Function to initialize and configure the digital ports
void PythonIO::initDigitalIO(unsigned int direction)
{
//All-right, theres a fair ammount of confusion as to what is what
//according to the beginning of the manual:
//SPIDATA1 = Data byte
//SPIDATA2 = Address Byte
//SPIDATA3 = command byte - Which I'm guessing is allways 0x40
//Not sure what I believe, but we're going to use that assumption to clean up their code
//Initialize
outb( CHIP0, rSPIControl );
outb( BUSCONFIG, rSPIStatus );
outb( 0x44, rSPIData1 );
outb( IOCON, rSPIData2 );
outb( WRITECMD, rSPIData3 );
waitOnTransaction();
outb( CHIP0, rSPIControl ); //Chip-select first on-board Digital I/O
outb( BUSCONFIG, rSPIStatus ); //irq3, 8.3MHz, int disabled, shift Msb
outb( 0xFF, rSPIData1 );
outb( GPPUA, rSPIData2 ); //GPPUA
outb( WRITECMD, rSPIData3 ); //The R/W bit(bit 0) should be 0 == write
waitOnTransaction();
outb( CHIP0, rSPIControl ); //Chip-select first on-board Digital I/O
outb( BUSCONFIG, rSPIStatus ); //irq3, 8.3MHz, int disabled, shift Msb
outb( 0xFF, rSPIData1 );
outb( GPPUB, rSPIData2 ); //GPPUB
outb( WRITECMD, rSPIData3 ); //The R/W bit(bit 0) should be 0 == write
waitOnTransaction();
//Initialize
outb( CHIP1, rSPIControl );
outb( BUSCONFIG, rSPIStatus );
outb( 0x44, rSPIData1 );
outb( IOCON, rSPIData2 );
outb( WRITECMD, rSPIData3 );
waitOnTransaction();
outb( CHIP1, rSPIControl ); //Chip-select first on-board Digital I/O
outb( BUSCONFIG, rSPIStatus ); //irq3, 8.3MHz, int disabled, shift Msb
outb( 0xFF, rSPIData1 );
outb( GPPUA, rSPIData2 ); //GPPUA
outb( WRITECMD, rSPIData3 ); //The R/W bit(bit 0) should be 0 == write
waitOnTransaction();
outb( CHIP1, rSPIControl ); //Chip-select first on-board Digital I/O
outb( BUSCONFIG, rSPIStatus ); //irq3, 8.3MHz, int disabled, shift Msb
outb( 0xFF, rSPIData1 );
outb( GPPUB, rSPIData2 ); //GPPUB
outb( WRITECMD, rSPIData3 ); //The R/W bit(bit 0) should be 0 == write
waitOnTransaction();
unsigned char byte0, byte1, byte2, byte3;
byte0 = (direction & 0x000000FF);
byte1 = ((direction & 0x0000FF00) >> 8);
byte2 = ((direction & 0x00FF0000) >> 16);
byte3 = ((direction & 0xFF000000) >> 24);
printf("DIR 0=%d, DIR 1=%d, DIR 2=%d, DIR 3=%d\n", byte0, byte1, byte2, byte3);
outb( CHIP0, rSPIControl ); //Chip-select first on-board Digital I/O
outb( BUSCONFIG, rSPIStatus ); //irq3, 8.3MHz, int disabled, shift Msb
outb( byte0, rSPIData1 ); //Set all 1's to set all to inputs
outb( IODIRA, rSPIData2 ); //IODIRA register = 0x00
outb( WRITECMD, rSPIData3 ); //The R/W bit(bit 0) should be 0 == write
waitOnTransaction();
outb( CHIP0, rSPIControl ); //Chip-select first on-board Digital I/O
outb( BUSCONFIG, rSPIStatus ); //irq3, 8.3MHz, int disabled, shift Msb
outb( byte1, rSPIData1 ); //Set all 1's to set all to inputs
outb( IODIRB, rSPIData2 ); //IODIRB register = 0x01
outb( WRITECMD, rSPIData3 ); //The R/W bit(bit 0) should be 0 == write
waitOnTransaction();
//We've now initialized the first chip
outb( CHIP1, rSPIControl ); //Chip-select second on-board Digital I/O
outb( BUSCONFIG, rSPIStatus ); //irq3, 8.3MHz, int disabled, shift Msb
outb( byte2, rSPIData1 ); //Set all 1's to set all to inputs
outb( IODIRA, rSPIData2 ); //IODIRA register = 0x00
outb( WRITECMD, rSPIData3 ); //The R/W bit(bit 0) should be 0 == write
waitOnTransaction();
outb( CHIP1, rSPIControl ); //Chip-select second on-board Digital I/O
outb( BUSCONFIG, rSPIStatus ); //irq3, 8.3MHz, int disabled, shift Msb
outb( byte3, rSPIData1 ); //Set all 1's to set all to inputs
outb( IODIRB, rSPIData2 ); //IODIRB register = 0x01
outb( WRITECMD, rSPIData3 ); //The R/W bit(bit 0) should be 0 == write
waitOnTransaction();
//We've now initialized the second chip to all inputs
}
/*
void PythonIO::setPullup(bool enable)
{
outb( CHIP0, rSPIControl ); //Chip-select first on-board Digital I/O
outb( BUSCONFIG, rSPIStatus ); //irq3, 8.3MHz, int disabled, shift Msb
outb( 0x
}
*/
void PythonIO::initPWM()
{
//ioperm only gives access to ports upto 0x3FF anything higher and we need to use iopl()
// ioperm(BASEADDRESS, #OFPORTS, ADDORREMOVEACCESS(bool));
char tmp_var;
outb(0x40, rHWMoniterIndex); // Waiting on more info as to what the actual pinout of this port
//is, but it is essentially a register selector for the HWMon chip
//(ie I have no friggin clue what 0x40 does, I can only assume
//that it sets me to a config register on the chip because the ASM tells me to do it)
tmp_var = inb(rHWMoniterData); //We need to see the old value to modify it
tmp_var = tmp_var & 0xFE; // doing a bitmask to disable the first bit (0xFE==11111110)
outb(tmp_var, rHWMoniterData); // Start bit is now off
// we've now disabled the chip
outb(PWMCONFIG1, rHWMoniterIndex); //Now we need to put the PWM into manual mode
tmp_var = inb(rHWMoniterData);
tmp_var = tmp_var | 0xE0; //apparently the 3MSBs are in control of manual mode
//however, there is some sloppy bitwise manipulation done in the ASM
//so this should double-checked
outb(tmp_var, rHWMoniterData);
//We've now put PWM1 into manual mode - need to do others if we want them
//We do in fact have to do the following to all of the PWM's even though we are only using one
outb(LOWTEMP1, rHWMoniterIndex);
outb(0x81, rHWMoniterData); //We have to set it to a value other than the default (0x80) and they
//suggested 0x81 in the example
outb(LOWTEMP2, rHWMoniterIndex);
outb(0x81, rHWMoniterData);
outb(LOWTEMP3, rHWMoniterIndex);
outb(0x81, rHWMoniterData);
//done setting low temp limit registers
//Now we set the PWM duty-cycle
outb(DUTY_CYCLE1, rHWMoniterIndex); //Chose the first pwm duty-cycle register
//***********************************************************
outb(0x22, rHWMoniterData); // we need to fix this value, it affects the position that the PWM is
//initialized at (ie the initial servo position)
//***********************************************************
//Done setting duty-cycle
//Set the PWM frequency
outb(RANGEFREQ1, rHWMoniterIndex);
tmp_var = inb(rHWMoniterData); //we need to read in the old value because we need to rewrite the same upper
//nibble, only the lower nibble affects frequency
tmp_var = tmp_var & 0xF0; // clear the lower nibble
tmp_var = tmp_var | 0x07; //87.7Hz, we may want to decide on a diff value depending on the servo we chose
outb(tmp_var, rHWMoniterData);
//Done setting the frequency
//Now we have to re-enable the chip
outb(0x40, rHWMoniterIndex);
tmp_var = inb(rHWMoniterData);
tmp_var = tmp_var | 0x01; //Re-enable the start-bit
outb(tmp_var, rHWMoniterData);
//Done re-enabling
}
float PythonIO::getFreq(int _chip)
{
return 1./((float)getTach(_chip) * 0.0000111);
}
int PythonIO::getTach(int _chip)
{
//LSB = 0x28, MSB = 0x29 ; + chip*2
word foo;
outb((0x28 + _chip * 2), rHWMoniterIndex);
foo.lsb = inb(rHWMoniterData);
outb((0x29 + _chip * 2), rHWMoniterIndex);
foo.msb = inb(rHWMoniterData);
return foo.value;
}
void PythonIO::setPWMDuty(char _duty)
{
outb(DUTY_CYCLE1, rHWMoniterIndex); //choose the first pwm duty-cycle register
outb(_duty, rHWMoniterData);
}
//Pause function for SPI transactions
void PythonIO::waitOnTransaction()
{
char tmp_var;
do
{
tmp_var = inb(rSPIStatus); //Read in and we need to check if the done bit is set
tmp_var = tmp_var & 0x01; //Isolate the done bit
}while(tmp_var == 0x01);
}