Aus RN-Wissen.de
Wechseln zu: Navigation, Suche
Balkonkraftwerk Speicher und Wechselrichter Tests und Tutorials

K (Planung)
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

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)


LiFePO4 Speicher Test