Basic Mid-Level control for the rebuilt MorphGI control unit, using PWM to communicate with the low level controllers.

Dependencies:   ros_lib_kinetic

Committer:
WD40andTape
Date:
Tue Jul 09 18:46:44 2019 +0000
Revision:
36:4459be8296e9
Parent:
34:54e9ebe9e87f
Child:
37:37da606f4466
tested and working with 9 stages

Who changed what in which revision?

UserRevisionLine numberNew contents of line
WD40andTape 8:d6657767a182 1 // LLComms.cpp
WD40andTape 8:d6657767a182 2
WD40andTape 8:d6657767a182 3 #include "LLComms.h"
WD40andTape 8:d6657767a182 4
dofydoink 12:595ed862e52f 5 LLComms::LLComms() :
WD40andTape 13:a373dfc57b89 6 queue(32 * EVENTS_EVENT_SIZE), //32 //8 * EVENTS_EVENT_SIZE
WD40andTape 36:4459be8296e9 7 pinGate6(PA_5),
WD40andTape 14:54c3759e76ed 8 spi_0(PC_12, PC_11, PC_10),
WD40andTape 14:54c3759e76ed 9 spi_1(PF_9, PF_8, PF_7),
WD40andTape 36:4459be8296e9 10 spi_2(PB_15, PC_2, PB_13),
WD40andTape 8:d6657767a182 11 // These interrupt pins have to be declared AFTER SPI declaration. No Clue Why.
WD40andTape 8:d6657767a182 12 pinGate0(PF_11),
WD40andTape 8:d6657767a182 13 pinGate1(PG_14),
WD40andTape 8:d6657767a182 14 pinGate2(PF_15),
WD40andTape 8:d6657767a182 15 pinGate3(PF_12),
WD40andTape 8:d6657767a182 16 pinGate4(PF_3),
WD40andTape 34:54e9ebe9e87f 17 pinGate5(PC_7),
WD40andTape 8:d6657767a182 18 pinGate7(PE_13),
WD40andTape 36:4459be8296e9 19 pinGate8(PF_4),//PB_3),
WD40andTape 36:4459be8296e9 20 pinReset(PD_2),
WD40andTape 36:4459be8296e9 21 chrp(PB_8),
WD40andTape 36:4459be8296e9 22 chrp1(PC_6)
WD40andTape 8:d6657767a182 23 { // Constructor
WD40andTape 8:d6657767a182 24
WD40andTape 24:bc852aa89e7a 25 spi_0.format(16,2);
WD40andTape 24:bc852aa89e7a 26 spi_0.frequency(LOW_LEVEL_SPI_FREQUENCY);
WD40andTape 24:bc852aa89e7a 27 spi_1.format(16,2);
WD40andTape 24:bc852aa89e7a 28 spi_1.frequency(LOW_LEVEL_SPI_FREQUENCY);
WD40andTape 36:4459be8296e9 29 spi_2.format(16,2);
WD40andTape 36:4459be8296e9 30 spi_2.frequency(LOW_LEVEL_SPI_FREQUENCY);
WD40andTape 24:bc852aa89e7a 31
WD40andTape 36:4459be8296e9 32 //PinName LLPins[N_CHANNELS] = {PD_15, PE_10, PD_11, PD_14, PE_7, PB_1, PF_10, PD_13};
WD40andTape 36:4459be8296e9 33 PinName LLPins[N_CHANNELS] = {PD_15, PE_10, PD_11, PD_14, PE_7, PB_1, PB_12, PD_13, PB_5};
WD40andTape 36:4459be8296e9 34 for (short int i=0; i<N_CHANNELS; i++) {
WD40andTape 10:1b6daba32452 35 isDataReady[i] = 0;
WD40andTape 8:d6657767a182 36 cs_LL[i] = new DigitalOut(LLPins[i]);
WD40andTape 34:54e9ebe9e87f 37 //cs_ADC[i] = new DigitalOut(ADCPins[i]);
WD40andTape 8:d6657767a182 38 }
WD40andTape 10:1b6daba32452 39
WD40andTape 9:cd3607ba5643 40 // Initialise relevant variables
WD40andTape 36:4459be8296e9 41 for(short int i=0; i<N_CHANNELS; i++) {
WD40andTape 9:cd3607ba5643 42 // All chip selects in off state
WD40andTape 9:cd3607ba5643 43 *cs_LL[i] = 1;
WD40andTape 34:54e9ebe9e87f 44 //*cs_ADC[i] = 1;
WD40andTape 26:7c59002c9cd7 45 // Initialise pressures/positions
WD40andTape 29:10a5cf37a875 46 pressureSensor_uint[i] = 0.0;
WD40andTape 26:7c59002c9cd7 47 pressureSensor_bar[i] = -1.0;
WD40andTape 29:10a5cf37a875 48 positionSensor_uint[i] = 0.0;
WD40andTape 26:7c59002c9cd7 49 positionSensor_mm[i] = -1.0;
WD40andTape 9:cd3607ba5643 50 }
WD40andTape 9:cd3607ba5643 51 pinReset = 1; // Initialise reset pin to not reset the controllers.
WD40andTape 9:cd3607ba5643 52 wait(0.25);
WD40andTape 9:cd3607ba5643 53 pinReset=0; // Reset controllers to be safe
WD40andTape 9:cd3607ba5643 54 wait(0.25);
WD40andTape 9:cd3607ba5643 55 pinReset = 1; // Ready to go
WD40andTape 10:1b6daba32452 56
WD40andTape 10:1b6daba32452 57 // Set up rise interrupts MIGHT NOT NEED TO BE POINTERS
dofydoink 12:595ed862e52f 58 pinGate0.rise(callback(this,&LLComms::rise0));
dofydoink 12:595ed862e52f 59 pinGate1.rise(callback(this,&LLComms::rise1));
dofydoink 12:595ed862e52f 60 pinGate2.rise(callback(this,&LLComms::rise2));
dofydoink 12:595ed862e52f 61 pinGate3.rise(callback(this,&LLComms::rise3));
dofydoink 12:595ed862e52f 62 pinGate4.rise(callback(this,&LLComms::rise4));
dofydoink 12:595ed862e52f 63 pinGate5.rise(callback(this,&LLComms::rise5));
dofydoink 12:595ed862e52f 64 pinGate6.rise(callback(this,&LLComms::rise6));
dofydoink 12:595ed862e52f 65 pinGate7.rise(callback(this,&LLComms::rise7));
WD40andTape 36:4459be8296e9 66 pinGate8.rise(callback(this,&LLComms::rise8));
WD40andTape 10:1b6daba32452 67 // Set up fall interrupts MIGHT NOT NEED TO BE POINTERS
dofydoink 12:595ed862e52f 68 pinGate0.fall(callback(this,&LLComms::fall0));
dofydoink 12:595ed862e52f 69 pinGate1.fall(callback(this,&LLComms::fall1));
dofydoink 12:595ed862e52f 70 pinGate2.fall(callback(this,&LLComms::fall2));
dofydoink 12:595ed862e52f 71 pinGate3.fall(callback(this,&LLComms::fall3));
dofydoink 12:595ed862e52f 72 pinGate4.fall(callback(this,&LLComms::fall4));
dofydoink 12:595ed862e52f 73 pinGate5.fall(callback(this,&LLComms::fall5));
dofydoink 12:595ed862e52f 74 pinGate6.fall(callback(this,&LLComms::fall6));
dofydoink 12:595ed862e52f 75 pinGate7.fall(callback(this,&LLComms::fall7));
WD40andTape 36:4459be8296e9 76 pinGate8.fall(callback(this,&LLComms::fall8));
WD40andTape 9:cd3607ba5643 77 }
WD40andTape 9:cd3607ba5643 78
dofydoink 11:7029367a1840 79 //LLComms::~LLComms(void) { } // Destructor
WD40andTape 26:7c59002c9cd7 80 unsigned int LLComms::formatMessage(short int type, double dblValue, double dblMaxValue) {
WD40andTape 24:bc852aa89e7a 81 // Convert to a 9-bit number
WD40andTape 24:bc852aa89e7a 82 int intValue = (int) ((dblValue/dblMaxValue)*511);
WD40andTape 24:bc852aa89e7a 83 intValue = intValue & 0x1FF; // Ensure number is 9-bit
WD40andTape 24:bc852aa89e7a 84 // Initialize message with value
WD40andTape 24:bc852aa89e7a 85 unsigned int intMsg = intValue;
WD40andTape 24:bc852aa89e7a 86 // Calculate checksum (the decimal sum of the position data)
WD40andTape 24:bc852aa89e7a 87 int intCheckSum = 0, intTempVar = intValue;
WD40andTape 26:7c59002c9cd7 88 while( intTempVar>0 ) {
WD40andTape 24:bc852aa89e7a 89 intCheckSum += intTempVar%10;
WD40andTape 25:88e6cccde856 90 intTempVar = floor(intTempVar/10.0);
WD40andTape 24:bc852aa89e7a 91 }
WD40andTape 24:bc852aa89e7a 92 // Add checksum to message
WD40andTape 24:bc852aa89e7a 93 intMsg = intMsg<<5;
WD40andTape 24:bc852aa89e7a 94 intMsg = intMsg | intCheckSum;
WD40andTape 24:bc852aa89e7a 95 // Add type bit (0 == position, 1 == velocity)
WD40andTape 24:bc852aa89e7a 96 intMsg = intMsg<<1;
WD40andTape 26:7c59002c9cd7 97 intMsg = intMsg | (int)type; // CAST AS BOOL
WD40andTape 24:bc852aa89e7a 98 // Calculate decimal parity check for the whole message
WD40andTape 24:bc852aa89e7a 99 unsigned int count = 0, b = 1;
WD40andTape 24:bc852aa89e7a 100 for(short int i=0; i<32; i++) {
WD40andTape 24:bc852aa89e7a 101 if( intMsg & (b << i) ) count++;
WD40andTape 24:bc852aa89e7a 102 }
WD40andTape 24:bc852aa89e7a 103 // Add parity bit to message (0 == Odd, 1 == Even)
WD40andTape 27:6853ee8ffefd 104 // Parity selected in this way to prevent 0x0000 from passing checks
WD40andTape 24:bc852aa89e7a 105 bool boolParity = !(bool)(count%2);
WD40andTape 24:bc852aa89e7a 106 intMsg = intMsg<<1;
WD40andTape 24:bc852aa89e7a 107 intMsg = intMsg | (int)boolParity;
WD40andTape 26:7c59002c9cd7 108 return intMsg;
WD40andTape 26:7c59002c9cd7 109 }
WD40andTape 26:7c59002c9cd7 110
WD40andTape 26:7c59002c9cd7 111 bool LLComms::CheckMessage(int msg) {
WD40andTape 26:7c59002c9cd7 112 // Find message parity
WD40andTape 26:7c59002c9cd7 113 short int count = 0;
WD40andTape 26:7c59002c9cd7 114 for(short int i=0; i<32; i++) {
WD40andTape 26:7c59002c9cd7 115 if( msg>>1 & (1<<i) ) count++;
WD40andTape 26:7c59002c9cd7 116 }
WD40andTape 26:7c59002c9cd7 117 int intParity = !(count%2);
WD40andTape 26:7c59002c9cd7 118 // Find message CheckSum
WD40andTape 26:7c59002c9cd7 119 int intChkSum = 0;
WD40andTape 26:7c59002c9cd7 120 int intTempVar = msg>>7;
WD40andTape 26:7c59002c9cd7 121 while(intTempVar > 0) {
WD40andTape 26:7c59002c9cd7 122 intChkSum += intTempVar%10;
WD40andTape 26:7c59002c9cd7 123 intTempVar = int(intTempVar/10);
WD40andTape 26:7c59002c9cd7 124 }
WD40andTape 26:7c59002c9cd7 125 // Check if parity and CheckSum match
WD40andTape 26:7c59002c9cd7 126 bool isParityCorrect = (intParity == (msg&0x1));
WD40andTape 26:7c59002c9cd7 127 bool isChkSumCorrect = (intChkSum == ((msg>>2)&0x1F));
WD40andTape 26:7c59002c9cd7 128 bool isCheckPassed = (isParityCorrect && isChkSumCorrect);
WD40andTape 26:7c59002c9cd7 129 return isCheckPassed;
WD40andTape 26:7c59002c9cd7 130 }
WD40andTape 26:7c59002c9cd7 131
WD40andTape 26:7c59002c9cd7 132 bool LLComms::PerformMasterSPI(SPI *spi, unsigned int outboundMsgs[], unsigned int inboundMsgsData[]) {
WD40andTape 26:7c59002c9cd7 133 unsigned int dummyMsg = 0x5555;
WD40andTape 26:7c59002c9cd7 134 bool isSuccess = true;
WD40andTape 26:7c59002c9cd7 135 unsigned int inboundMsg, typeBit;
WD40andTape 27:6853ee8ffefd 136 AnalogIn ain(PA_4); // Random analogue pin
WD40andTape 26:7c59002c9cd7 137 for(short int i=0; i<3; i++) { // Loop 3 times for 3 SPI messages
WD40andTape 27:6853ee8ffefd 138 ain.read_u16(); // Read analogue pin to cause a delay
WD40andTape 27:6853ee8ffefd 139 ain.read_u16();
WD40andTape 26:7c59002c9cd7 140 if(i==0) {
WD40andTape 26:7c59002c9cd7 141 inboundMsg = spi->write(outboundMsgs[0]);
WD40andTape 26:7c59002c9cd7 142 } else if(i==1) {
WD40andTape 26:7c59002c9cd7 143 inboundMsg = spi->write(outboundMsgs[1]);
WD40andTape 26:7c59002c9cd7 144 } else {
WD40andTape 26:7c59002c9cd7 145 inboundMsg = spi->write(dummyMsg);
WD40andTape 26:7c59002c9cd7 146 }
WD40andTape 26:7c59002c9cd7 147 if((unsigned int)inboundMsg != dummyMsg) { // Message is not dummy which is only used for reply
WD40andTape 26:7c59002c9cd7 148 typeBit = inboundMsg>>1 & 0x1;
WD40andTape 26:7c59002c9cd7 149 inboundMsgsData[typeBit] = inboundMsg>>7 & 0x1FF;
WD40andTape 26:7c59002c9cd7 150 if( !CheckMessage(inboundMsg) ) {
WD40andTape 26:7c59002c9cd7 151 isSuccess = false;
WD40andTape 26:7c59002c9cd7 152 }
WD40andTape 26:7c59002c9cd7 153 }
WD40andTape 26:7c59002c9cd7 154 }
WD40andTape 26:7c59002c9cd7 155 return isSuccess;
WD40andTape 24:bc852aa89e7a 156 }
WD40andTape 24:bc852aa89e7a 157
WD40andTape 10:1b6daba32452 158 void LLComms::SendReceiveData(int channel) {
WD40andTape 24:bc852aa89e7a 159 mutChannel[channel].lock(); // Lock mutex for specific Channel
WD40andTape 24:bc852aa89e7a 160
WD40andTape 24:bc852aa89e7a 161 // Construct messages
WD40andTape 26:7c59002c9cd7 162 unsigned int intPositionMsg = formatMessage(0,demandPosition_mm[channel],MAX_ACTUATOR_LIMIT_MM);
WD40andTape 26:7c59002c9cd7 163 unsigned int intVelocityMsg = formatMessage(1,demandSpeed_mmps[channel],MAX_SPEED_MMPS);
WD40andTape 26:7c59002c9cd7 164
WD40andTape 26:7c59002c9cd7 165 *cs_LL[channel] = 0; // Select relevant chip
WD40andTape 26:7c59002c9cd7 166 unsigned int outboundMsgs[2] = { intPositionMsg , intVelocityMsg };
WD40andTape 27:6853ee8ffefd 167 unsigned int inboundMsgsData[2] = { 0 };
WD40andTape 26:7c59002c9cd7 168 bool isSPIsuccess = false;
WD40andTape 26:7c59002c9cd7 169 if( channel < 4 ) {
WD40andTape 26:7c59002c9cd7 170 isSPIsuccess = PerformMasterSPI(&spi_0,outboundMsgs,inboundMsgsData);
WD40andTape 36:4459be8296e9 171 } else if( channel < 7 ) {//was 7, but should have been 8?
WD40andTape 36:4459be8296e9 172 isSPIsuccess = PerformMasterSPI(&spi_1,outboundMsgs,inboundMsgsData);
WD40andTape 26:7c59002c9cd7 173 } else {
WD40andTape 36:4459be8296e9 174 isSPIsuccess = PerformMasterSPI(&spi_2,outboundMsgs,inboundMsgsData);
WD40andTape 26:7c59002c9cd7 175 }
WD40andTape 26:7c59002c9cd7 176 *cs_LL[channel] = 1; // Deselect chip
WD40andTape 26:7c59002c9cd7 177 if( isSPIsuccess ) {
WD40andTape 26:7c59002c9cd7 178 isDataReady[channel] = 0; // Data no longer ready, i.e. we now require new data
WD40andTape 29:10a5cf37a875 179 positionSensor_uint[channel] = inboundMsgsData[0];
WD40andTape 27:6853ee8ffefd 180 positionSensor_mm[channel] = ((double)inboundMsgsData[0]/511) * (double)MAX_ACTUATOR_LENGTH_MM;
WD40andTape 27:6853ee8ffefd 181 positionSensor_mm[channel] = min( max(positionSensor_mm[channel],0.0) , (double)MAX_ACTUATOR_LENGTH_MM );
WD40andTape 29:10a5cf37a875 182 pressureSensor_uint[channel] = inboundMsgsData[1];
WD40andTape 27:6853ee8ffefd 183 pressureSensor_bar[channel] = ((double)inboundMsgsData[1]/511) * (double)MAX_PRESSURE_LIMIT;
WD40andTape 27:6853ee8ffefd 184 pressureSensor_bar[channel] = min( max(pressureSensor_bar[channel],0.0) , (double)MAX_PRESSURE_LIMIT );
WD40andTape 26:7c59002c9cd7 185 } else { // Data is STILL ready and will be resent at the next pin interrupt
WD40andTape 26:7c59002c9cd7 186 //printf("SPI failed: %d%d. Resending.\n\r",isPositionValid,isPressureValid);
WD40andTape 26:7c59002c9cd7 187 }
WD40andTape 26:7c59002c9cd7 188
WD40andTape 26:7c59002c9cd7 189 mutChannel[channel].unlock();//unlock mutex for specific channel
WD40andTape 26:7c59002c9cd7 190 }
WD40andTape 26:7c59002c9cd7 191
WD40andTape 10:1b6daba32452 192 // Common rise handler function
WD40andTape 10:1b6daba32452 193 void LLComms::common_rise_handler(int channel) {
WD40andTape 26:7c59002c9cd7 194 //printf("%d %d common_rise_handler\n\r",channel,isDataReady[channel]);
WD40andTape 36:4459be8296e9 195 if(channel==6) chrp = 1;
WD40andTape 36:4459be8296e9 196 if(channel==0) chrp1 = 1;
WD40andTape 26:7c59002c9cd7 197 if (isDataReady[channel]) { // Check if data is ready for transmission
WD40andTape 10:1b6daba32452 198 ThreadID[channel] = queue.call(this,&LLComms::SendReceiveData,channel); // Schedule transmission
WD40andTape 10:1b6daba32452 199 }
WD40andTape 10:1b6daba32452 200 }
WD40andTape 10:1b6daba32452 201
WD40andTape 10:1b6daba32452 202 // Common fall handler functions
WD40andTape 10:1b6daba32452 203 void LLComms::common_fall_handler(int channel) {
WD40andTape 36:4459be8296e9 204 if(channel==6) chrp = 0;
WD40andTape 36:4459be8296e9 205 if(channel==0) chrp1 = 0;
WD40andTape 10:1b6daba32452 206 queue.cancel(ThreadID[channel]); // Cancel relevant queued event
WD40andTape 10:1b6daba32452 207 }
WD40andTape 10:1b6daba32452 208
WD40andTape 10:1b6daba32452 209 // Stub rise functions
WD40andTape 10:1b6daba32452 210 void LLComms::rise0(void) { common_rise_handler(0); }
WD40andTape 10:1b6daba32452 211 void LLComms::rise1(void) { common_rise_handler(1); }
WD40andTape 10:1b6daba32452 212 void LLComms::rise2(void) { common_rise_handler(2); }
WD40andTape 10:1b6daba32452 213 void LLComms::rise3(void) { common_rise_handler(3); }
WD40andTape 10:1b6daba32452 214 void LLComms::rise4(void) { common_rise_handler(4); }
WD40andTape 10:1b6daba32452 215 void LLComms::rise5(void) { common_rise_handler(5); }
WD40andTape 10:1b6daba32452 216 void LLComms::rise6(void) { common_rise_handler(6); }
WD40andTape 10:1b6daba32452 217 void LLComms::rise7(void) { common_rise_handler(7); }
WD40andTape 36:4459be8296e9 218 void LLComms::rise8(void) { common_rise_handler(8); }
WD40andTape 10:1b6daba32452 219 // Stub fall functions
WD40andTape 10:1b6daba32452 220 void LLComms::fall0(void) { common_fall_handler(0); }
WD40andTape 10:1b6daba32452 221 void LLComms::fall1(void) { common_fall_handler(1); }
WD40andTape 10:1b6daba32452 222 void LLComms::fall2(void) { common_fall_handler(2); }
WD40andTape 10:1b6daba32452 223 void LLComms::fall3(void) { common_fall_handler(3); }
WD40andTape 10:1b6daba32452 224 void LLComms::fall4(void) { common_fall_handler(4); }
WD40andTape 10:1b6daba32452 225 void LLComms::fall5(void) { common_fall_handler(5); }
WD40andTape 10:1b6daba32452 226 void LLComms::fall6(void) { common_fall_handler(6); }
WD40andTape 36:4459be8296e9 227 void LLComms::fall7(void) { common_fall_handler(7); }
WD40andTape 36:4459be8296e9 228 void LLComms::fall8(void) { common_fall_handler(8); }