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.
Bitte testet diese Version! Was sollte noch geändert/verbessert werden? Fehler?
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(); clearLCD(); setLEDs(0b1111); mSleep(500); setLEDs(0b0000); I2CTWI_initSlave(RP6Control_I2C_SLAVE_ADR); status.byte = 0; interrupt_status.byte = 0; 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)
Vorbereitung
Um für die Funktionsnamen der Sound- und EEPROM-Befehle keine Probleme zu bekommen, müssen wir die aktuelle RP6M256Lib.h (Version 1.1 - 16.07.2012) anpassen.
Die folgenden Zeilen müssen auskommentiert werden:
... uint8_t SPI_EEPROM_readByte(uint16_t memAddr); void SPI_EEPROM_writeByte(uint16_t memAddr, uint8_t data); void SPI_EEPROM_enableWrite(void); void SPI_EEPROM_disableWrite(void); uint8_t SPI_EEPROM_getStatus(void); void SPI_EEPROM_writeBytes(uint16_t startAddr, uint8_t *buffer, uint8_t length); void SPI_EEPROM_readBytes(uint16_t startAddr, uint8_t *buffer, uint8_t length); ... void beep(unsigned char pitch, unsigned int time); void setBeeperPitch(uint8_t pitch); #define sound(_pitch_,_time_,_delay_) {beep(_pitch_,_time_);mSleep(_delay_ + _time_);} ...
Keine Sorge! Dadurch verändert sich in der RP6M256Lib nichts, weil es alle diese Funktionen nicht gibt (es gibt ja auch kein SPI-EEPROM und keinen Beeper auf der M256 WiFi)!
Demo
Diese erste Demo zeigt nur ein Lauflicht auf der M32,- über I2C von der M256 WiFi gesteuert.
Datei RP6M256_M32_I2CMaster.c:
/* * **************************************************************************** * RP6 ROBOT SYSTEM - RP6 CONTROL M256 Examples * **************************************************************************** * Example: M32 I2C Master * Author(s): Dirk * **************************************************************************** * Description: * In this example we show how to react on interrupt requests from the * Microcontroller on the RP6 CONTROL M32. It sets the signal INT2 (that's what * it is called on the RP6 hardware...) which is connected to the external * interrupt PCINT 15 of the Microcontroller. We will NOT use the interrupt * routine to react on the interrupts. Instead we simply poll the interrupt * pin and check if there is an request. This works better together with * the I2C Bus Master routines of the RP6Library. They are also interrupt * based and thus we can not directly start a new transmission out of the * interrupt service routine of a Pin Change Interrupt. * It would not make any difference in this case, but we could get new * problems when there is a I2C Bus transfer in progress when we get * an interrupt event. Then it could get cancelled and replaced by the * new request, which would cause problems sometimes. * * When an Interrupt Event occurs on the Slave Controller, the program * initiates an I2C-Bus request for the first 3 Status Registers. * In the Status registers some bits change depending on what has caused * the interrupt Event (e.g. a key on the RP6 CONTROL M32 has been pressed * or released...) so we can determine what happened and can react on it * accordingly. * * ############################################################################ * 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! * You should also connect to it via WIFI. * ############################################################################ * **************************************************************************** */ /*****************************************************************************/ // Includes: #include "RP6M256Lib.h" // The RP6 M256 Library. // Always needs to be included! #include "RP6I2CmasterTWI.h" // Include the I2C-Bus Master Library /*****************************************************************************/ /*****************************************************************************/ // Include our new "RP6M256 M32 I2C Master library": #include "RP6M256_M32_I2CMasterLib.h" /*****************************************************************************/ /** * Here we do a small M32 LED test * (a running light with direction changing)! * For timing we use Stopwatch #2. */ void task_runningLight(void) { static uint8_t runLight = 1; static uint8_t dir; // Moving direction for running light if(getStopwatch2() > 100) // 100ms { // Set status LEDs to the value of the variable runLight: setM32LEDs(runLight); // Shift the LED bit left or right depending on direction: if(dir == 0) runLight <<= 1; else runLight >>= 1; // Change the direction if we reached one of the two outer LEDs: if(runLight > 7 ) dir = 1; else if (runLight < 2 ) dir = 0; // Reset Stopwatch2: setStopwatch2(0); } } /*****************************************************************************/ // I2C Requests: /** * The I2C_requestedDataReady Event Handler */ void I2C_requestedDataReady(uint8_t dataRequestID) { checkM32Status(dataRequestID); } /*****************************************************************************/ // I2C Error handler /** * This function gets called automatically if there was an I2C Error like * the slave sent a "not acknowledge" (NACK, error codes e.g. 0x20 or 0x30). * The most common mistakes are: */ void I2C_transmissionError(uint8_t errorState) { writeString_P_WIFI("\nI2C ERROR - TWI STATE: 0x"); writeInteger_WIFI(errorState, HEX); writeChar_WIFI('\n'); } /*****************************************************************************/ // Main function - The program starts here: int main(void) { initRP6M256(); // Always call this first! The Processor will not work // correctly otherwise. initLCD(); // Initialize the LC-Display (LCD) // Always call this before using the LCD! setLEDs(0b1111); mSleep(500); setLEDs(0b0000); writeString_P_WIFI("\n\nRP6 CONTROL M32 I2C Master Example Program!\n"); // IMPORTANT: I2CTWI_initMaster(100); // Initialize the TWI Module for Master operation // with 100kHz SCL Frequency // Also very important in this example: // Register the event handlers: I2CTWI_setTransmissionErrorHandler(I2C_transmissionError); I2CTWI_setRequestedDataReadyHandler(I2C_requestedDataReady); setLEDs(0b1111); // Write a text message to the LCD: showScreenLCD("################", "################"); mSleep(1500); showScreenLCD("RP6v2-M256-WIFI ", "<<LC - DISPLAY>>"); mSleep(2500); showScreenLCD(" M32 I2C Master", "Example Program"); mSleep(2500); clearLCD(); setLEDs(0b0000); // --------------------------------------- // Enable LCD Heartbeat function on Slave: I2CTWI_transmit3Bytes(I2C_RP6_M32_ADR, 0, CMD_SET_HEARTBEAT, true); // (The LCD Heartbeat function lets a '*' character blink with 1Hz on // the LC-Display of the Slave if the Slave functions properly.) // Enable Software Watchdog timer on Slave: I2CTWI_transmit3Bytes(I2C_RP6_M32_ADR, 0, CMD_SET_WDT, true); // (This timer shows blinking LEDs on the Slave if the Master Controller // does not react on interrupt requests after a few seconds. This can // help to find communication problems ...) // --------------------------------------- startStopwatch1(); // For LCDHeartbeat function startStopwatch2(); // For runningLight function while(true) { // You need to call task_I2CTWI frequently out of the // main loop - otherwise the I2C Bus request functions don't work. task_checkPCINT15(); task_I2CTWI(); task_LCDHeartbeat(); task_runningLight(); } return 0; }
M32 I2C Master Library
Hier soll mal die Master Library stehen, die die Befehle enthält, um die M32 über I2C (fast) auf dieselbe Weise zu steuern, wie das direkt der Fall wäre.
Header
Datei RP6M256_M32_I2CMasterLib.h:
/* * **************************************************************************** * RP6 ROBOT SYSTEM - RP6 CONTROL M256 Examples * **************************************************************************** * Example: M32 I2C Master Library * Author(s): Dirk * **************************************************************************** * Description: * Header file for new library. * * **************************************************************************** */ #ifndef RP6M256_M32_I2CMASTERLIB_H #define RP6M256_M32_I2CMASTERLIB_H /*****************************************************************************/ // Includes: #include "RP6M256Lib.h" #include "RP6I2CmasterTWI.h" // Define the RP6 CONTROL M32 address here: #define I2C_RP6_M32_ADR 12 /*****************************************************************************/ // These are the same register/command definitions as you can find them in // the I2C Bus Slave Example program for RP6 CONTROL M32: #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 #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 /*****************************************************************************/ // The Status Struct - here we write the data of the main status register. // It is the same definition as it can be found in the RP6Control_I2CSlave // program! 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 slave 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; // These variables contain the results of the M32 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. These variables // can be found identically in the RP6Control_I2CSlave program! uint8_t spibyte; uint16_t spiword; uint8_t spieepromstatus; uint8_t spieeprombyte; uint16_t spieepromword; /*****************************************************************************/ // M32 slave variables and typedefs // Free M32 IO portpins: typedef union { uint8_t byte; struct { unsigned pd5:1; // IO_PD5 unsigned pd6:1; // IO_PD6 unsigned pc2:1; // IO_PC2 unsigned pc3:1; // IO_PC3 unsigned pc4:1; // IO_PC4 unsigned pc5:1; // IO_PC5 unsigned pc6:1; // IO_PC6 unsigned pc7:1; // IO_PC7 }; } freeIOs_t; extern freeIOs_t ins; extern freeIOs_t outs; // Free M32 ADCs: extern uint16_t adc7; extern uint16_t adc6; extern uint16_t adc5; extern uint16_t adc4; extern uint16_t adc3; extern uint16_t adc2; extern uint16_t adcKeypad; extern uint16_t adcMic; // Key pressed/released number: extern uint8_t releasedKeyNumber; extern uint8_t pressedKeyNumber; // M32 status LEDs: typedef union { uint8_t byte; struct { uint8_t LEDS:4; uint8_t LCDD:4; }; struct { uint8_t LED4:1; uint8_t LED3:1; uint8_t LED2:1; uint8_t LED1:1; uint8_t D0:1; uint8_t D1:1; uint8_t D2:1; uint8_t D3:1; }; } externalPort_t; extern externalPort_t externalPort; // M32 PORTA A/D Convertor channels: #define ADC_7 7 #define ADC_6 6 #define ADC_5 5 #define ADC_4 4 #define ADC_3 3 #define ADC_2 2 #define ADC_KEYPAD 1 #define ADC_MIC 0 #define PCINT15_STATUS_CHECK 0 /*****************************************************************************/ // Master functions void task_LCDHeartbeat(void); void getAllSensors(void); void task_checkPCINT15(void); uint8_t checkM32Status(uint8_t dataRequestID); void I2C_transmissionError(uint8_t errorState); void WDT_setRequestHandler(void (*requestHandler)(void)); void waitForTransmitComplete(void); /*****************************************************************************/ // M32 Slave functions uint16_t readM32ADC(uint8_t channel); void setFreeIOsToIN(void); void setFreeIOsToOUT(void); void updateOUTs(void); void setOUTs(uint8_t out); void writeM32SPI(uint8_t data); uint8_t readM32SPI(void); uint16_t readWordM32SPI(void); void writeWordM32SPI(uint16_t data); void writeBufferM32SPI(uint8_t *buffer, uint8_t length); void readBufferM32SPI(uint8_t *buffer, uint8_t length); uint8_t SPI_EEPROM_readByte(uint16_t memAddr); void SPI_EEPROM_writeByte(uint16_t memAddr, uint8_t data); void SPI_EEPROM_enableWrite(void); void SPI_EEPROM_disableWrite(void); uint8_t SPI_EEPROM_getStatus(void); void SPI_EEPROM_writeBytes(uint16_t startAddr, uint8_t *buffer, uint8_t length); void SPI_EEPROM_readBytes(uint16_t startAddr, uint8_t *buffer, uint8_t length); void outputExt(void); void setM32LEDs(uint8_t leds); void initM32LCD(void); void clearM32LCD(void); void clearPosM32LCD(uint8_t line, uint8_t pos, uint8_t length); void writeCharM32LCD(uint8_t ch); //void writeStringM32LCD(char *string); //void writeStringLengthM32LCD(char *string, uint8_t length, uint8_t offset); //void showScreenM32LCD(const char *line1, const char *line2); void writeIntegerM32LCD(int16_t number, uint8_t base); //void writeIntegerLengthM32LCD(int16_t number, uint8_t base, uint8_t length); void setCursorPosM32LCD(uint8_t line, uint8_t pos); uint8_t getM32PressedKeyNumber(void); void dischargePeakDetector(void); uint16_t getMicrophonePeak(void); void beep(unsigned char pitch, unsigned int time); void setBeeperPitch(uint8_t pitch); void sound(uint8_t pitch, unsigned int time, uint16_t delay); /*****************************************************************************/ #endif
Library
Datei RP6M256_M32_I2CMasterLib.c:
Siehe auch
Weblinks
Autoren
--Dirk 19:03, 14. Sep 2012 (CET)