Dirk (Diskussion | Beiträge) K (→Planung) |
Dirk (Diskussion | Beiträge) K (→I2C-Slave) |
||
| Zeile 101: | Zeile 101: | ||
=I2C-Slave= | =I2C-Slave= | ||
| + | Hier mal eine erste Version des M32 I2C-Slave. | ||
| + | Datei RP6Control_I2CSlave.c: | ||
| + | <pre>/* | ||
| + | * **************************************************************************** | ||
| + | * RP6 ROBOT SYSTEM - RP6 CONTROL M32 EXAMPLES | ||
| + | * **************************************************************************** | ||
| + | * Example: I2C Slave | ||
| + | * Author(s): Dirk | ||
| + | * **************************************************************************** | ||
| + | * Description: | ||
| + | * | ||
| + | * A very common thing that many users will want to do with their M32 is | ||
| + | * to control it with a second controller which has more free resources. | ||
| + | * (more free memory, free I/O Ports and ADCs, faster, etc. pp. | ||
| + | * for example the RP6 C-Control PRO M128 or M256 WIFI expansion Module) | ||
| + | * | ||
| + | * This programs allows you to control the RP6 CONTROL M32 completely via | ||
| + | * I2C-Bus as a slave device! | ||
| + | * | ||
| + | * ############################################################################ | ||
| + | * The Robot does NOT move in this example! You can simply put it on a table | ||
| + | * next to your PC and you should connect it to the PC via the USB Interface! | ||
| + | * ############################################################################ | ||
| + | * **************************************************************************** | ||
| + | */ | ||
| + | |||
| + | /*****************************************************************************/ | ||
| + | // Includes: | ||
| + | |||
| + | #include "RP6ControlLib.h" // The RP6 Control Library v1.32beta. | ||
| + | // Always needs to be included! | ||
| + | #include "RP6I2CslaveTWI.h" // Include the I²C-Bus Slave Library | ||
| + | |||
| + | /*****************************************************************************/ | ||
| + | |||
| + | // The Slave Address on the I2C Bus can be specified here: | ||
| + | #define RP6Control_I2C_SLAVE_ADR 12 | ||
| + | |||
| + | /*****************************************************************************/ | ||
| + | |||
| + | // This bitfield contains the main interrupt event status bits. This can be | ||
| + | // read out and any Master devices can react on the specific events. | ||
| + | union { | ||
| + | uint8_t byte; | ||
| + | struct { | ||
| + | uint8_t timeout:1; | ||
| + | uint8_t mem_cs2Change:1; | ||
| + | uint8_t insChange:1; | ||
| + | uint8_t keyChange:1; | ||
| + | uint8_t keypressed:1; | ||
| + | uint8_t unused:3; | ||
| + | }; | ||
| + | } interrupt_status; | ||
| + | |||
| + | // Some status bits with current settings and other things. | ||
| + | union { | ||
| + | uint8_t byte; | ||
| + | struct { | ||
| + | uint8_t old_mem_cs2:1; | ||
| + | uint8_t mem_cs2:1; | ||
| + | uint8_t watchDogTimer:1; | ||
| + | uint8_t wdtRequest:1; | ||
| + | uint8_t wdtRequestEnable:1; | ||
| + | uint8_t heartbeat:1; | ||
| + | uint8_t unused:2; | ||
| + | }; | ||
| + | } status; | ||
| + | |||
| + | /*****************************************************************************/ | ||
| + | |||
| + | /** | ||
| + | * Generates Interrupt Signal and starts Software Watchdog | ||
| + | */ | ||
| + | void signalInterrupt(void) | ||
| + | { | ||
| + | I2CTWI_dataWasRead = 0; | ||
| + | DDRD |= EINT2; // XBUS INT2 | ||
| + | PORTD |= EINT2; | ||
| + | if(status.watchDogTimer) | ||
| + | startStopwatch2(); | ||
| + | } | ||
| + | |||
| + | /** | ||
| + | * Clears Interrupt | ||
| + | */ | ||
| + | void clearInterrupt(void) | ||
| + | { | ||
| + | stopStopwatch2(); | ||
| + | setStopwatch2(0); | ||
| + | status.wdtRequest = false; | ||
| + | PORTD &= ~EINT2; // XBUS INT2 | ||
| + | DDRD &= ~EINT2; | ||
| + | } | ||
| + | |||
| + | freeIOs_t old_ins; | ||
| + | uint8_t old_releasedKeyNumber; | ||
| + | uint8_t update_count = 0; | ||
| + | |||
| + | /** | ||
| + | * This function needs to be called frequently in the main loop. It updates | ||
| + | * some values (currently only mem_cs2Change, insChange, keyChange and | ||
| + | * keypressed status, but this may be expanded in future). | ||
| + | */ | ||
| + | void task_update(void) | ||
| + | { | ||
| + | if(getStopwatch4() > 250) | ||
| + | { | ||
| + | // Update mem_cs2 status: | ||
| + | status.mem_cs2 = PINB & MEM_CS2; | ||
| + | update_count++; | ||
| + | setStopwatch4(0); | ||
| + | } | ||
| + | if(update_count > 5) | ||
| + | { | ||
| + | // Update mem_cs2Change: | ||
| + | if(!interrupt_status.mem_cs2Change | ||
| + | && (status.mem_cs2 != status.old_mem_cs2)) | ||
| + | { | ||
| + | status.old_mem_cs2 = status.mem_cs2; | ||
| + | interrupt_status.mem_cs2Change = true; | ||
| + | signalInterrupt(); | ||
| + | } | ||
| + | else if(interrupt_status.mem_cs2Change | ||
| + | && (status.mem_cs2 == status.old_mem_cs2)) | ||
| + | { | ||
| + | interrupt_status.mem_cs2Change = false; | ||
| + | signalInterrupt(); | ||
| + | } | ||
| + | // Update insChange: | ||
| + | if(!interrupt_status.insChange && (ins.byte != old_ins.byte)) | ||
| + | { | ||
| + | old_ins = ins; | ||
| + | interrupt_status.insChange = true; | ||
| + | signalInterrupt(); | ||
| + | } | ||
| + | else if(interrupt_status.insChange && (ins.byte == old_ins.byte)) | ||
| + | { | ||
| + | interrupt_status.insChange = false; | ||
| + | signalInterrupt(); | ||
| + | } | ||
| + | // Update keyChange: | ||
| + | if(!interrupt_status.keyChange | ||
| + | && (releasedKeyNumber != old_releasedKeyNumber)) | ||
| + | { | ||
| + | old_releasedKeyNumber = releasedKeyNumber; | ||
| + | interrupt_status.keyChange = true; | ||
| + | signalInterrupt(); | ||
| + | } | ||
| + | else if(interrupt_status.keyChange | ||
| + | && (releasedKeyNumber == old_releasedKeyNumber)) | ||
| + | { | ||
| + | interrupt_status.keyChange = false; | ||
| + | signalInterrupt(); | ||
| + | } | ||
| + | update_count = 0; | ||
| + | } | ||
| + | // Update keypressed status: | ||
| + | interrupt_status.keypressed = pressedKeyNumber; | ||
| + | } | ||
| + | |||
| + | /*****************************************************************************/ | ||
| + | // I2C Registers that can be read by the Master. Their names should | ||
| + | // be self-explanatory and directly relate to the equivalent variables/functions | ||
| + | // in the RP6Library | ||
| + | |||
| + | #define I2C_REG_STATUS1 0 | ||
| + | #define I2C_REG_STATUS2 1 | ||
| + | #define I2C_REG_IO_STATUS 2 | ||
| + | #define I2C_REG_MEM_CS2 3 | ||
| + | #define I2C_REG_SPIBYTE 4 | ||
| + | #define I2C_REG_SPIWORD_L 5 | ||
| + | #define I2C_REG_SPIWORD_H 6 | ||
| + | #define I2C_REG_SPIEEPROMSTATUS 7 | ||
| + | #define I2C_REG_SPIEEPROMBYTE 8 | ||
| + | #define I2C_REG_SPIEEPROMWORD_L 9 | ||
| + | #define I2C_REG_SPIEEPROMWORD_H 10 | ||
| + | #define I2C_REG_ADC_4_L 11 | ||
| + | #define I2C_REG_ADC_4_H 12 | ||
| + | #define I2C_REG_ADC_3_L 13 | ||
| + | #define I2C_REG_ADC_3_H 14 | ||
| + | #define I2C_REG_ADC_2_L 15 | ||
| + | #define I2C_REG_ADC_2_H 16 | ||
| + | #define I2C_REG_ADC_6_L 17 | ||
| + | #define I2C_REG_ADC_6_H 18 | ||
| + | #define I2C_REG_ADC_5_L 19 | ||
| + | #define I2C_REG_ADC_5_H 20 | ||
| + | #define I2C_REG_ADC_7_L 21 | ||
| + | #define I2C_REG_ADC_7_H 22 | ||
| + | #define I2C_REG_ADC_MIC_L 23 | ||
| + | #define I2C_REG_ADC_MIC_H 24 | ||
| + | #define I2C_REG_ADC_KEYPAD_L 25 | ||
| + | #define I2C_REG_ADC_KEYPAD_H 26 | ||
| + | #define I2C_REG_RELEASEDKEYNUMBER 27 | ||
| + | #define I2C_REG_PRESSEDKEYNUMBER 28 | ||
| + | #define I2C_REG_LEDS 29 | ||
| + | |||
| + | |||
| + | // These variables contain the results of the functions readSPI(), | ||
| + | // readWordSPI(), SPI_EEPROM_readByte[s](), SPI_EEPROM_getStatus() after the | ||
| + | // Master sent one of the commands CMD_READSPI, CMD_READWORDSPI, | ||
| + | // CMD_SPI_EEPROM_READBYTE/WORD, CMD_SPI_EEPROM_GETSTATUS. So these variables | ||
| + | // are updated only "on demand" and NOT permanently! | ||
| + | uint8_t spibyte; | ||
| + | uint16_t spiword; | ||
| + | uint8_t spieepromstatus; | ||
| + | uint8_t spieeprombyte; | ||
| + | uint16_t spieepromword; | ||
| + | |||
| + | /** | ||
| + | * This very important function updates ALL registers that the Master can read. | ||
| + | * It is called frequently out of the Main loop. | ||
| + | */ | ||
| + | void task_updateRegisters(void) | ||
| + | { | ||
| + | if(!I2CTWI_readBusy) | ||
| + | { | ||
| + | I2CTWI_readRegisters[I2C_REG_STATUS1] = (uint8_t)(interrupt_status.byte); | ||
| + | I2CTWI_readRegisters[I2C_REG_STATUS2] = (uint8_t)(status.byte); | ||
| + | I2CTWI_readRegisters[I2C_REG_IO_STATUS] = (uint8_t)(ins.byte); | ||
| + | I2CTWI_readRegisters[I2C_REG_MEM_CS2] = (uint8_t)(status.mem_cs2); | ||
| + | I2CTWI_readRegisters[I2C_REG_SPIBYTE] = (uint8_t)(spibyte); | ||
| + | I2CTWI_readRegisters[I2C_REG_SPIWORD_L] = (uint8_t)(spiword); | ||
| + | I2CTWI_readRegisters[I2C_REG_SPIWORD_H] = (uint8_t)(spiword>>8); | ||
| + | I2CTWI_readRegisters[I2C_REG_SPIEEPROMSTATUS] = (uint8_t)(spieepromstatus); | ||
| + | I2CTWI_readRegisters[I2C_REG_SPIEEPROMBYTE] = (uint8_t)(spieeprombyte); | ||
| + | I2CTWI_readRegisters[I2C_REG_SPIEEPROMWORD_L] = (uint8_t)(spieepromword); | ||
| + | I2CTWI_readRegisters[I2C_REG_SPIEEPROMWORD_H] = (uint8_t)(spieepromword>>8); | ||
| + | I2CTWI_readRegisters[I2C_REG_ADC_4_L] = (uint8_t)(adc4); | ||
| + | I2CTWI_readRegisters[I2C_REG_ADC_4_H] = (uint8_t)(adc4>>8); | ||
| + | I2CTWI_readRegisters[I2C_REG_ADC_3_L] = (uint8_t)(adc3); | ||
| + | I2CTWI_readRegisters[I2C_REG_ADC_3_H] = (uint8_t)(adc3>>8); | ||
| + | I2CTWI_readRegisters[I2C_REG_ADC_2_L] = (uint8_t)(adc2); | ||
| + | I2CTWI_readRegisters[I2C_REG_ADC_2_H] = (uint8_t)(adc2>>8); | ||
| + | I2CTWI_readRegisters[I2C_REG_ADC_6_L] = (uint8_t)(adc6); | ||
| + | I2CTWI_readRegisters[I2C_REG_ADC_6_H] = (uint8_t)(adc6>>8); | ||
| + | I2CTWI_readRegisters[I2C_REG_ADC_5_L] = (uint8_t)(adc5); | ||
| + | I2CTWI_readRegisters[I2C_REG_ADC_5_H] = (uint8_t)(adc5>>8); | ||
| + | I2CTWI_readRegisters[I2C_REG_ADC_7_L] = (uint8_t)(adc7); | ||
| + | I2CTWI_readRegisters[I2C_REG_ADC_7_H] = (uint8_t)(adc7>>8); | ||
| + | I2CTWI_readRegisters[I2C_REG_ADC_MIC_L] = (uint8_t)(adcMic); | ||
| + | I2CTWI_readRegisters[I2C_REG_ADC_MIC_H] = (uint8_t)(adcMic>>8); | ||
| + | I2CTWI_readRegisters[I2C_REG_ADC_KEYPAD_L] = (uint8_t)(adcKeypad); | ||
| + | I2CTWI_readRegisters[I2C_REG_ADC_KEYPAD_H] = (uint8_t)(adcKeypad>>8); | ||
| + | I2CTWI_readRegisters[I2C_REG_RELEASEDKEYNUMBER] = (uint8_t)(releasedKeyNumber); | ||
| + | I2CTWI_readRegisters[I2C_REG_PRESSEDKEYNUMBER] = (uint8_t)(pressedKeyNumber); | ||
| + | I2CTWI_readRegisters[I2C_REG_LEDS] = (uint8_t)(externalPort.LEDS); | ||
| + | if(I2CTWI_dataWasRead && I2CTWI_dataReadFromReg == 0) | ||
| + | clearInterrupt(); | ||
| + | } | ||
| + | } | ||
| + | |||
| + | /*****************************************************************************/ | ||
| + | // Command Registers - these can be written by the Master. | ||
| + | // The other registers (read registers) can NOT be written to. The only way to | ||
| + | // communicate with the M32 is via specific commands. | ||
| + | // Of course you can also add more registers if you like... | ||
| + | |||
| + | // ---------------------- | ||
| + | |||
| + | #define I2C_REGW_CMD 0 | ||
| + | #define I2C_REGW_CMD_PARAM1 1 | ||
| + | #define I2C_REGW_CMD_PARAM2 2 | ||
| + | #define I2C_REGW_CMD_PARAM3 3 | ||
| + | #define I2C_REGW_CMD_PARAM4 4 | ||
| + | #define I2C_REGW_CMD_PARAM5 5 | ||
| + | #define I2C_REGW_CMD_PARAM6 6 | ||
| + | |||
| + | // ---------------------- | ||
| + | |||
| + | uint8_t cmd; | ||
| + | uint8_t param1; | ||
| + | uint8_t param2; | ||
| + | uint8_t param3; | ||
| + | uint8_t param4; | ||
| + | uint8_t param5; | ||
| + | uint8_t param6; | ||
| + | |||
| + | /** | ||
| + | * Checks if a new Command has been received and also reads all | ||
| + | * paramters associated with this command. | ||
| + | * It returns true if a new command has been received. | ||
| + | */ | ||
| + | uint8_t getCommand(void) | ||
| + | { | ||
| + | if(I2CTWI_writeRegisters[I2C_REGW_CMD] && !I2CTWI_writeBusy) | ||
| + | { | ||
| + | cmd = I2CTWI_writeRegisters[I2C_REGW_CMD]; // store command register | ||
| + | I2CTWI_writeRegisters[I2C_REGW_CMD] = 0; // clear command register (!!!) | ||
| + | param1 = I2CTWI_writeRegisters[I2C_REGW_CMD_PARAM1]; // parameters 1-6... | ||
| + | param2 = I2CTWI_writeRegisters[I2C_REGW_CMD_PARAM2]; | ||
| + | param3 = I2CTWI_writeRegisters[I2C_REGW_CMD_PARAM3]; | ||
| + | param4 = I2CTWI_writeRegisters[I2C_REGW_CMD_PARAM4]; | ||
| + | param5 = I2CTWI_writeRegisters[I2C_REGW_CMD_PARAM5]; | ||
| + | param6 = I2CTWI_writeRegisters[I2C_REGW_CMD_PARAM6]; | ||
| + | return true; | ||
| + | } | ||
| + | return false; | ||
| + | } | ||
| + | |||
| + | /*****************************************************************************/ | ||
| + | // Command processor: | ||
| + | |||
| + | // Commands: | ||
| + | #define CMD_CONFIGIOS 0 | ||
| + | #define CMD_SETIOS 1 | ||
| + | #define CMD_CONFIG 2 | ||
| + | #define CMD_SETLEDS 3 | ||
| + | #define CMD_DISCHARGEPEAKDETECTOR 4 | ||
| + | #define CMD_GETMICROPHONEPEAK 5 | ||
| + | #define CMD_SETMEM_CS2 6 | ||
| + | #define CMD_WRITESPI 7 | ||
| + | #define CMD_WRITEWORDSPI 8 | ||
| + | #define CMD_READSPI 9 | ||
| + | #define CMD_READWORDSPI 10 | ||
| + | |||
| + | #define CMD_SET_WDT 11 | ||
| + | #define CMD_SET_WDT_RQ 12 | ||
| + | #define CMD_SET_HEARTBEAT 13 | ||
| + | |||
| + | #define CMD_SPI_EEPROM_WRITEBYTE 14 | ||
| + | #define CMD_SPI_EEPROM_WRITEWORD 15 | ||
| + | #define CMD_SPI_EEPROM_ENABLEWRITE 16 | ||
| + | #define CMD_SPI_EEPROM_DISABLEWRITE 17 | ||
| + | #define CMD_SPI_EEPROM_READBYTE 18 | ||
| + | #define CMD_SPI_EEPROM_READWORD 19 | ||
| + | #define CMD_SPI_EEPROM_GETSTATUS 20 | ||
| + | |||
| + | #define CMD_INITLCD 21 | ||
| + | #define CMD_CLEARLCD 22 | ||
| + | #define CMD_CLEARPOSLCD 23 | ||
| + | #define CMD_WRITECHARLCD 24 | ||
| + | #define CMD_WRITEINTEGERLCD 25 | ||
| + | #define CMD_SETCURSORPOSLCD 26 | ||
| + | |||
| + | #define CMD_BEEP 27 | ||
| + | #define CMD_SETBEEPERPITCH 28 | ||
| + | #define CMD_SOUND 29 | ||
| + | |||
| + | |||
| + | uint8_t rw_buffer[3]; | ||
| + | |||
| + | /** | ||
| + | * This function checks if commands have been received and processes them. | ||
| + | */ | ||
| + | void task_commandProcessor(void) | ||
| + | { | ||
| + | if(getCommand()) | ||
| + | { | ||
| + | switch(cmd) | ||
| + | { | ||
| + | case CMD_CONFIGIOS: if(param1) setFreeIOsToOUT(); else setFreeIOsToIN(); break; | ||
| + | case CMD_SETIOS: setOUTs(param1); break; | ||
| + | case CMD_CONFIG: break; | ||
| + | case CMD_SETLEDS: setLEDs(param1); break; | ||
| + | case CMD_DISCHARGEPEAKDETECTOR: dischargePeakDetector(); break; | ||
| + | case CMD_GETMICROPHONEPEAK: adcMic = getMicrophonePeak(); break; | ||
| + | case CMD_SETMEM_CS2: if(param1) PORTB |= MEM_CS2; else PORTB &= ~MEM_CS2; break; | ||
| + | case CMD_WRITESPI: writeSPI(param1); break; | ||
| + | case CMD_WRITEWORDSPI: writeWordSPI((param1<<8)+param2); break; | ||
| + | case CMD_READSPI: spibyte = readSPI(); break; | ||
| + | case CMD_READWORDSPI: spiword = readWordSPI(); break; | ||
| + | case CMD_SET_WDT: status.watchDogTimer = param1 ? true : false; break; | ||
| + | case CMD_SET_WDT_RQ: status.wdtRequestEnable = param1 ? true : false; break; | ||
| + | case CMD_SET_HEARTBEAT: status.heartbeat = param1 ? true : false; break; | ||
| + | case CMD_SPI_EEPROM_WRITEBYTE: SPI_EEPROM_writeByte((param1<<8)+param2, param3); break; | ||
| + | case CMD_SPI_EEPROM_WRITEWORD: rw_buffer[0] = param3; rw_buffer[1] = param4; | ||
| + | SPI_EEPROM_writeBytes((param1<<8)+param2, &rw_buffer[0], 2); break; | ||
| + | case CMD_SPI_EEPROM_ENABLEWRITE: SPI_EEPROM_enableWrite(); break; | ||
| + | case CMD_SPI_EEPROM_DISABLEWRITE: SPI_EEPROM_disableWrite(); break; | ||
| + | case CMD_SPI_EEPROM_READBYTE: spieeprombyte = SPI_EEPROM_readByte((param1<<8)+param2); break; | ||
| + | case CMD_SPI_EEPROM_READWORD: SPI_EEPROM_readBytes((param1<<8)+param2, &rw_buffer[0], 2); | ||
| + | spieepromword = (rw_buffer[0]<<8)+rw_buffer[1]; break; | ||
| + | case CMD_SPI_EEPROM_GETSTATUS: spieepromstatus = SPI_EEPROM_getStatus(); break; | ||
| + | case CMD_INITLCD: initLCD(); break; | ||
| + | case CMD_CLEARLCD: clearLCD(); break; | ||
| + | case CMD_CLEARPOSLCD: clearPosLCD(param1, param2, param3); break; | ||
| + | case CMD_WRITECHARLCD: writeCharLCD(param1); break; | ||
| + | case CMD_WRITEINTEGERLCD: writeIntegerLCD((param1<<8)+param2, param3); break; | ||
| + | case CMD_SETCURSORPOSLCD: setCursorPosLCD(param1, param2); break; | ||
| + | case CMD_BEEP: beep(param1, (param2<<8)+param3); break; | ||
| + | case CMD_SETBEEPERPITCH: setBeeperPitch(param1); break; | ||
| + | case CMD_SOUND: sound(param1, (param2<<8)+param3, (param4<<8)+param5); break; | ||
| + | } | ||
| + | } | ||
| + | } | ||
| + | |||
| + | /** | ||
| + | * This is the Software watchdog function. After any interrupt event, a timer is | ||
| + | * started and if a certain amount of time has passed by with no reaction from | ||
| + | * the Master, the RP6 CONTROL M32 shows this by blinking with status LEDs 1..4 | ||
| + | * for 3 seconds. After this the interrupt and interrupt status are cleared. | ||
| + | * Usually the Master program has errors or is locked up if it does not react, | ||
| + | * so the blinking LEDs show, that there is a communication problem. | ||
| + | */ | ||
| + | void task_MasterTimeout(void) | ||
| + | { | ||
| + | if(status.watchDogTimer) | ||
| + | { | ||
| + | static uint8_t blinkflag = 0; | ||
| + | if(getStopwatch2() > 3000) // 3 seconds timeout for the master to react on | ||
| + | { // our interrupt events - if he does not react, we | ||
| + | // blink with LEDs 1..4 for another 3 seconds! | ||
| + | interrupt_status.timeout = true; | ||
| + | if(getStopwatch2() > 6000) | ||
| + | { | ||
| + | setLEDs(0b0000); // Clear LEDs | ||
| + | interrupt_status.byte = 0; // Clear interrupt status | ||
| + | setStopwatch4(0); | ||
| + | clearInterrupt(); // Clear interrupt | ||
| + | } | ||
| + | } | ||
| + | else if(getStopwatch3() > 250) | ||
| + | { | ||
| + | status.wdtRequest = true; | ||
| + | signalInterrupt(); | ||
| + | setStopwatch3(0); | ||
| + | } | ||
| + | if(interrupt_status.timeout) | ||
| + | { | ||
| + | if(getStopwatch5() > 200) | ||
| + | { | ||
| + | if(blinkflag) | ||
| + | { | ||
| + | setLEDs(0b1001); | ||
| + | blinkflag = 0; | ||
| + | } | ||
| + | else | ||
| + | { | ||
| + | setLEDs(0b0110); | ||
| + | blinkflag = 1; | ||
| + | } | ||
| + | setStopwatch5(0); | ||
| + | } | ||
| + | } | ||
| + | } | ||
| + | } | ||
| + | |||
| + | /** | ||
| + | * LCD Heartbeat function | ||
| + | */ | ||
| + | void task_LCDHeartbeat(void) | ||
| + | { | ||
| + | if(status.heartbeat) | ||
| + | { | ||
| + | if(getStopwatch1() > 500) | ||
| + | { | ||
| + | static uint8_t heartbeat = false; | ||
| + | if(heartbeat) | ||
| + | { | ||
| + | clearPosLCD(1, 15, 1); | ||
| + | heartbeat = false; | ||
| + | } | ||
| + | else | ||
| + | { | ||
| + | setCursorPosLCD(1, 15); | ||
| + | writeStringLCD_P("*"); | ||
| + | heartbeat = true; | ||
| + | } | ||
| + | setStopwatch1(0); | ||
| + | } | ||
| + | } | ||
| + | } | ||
| + | |||
| + | /*****************************************************************************/ | ||
| + | // Main - The program starts here: | ||
| + | |||
| + | int16_t main(void) | ||
| + | { | ||
| + | initRP6Control(); | ||
| + | |||
| + | setLEDs(0b1111); | ||
| + | mSleep(500); | ||
| + | setLEDs(0b0000); | ||
| + | |||
| + | I2CTWI_initSlave(RP6Control_I2C_SLAVE_ADR); | ||
| + | |||
| + | status.byte = 0; | ||
| + | interrupt_status.byte = 0; | ||
| + | // TEST TEST TEST TEST TEST TEST | ||
| + | status.watchDogTimer = true; | ||
| + | status.heartbeat = true; | ||
| + | // TEST TEST TEST TEST TEST TEST | ||
| + | startStopwatch1(); // For LCDHeartbeat function | ||
| + | startStopwatch3(); | ||
| + | startStopwatch4(); | ||
| + | startStopwatch5(); | ||
| + | |||
| + | while(true) | ||
| + | { | ||
| + | task_commandProcessor(); | ||
| + | task_update(); | ||
| + | task_updateRegisters(); | ||
| + | task_RP6M32System(); | ||
| + | task_MasterTimeout(); | ||
| + | task_LCDHeartbeat(); | ||
| + | } | ||
| + | |||
| + | return 0; | ||
| + | } | ||
| + | </pre> | ||
=I2C-Master (RP6v2 M256 WiFi)= | =I2C-Master (RP6v2 M256 WiFi)= | ||
Version vom 13. September 2012, 21:13 Uhr
Inhaltsverzeichnis
Planung
Erst mal die Planung:
- 1. Der I2C-Slave für die M32 soll genauso arbeiten, wie der RP6Base I2C-Slave (RP6Base_I2CSlave.c) in den Demos.
- 2. Er soll möglichst (fast) alle Funktionen/Ressourcen der M32 über I2C "fernsteuerbar" bzw. abfragbar machen.
- 3. Er soll als I2C-Master eine andere M32, die CCPRO M128 oder die M256 WiFi akzeptieren.
- 4. Er soll die I2C-Adresse 12 bekommen.
- 5. Er soll über XBUS INT2 mit dem Master verbunden sein.
- 6. Er soll wie der Base-Slave auch eine Timeout-Funktion haben.
- 7. Er soll folgende Befehle (commands) über I2C verstehen:
// Commands: #define CMD_CONFIGIOS 0 #define CMD_SETIOS 1 #define CMD_CONFIG 2 #define CMD_SETLEDS 3 #define CMD_DISCHARGEPEAKDETECTOR 4 #define CMD_GETMICROPHONEPEAK 5 #define CMD_SETMEM_CS2 6 #define CMD_WRITESPI 7 #define CMD_WRITEWORDSPI 8 #define CMD_READSPI 9 #define CMD_READWORDSPI 10 #define CMD_SET_WDT 11 #define CMD_SET_WDT_RQ 12 #define CMD_SET_HEARTBEAT 13 #define CMD_SPI_EEPROM_WRITEBYTE 14 #define CMD_SPI_EEPROM_WRITEWORD 15 #define CMD_SPI_EEPROM_ENABLEWRITE 16 #define CMD_SPI_EEPROM_DISABLEWRITE 17 #define CMD_SPI_EEPROM_READBYTE 18 #define CMD_SPI_EEPROM_READWORD 19 #define CMD_SPI_EEPROM_GETSTATUS 20 #define CMD_INITLCD 21 #define CMD_CLEARLCD 22 #define CMD_CLEARPOSLCD 23 #define CMD_WRITECHARLCD 24 #define CMD_WRITEINTEGERLCD 25 #define CMD_SETCURSORPOSLCD 26 #define CMD_BEEP 27 #define CMD_SETBEEPERPITCH 28 #define CMD_SOUND 29
Dabei setzt Befehl 0 die 8 freien I/O-Pins der M32 als Ein- oder Ausgänge. Befehl 1 schaltet die einzelnen I/O-Portpins. Befehl 2 ist Platzhalter ohne Funktion (z.B. zur Konfiguration des Slave). Befehl 3 schaltet die LEDs. Befehle 4, 5 gehen mit dem Mikro um. Befehle 6-10 sind die SPI-Befehle. Befehle 11,12 gehören zum Watchdog-Timer (wie bei der Base!). Befehl 13 schaltet die LCD Heartbeat (Herzschlag) Funktion. Befehle 14-20 lesen und schreiben von/aus dem SPI-EEPROM auf der M32. Befehle 21-26 steuern das LCD auf der M32 an. Befehle 27-29 steuern den Sound mit dem Beeper.
- 8. Er soll folgende Register zum Lesen durch den Master vorhalten:
#define I2C_REG_STATUS1 0 #define I2C_REG_STATUS2 1 #define I2C_REG_IO_STATUS 2 #define I2C_REG_MEM_CS2 3 #define I2C_REG_SPIBYTE 4 #define I2C_REG_SPIWORD_L 5 #define I2C_REG_SPIWORD_H 6 #define I2C_REG_SPIEEPROMSTATUS 7 #define I2C_REG_SPIEEPROMBYTE 8 #define I2C_REG_SPIEEPROMWORD_L 9 #define I2C_REG_SPIEEPROMWORD_H 10 #define I2C_REG_ADC_4_L 11 #define I2C_REG_ADC_4_H 12 #define I2C_REG_ADC_3_L 13 #define I2C_REG_ADC_3_H 14 #define I2C_REG_ADC_2_L 15 #define I2C_REG_ADC_2_H 16 #define I2C_REG_ADC_6_L 17 #define I2C_REG_ADC_6_H 18 #define I2C_REG_ADC_5_L 19 #define I2C_REG_ADC_5_H 20 #define I2C_REG_ADC_7_L 21 #define I2C_REG_ADC_7_H 22 #define I2C_REG_ADC_MIC_L 23 #define I2C_REG_ADC_MIC_H 24 #define I2C_REG_ADC_KEYPAD_L 25 #define I2C_REG_ADC_KEYPAD_H 26 #define I2C_REG_RELEASEDKEYNUMBER 27 #define I2C_REG_PRESSEDKEYNUMBER 28 #define I2C_REG_LEDS 29
Die REGs 0,1 sind die Interrupt- und Status-Register wie beim Base-Slave. IO-Status (REG 2) sind die 8 freien I/O-Ports (sofern auf Eingänge geschaltet). REGs 3-10 sind Leseregister der SPI- und SPI-EEPROM-Funktionen. REGs 11-22 sind die freien ADC-Kanäle der M32. REGs 23,24 sind der ADC-Wert des Mikro. REGs 25,26 sind der ADC-Keypad-Wert. REGs 27,28 sind die Nummern der zuletzt losgelassenen bzw. gedrückten Taste. Mit REG 29 läßt sich der aktuelle Stand der 4 LEDs auslesen (an/aus).
- 9. Er soll auf die RP6Control Library V1.32beta aufsetzen. Grund: Die aktuelle Lib V1.32beta ist voll kompatibel zur neuesten Version 1.3 und stellt mit eigenen Tasks schon regelmäßig die ADC-Werte und Werte der I/O-Ports zur Verfügung.
- 10. Bei Timeout soll die M32 funktionsfähig bleiben (Base-Slave bleibt dann in einer Endlosschleife stehen und muss resettet werden!).
I2C-Slave
Hier mal eine erste Version des M32 I2C-Slave.
Datei RP6Control_I2CSlave.c:
/*
* ****************************************************************************
* RP6 ROBOT SYSTEM - RP6 CONTROL M32 EXAMPLES
* ****************************************************************************
* Example: I2C Slave
* Author(s): Dirk
* ****************************************************************************
* Description:
*
* A very common thing that many users will want to do with their M32 is
* to control it with a second controller which has more free resources.
* (more free memory, free I/O Ports and ADCs, faster, etc. pp.
* for example the RP6 C-Control PRO M128 or M256 WIFI expansion Module)
*
* This programs allows you to control the RP6 CONTROL M32 completely via
* I2C-Bus as a slave device!
*
* ############################################################################
* The Robot does NOT move in this example! You can simply put it on a table
* next to your PC and you should connect it to the PC via the USB Interface!
* ############################################################################
* ****************************************************************************
*/
/*****************************************************************************/
// Includes:
#include "RP6ControlLib.h" // The RP6 Control Library v1.32beta.
// Always needs to be included!
#include "RP6I2CslaveTWI.h" // Include the I²C-Bus Slave Library
/*****************************************************************************/
// The Slave Address on the I2C Bus can be specified here:
#define RP6Control_I2C_SLAVE_ADR 12
/*****************************************************************************/
// This bitfield contains the main interrupt event status bits. This can be
// read out and any Master devices can react on the specific events.
union {
uint8_t byte;
struct {
uint8_t timeout:1;
uint8_t mem_cs2Change:1;
uint8_t insChange:1;
uint8_t keyChange:1;
uint8_t keypressed:1;
uint8_t unused:3;
};
} interrupt_status;
// Some status bits with current settings and other things.
union {
uint8_t byte;
struct {
uint8_t old_mem_cs2:1;
uint8_t mem_cs2:1;
uint8_t watchDogTimer:1;
uint8_t wdtRequest:1;
uint8_t wdtRequestEnable:1;
uint8_t heartbeat:1;
uint8_t unused:2;
};
} status;
/*****************************************************************************/
/**
* Generates Interrupt Signal and starts Software Watchdog
*/
void signalInterrupt(void)
{
I2CTWI_dataWasRead = 0;
DDRD |= EINT2; // XBUS INT2
PORTD |= EINT2;
if(status.watchDogTimer)
startStopwatch2();
}
/**
* Clears Interrupt
*/
void clearInterrupt(void)
{
stopStopwatch2();
setStopwatch2(0);
status.wdtRequest = false;
PORTD &= ~EINT2; // XBUS INT2
DDRD &= ~EINT2;
}
freeIOs_t old_ins;
uint8_t old_releasedKeyNumber;
uint8_t update_count = 0;
/**
* This function needs to be called frequently in the main loop. It updates
* some values (currently only mem_cs2Change, insChange, keyChange and
* keypressed status, but this may be expanded in future).
*/
void task_update(void)
{
if(getStopwatch4() > 250)
{
// Update mem_cs2 status:
status.mem_cs2 = PINB & MEM_CS2;
update_count++;
setStopwatch4(0);
}
if(update_count > 5)
{
// Update mem_cs2Change:
if(!interrupt_status.mem_cs2Change
&& (status.mem_cs2 != status.old_mem_cs2))
{
status.old_mem_cs2 = status.mem_cs2;
interrupt_status.mem_cs2Change = true;
signalInterrupt();
}
else if(interrupt_status.mem_cs2Change
&& (status.mem_cs2 == status.old_mem_cs2))
{
interrupt_status.mem_cs2Change = false;
signalInterrupt();
}
// Update insChange:
if(!interrupt_status.insChange && (ins.byte != old_ins.byte))
{
old_ins = ins;
interrupt_status.insChange = true;
signalInterrupt();
}
else if(interrupt_status.insChange && (ins.byte == old_ins.byte))
{
interrupt_status.insChange = false;
signalInterrupt();
}
// Update keyChange:
if(!interrupt_status.keyChange
&& (releasedKeyNumber != old_releasedKeyNumber))
{
old_releasedKeyNumber = releasedKeyNumber;
interrupt_status.keyChange = true;
signalInterrupt();
}
else if(interrupt_status.keyChange
&& (releasedKeyNumber == old_releasedKeyNumber))
{
interrupt_status.keyChange = false;
signalInterrupt();
}
update_count = 0;
}
// Update keypressed status:
interrupt_status.keypressed = pressedKeyNumber;
}
/*****************************************************************************/
// I2C Registers that can be read by the Master. Their names should
// be self-explanatory and directly relate to the equivalent variables/functions
// in the RP6Library
#define I2C_REG_STATUS1 0
#define I2C_REG_STATUS2 1
#define I2C_REG_IO_STATUS 2
#define I2C_REG_MEM_CS2 3
#define I2C_REG_SPIBYTE 4
#define I2C_REG_SPIWORD_L 5
#define I2C_REG_SPIWORD_H 6
#define I2C_REG_SPIEEPROMSTATUS 7
#define I2C_REG_SPIEEPROMBYTE 8
#define I2C_REG_SPIEEPROMWORD_L 9
#define I2C_REG_SPIEEPROMWORD_H 10
#define I2C_REG_ADC_4_L 11
#define I2C_REG_ADC_4_H 12
#define I2C_REG_ADC_3_L 13
#define I2C_REG_ADC_3_H 14
#define I2C_REG_ADC_2_L 15
#define I2C_REG_ADC_2_H 16
#define I2C_REG_ADC_6_L 17
#define I2C_REG_ADC_6_H 18
#define I2C_REG_ADC_5_L 19
#define I2C_REG_ADC_5_H 20
#define I2C_REG_ADC_7_L 21
#define I2C_REG_ADC_7_H 22
#define I2C_REG_ADC_MIC_L 23
#define I2C_REG_ADC_MIC_H 24
#define I2C_REG_ADC_KEYPAD_L 25
#define I2C_REG_ADC_KEYPAD_H 26
#define I2C_REG_RELEASEDKEYNUMBER 27
#define I2C_REG_PRESSEDKEYNUMBER 28
#define I2C_REG_LEDS 29
// These variables contain the results of the functions readSPI(),
// readWordSPI(), SPI_EEPROM_readByte[s](), SPI_EEPROM_getStatus() after the
// Master sent one of the commands CMD_READSPI, CMD_READWORDSPI,
// CMD_SPI_EEPROM_READBYTE/WORD, CMD_SPI_EEPROM_GETSTATUS. So these variables
// are updated only "on demand" and NOT permanently!
uint8_t spibyte;
uint16_t spiword;
uint8_t spieepromstatus;
uint8_t spieeprombyte;
uint16_t spieepromword;
/**
* This very important function updates ALL registers that the Master can read.
* It is called frequently out of the Main loop.
*/
void task_updateRegisters(void)
{
if(!I2CTWI_readBusy)
{
I2CTWI_readRegisters[I2C_REG_STATUS1] = (uint8_t)(interrupt_status.byte);
I2CTWI_readRegisters[I2C_REG_STATUS2] = (uint8_t)(status.byte);
I2CTWI_readRegisters[I2C_REG_IO_STATUS] = (uint8_t)(ins.byte);
I2CTWI_readRegisters[I2C_REG_MEM_CS2] = (uint8_t)(status.mem_cs2);
I2CTWI_readRegisters[I2C_REG_SPIBYTE] = (uint8_t)(spibyte);
I2CTWI_readRegisters[I2C_REG_SPIWORD_L] = (uint8_t)(spiword);
I2CTWI_readRegisters[I2C_REG_SPIWORD_H] = (uint8_t)(spiword>>8);
I2CTWI_readRegisters[I2C_REG_SPIEEPROMSTATUS] = (uint8_t)(spieepromstatus);
I2CTWI_readRegisters[I2C_REG_SPIEEPROMBYTE] = (uint8_t)(spieeprombyte);
I2CTWI_readRegisters[I2C_REG_SPIEEPROMWORD_L] = (uint8_t)(spieepromword);
I2CTWI_readRegisters[I2C_REG_SPIEEPROMWORD_H] = (uint8_t)(spieepromword>>8);
I2CTWI_readRegisters[I2C_REG_ADC_4_L] = (uint8_t)(adc4);
I2CTWI_readRegisters[I2C_REG_ADC_4_H] = (uint8_t)(adc4>>8);
I2CTWI_readRegisters[I2C_REG_ADC_3_L] = (uint8_t)(adc3);
I2CTWI_readRegisters[I2C_REG_ADC_3_H] = (uint8_t)(adc3>>8);
I2CTWI_readRegisters[I2C_REG_ADC_2_L] = (uint8_t)(adc2);
I2CTWI_readRegisters[I2C_REG_ADC_2_H] = (uint8_t)(adc2>>8);
I2CTWI_readRegisters[I2C_REG_ADC_6_L] = (uint8_t)(adc6);
I2CTWI_readRegisters[I2C_REG_ADC_6_H] = (uint8_t)(adc6>>8);
I2CTWI_readRegisters[I2C_REG_ADC_5_L] = (uint8_t)(adc5);
I2CTWI_readRegisters[I2C_REG_ADC_5_H] = (uint8_t)(adc5>>8);
I2CTWI_readRegisters[I2C_REG_ADC_7_L] = (uint8_t)(adc7);
I2CTWI_readRegisters[I2C_REG_ADC_7_H] = (uint8_t)(adc7>>8);
I2CTWI_readRegisters[I2C_REG_ADC_MIC_L] = (uint8_t)(adcMic);
I2CTWI_readRegisters[I2C_REG_ADC_MIC_H] = (uint8_t)(adcMic>>8);
I2CTWI_readRegisters[I2C_REG_ADC_KEYPAD_L] = (uint8_t)(adcKeypad);
I2CTWI_readRegisters[I2C_REG_ADC_KEYPAD_H] = (uint8_t)(adcKeypad>>8);
I2CTWI_readRegisters[I2C_REG_RELEASEDKEYNUMBER] = (uint8_t)(releasedKeyNumber);
I2CTWI_readRegisters[I2C_REG_PRESSEDKEYNUMBER] = (uint8_t)(pressedKeyNumber);
I2CTWI_readRegisters[I2C_REG_LEDS] = (uint8_t)(externalPort.LEDS);
if(I2CTWI_dataWasRead && I2CTWI_dataReadFromReg == 0)
clearInterrupt();
}
}
/*****************************************************************************/
// Command Registers - these can be written by the Master.
// The other registers (read registers) can NOT be written to. The only way to
// communicate with the M32 is via specific commands.
// Of course you can also add more registers if you like...
// ----------------------
#define I2C_REGW_CMD 0
#define I2C_REGW_CMD_PARAM1 1
#define I2C_REGW_CMD_PARAM2 2
#define I2C_REGW_CMD_PARAM3 3
#define I2C_REGW_CMD_PARAM4 4
#define I2C_REGW_CMD_PARAM5 5
#define I2C_REGW_CMD_PARAM6 6
// ----------------------
uint8_t cmd;
uint8_t param1;
uint8_t param2;
uint8_t param3;
uint8_t param4;
uint8_t param5;
uint8_t param6;
/**
* Checks if a new Command has been received and also reads all
* paramters associated with this command.
* It returns true if a new command has been received.
*/
uint8_t getCommand(void)
{
if(I2CTWI_writeRegisters[I2C_REGW_CMD] && !I2CTWI_writeBusy)
{
cmd = I2CTWI_writeRegisters[I2C_REGW_CMD]; // store command register
I2CTWI_writeRegisters[I2C_REGW_CMD] = 0; // clear command register (!!!)
param1 = I2CTWI_writeRegisters[I2C_REGW_CMD_PARAM1]; // parameters 1-6...
param2 = I2CTWI_writeRegisters[I2C_REGW_CMD_PARAM2];
param3 = I2CTWI_writeRegisters[I2C_REGW_CMD_PARAM3];
param4 = I2CTWI_writeRegisters[I2C_REGW_CMD_PARAM4];
param5 = I2CTWI_writeRegisters[I2C_REGW_CMD_PARAM5];
param6 = I2CTWI_writeRegisters[I2C_REGW_CMD_PARAM6];
return true;
}
return false;
}
/*****************************************************************************/
// Command processor:
// Commands:
#define CMD_CONFIGIOS 0
#define CMD_SETIOS 1
#define CMD_CONFIG 2
#define CMD_SETLEDS 3
#define CMD_DISCHARGEPEAKDETECTOR 4
#define CMD_GETMICROPHONEPEAK 5
#define CMD_SETMEM_CS2 6
#define CMD_WRITESPI 7
#define CMD_WRITEWORDSPI 8
#define CMD_READSPI 9
#define CMD_READWORDSPI 10
#define CMD_SET_WDT 11
#define CMD_SET_WDT_RQ 12
#define CMD_SET_HEARTBEAT 13
#define CMD_SPI_EEPROM_WRITEBYTE 14
#define CMD_SPI_EEPROM_WRITEWORD 15
#define CMD_SPI_EEPROM_ENABLEWRITE 16
#define CMD_SPI_EEPROM_DISABLEWRITE 17
#define CMD_SPI_EEPROM_READBYTE 18
#define CMD_SPI_EEPROM_READWORD 19
#define CMD_SPI_EEPROM_GETSTATUS 20
#define CMD_INITLCD 21
#define CMD_CLEARLCD 22
#define CMD_CLEARPOSLCD 23
#define CMD_WRITECHARLCD 24
#define CMD_WRITEINTEGERLCD 25
#define CMD_SETCURSORPOSLCD 26
#define CMD_BEEP 27
#define CMD_SETBEEPERPITCH 28
#define CMD_SOUND 29
uint8_t rw_buffer[3];
/**
* This function checks if commands have been received and processes them.
*/
void task_commandProcessor(void)
{
if(getCommand())
{
switch(cmd)
{
case CMD_CONFIGIOS: if(param1) setFreeIOsToOUT(); else setFreeIOsToIN(); break;
case CMD_SETIOS: setOUTs(param1); break;
case CMD_CONFIG: break;
case CMD_SETLEDS: setLEDs(param1); break;
case CMD_DISCHARGEPEAKDETECTOR: dischargePeakDetector(); break;
case CMD_GETMICROPHONEPEAK: adcMic = getMicrophonePeak(); break;
case CMD_SETMEM_CS2: if(param1) PORTB |= MEM_CS2; else PORTB &= ~MEM_CS2; break;
case CMD_WRITESPI: writeSPI(param1); break;
case CMD_WRITEWORDSPI: writeWordSPI((param1<<8)+param2); break;
case CMD_READSPI: spibyte = readSPI(); break;
case CMD_READWORDSPI: spiword = readWordSPI(); break;
case CMD_SET_WDT: status.watchDogTimer = param1 ? true : false; break;
case CMD_SET_WDT_RQ: status.wdtRequestEnable = param1 ? true : false; break;
case CMD_SET_HEARTBEAT: status.heartbeat = param1 ? true : false; break;
case CMD_SPI_EEPROM_WRITEBYTE: SPI_EEPROM_writeByte((param1<<8)+param2, param3); break;
case CMD_SPI_EEPROM_WRITEWORD: rw_buffer[0] = param3; rw_buffer[1] = param4;
SPI_EEPROM_writeBytes((param1<<8)+param2, &rw_buffer[0], 2); break;
case CMD_SPI_EEPROM_ENABLEWRITE: SPI_EEPROM_enableWrite(); break;
case CMD_SPI_EEPROM_DISABLEWRITE: SPI_EEPROM_disableWrite(); break;
case CMD_SPI_EEPROM_READBYTE: spieeprombyte = SPI_EEPROM_readByte((param1<<8)+param2); break;
case CMD_SPI_EEPROM_READWORD: SPI_EEPROM_readBytes((param1<<8)+param2, &rw_buffer[0], 2);
spieepromword = (rw_buffer[0]<<8)+rw_buffer[1]; break;
case CMD_SPI_EEPROM_GETSTATUS: spieepromstatus = SPI_EEPROM_getStatus(); break;
case CMD_INITLCD: initLCD(); break;
case CMD_CLEARLCD: clearLCD(); break;
case CMD_CLEARPOSLCD: clearPosLCD(param1, param2, param3); break;
case CMD_WRITECHARLCD: writeCharLCD(param1); break;
case CMD_WRITEINTEGERLCD: writeIntegerLCD((param1<<8)+param2, param3); break;
case CMD_SETCURSORPOSLCD: setCursorPosLCD(param1, param2); break;
case CMD_BEEP: beep(param1, (param2<<8)+param3); break;
case CMD_SETBEEPERPITCH: setBeeperPitch(param1); break;
case CMD_SOUND: sound(param1, (param2<<8)+param3, (param4<<8)+param5); break;
}
}
}
/**
* This is the Software watchdog function. After any interrupt event, a timer is
* started and if a certain amount of time has passed by with no reaction from
* the Master, the RP6 CONTROL M32 shows this by blinking with status LEDs 1..4
* for 3 seconds. After this the interrupt and interrupt status are cleared.
* Usually the Master program has errors or is locked up if it does not react,
* so the blinking LEDs show, that there is a communication problem.
*/
void task_MasterTimeout(void)
{
if(status.watchDogTimer)
{
static uint8_t blinkflag = 0;
if(getStopwatch2() > 3000) // 3 seconds timeout for the master to react on
{ // our interrupt events - if he does not react, we
// blink with LEDs 1..4 for another 3 seconds!
interrupt_status.timeout = true;
if(getStopwatch2() > 6000)
{
setLEDs(0b0000); // Clear LEDs
interrupt_status.byte = 0; // Clear interrupt status
setStopwatch4(0);
clearInterrupt(); // Clear interrupt
}
}
else if(getStopwatch3() > 250)
{
status.wdtRequest = true;
signalInterrupt();
setStopwatch3(0);
}
if(interrupt_status.timeout)
{
if(getStopwatch5() > 200)
{
if(blinkflag)
{
setLEDs(0b1001);
blinkflag = 0;
}
else
{
setLEDs(0b0110);
blinkflag = 1;
}
setStopwatch5(0);
}
}
}
}
/**
* LCD Heartbeat function
*/
void task_LCDHeartbeat(void)
{
if(status.heartbeat)
{
if(getStopwatch1() > 500)
{
static uint8_t heartbeat = false;
if(heartbeat)
{
clearPosLCD(1, 15, 1);
heartbeat = false;
}
else
{
setCursorPosLCD(1, 15);
writeStringLCD_P("*");
heartbeat = true;
}
setStopwatch1(0);
}
}
}
/*****************************************************************************/
// Main - The program starts here:
int16_t main(void)
{
initRP6Control();
setLEDs(0b1111);
mSleep(500);
setLEDs(0b0000);
I2CTWI_initSlave(RP6Control_I2C_SLAVE_ADR);
status.byte = 0;
interrupt_status.byte = 0;
// TEST TEST TEST TEST TEST TEST
status.watchDogTimer = true;
status.heartbeat = true;
// TEST TEST TEST TEST TEST TEST
startStopwatch1(); // For LCDHeartbeat function
startStopwatch3();
startStopwatch4();
startStopwatch5();
while(true)
{
task_commandProcessor();
task_update();
task_updateRegisters();
task_RP6M32System();
task_MasterTimeout();
task_LCDHeartbeat();
}
return 0;
}
I2C-Master (RP6v2 M256 WiFi)
Siehe auch
Weblinks
Autoren
--Dirk 19:20, 12. Sep 2012 (CET)