package com.jopdesign.io; import javax.realtime.RawInt; import javax.safetycritical.annotate.Level; import javax.safetycritical.annotate.SCJAllowed; import javax.safetycritical.annotate.SCJRestricted; import csp.Buffer; import csp.Constants; public class I2Cport extends HardwareObject implements RawInt{ // TX/RX buffer size in bytes. This size is the size of the FIFO's in // the hardware controller. To modify it you should modify the VHDL files. public static final int BUFFER_SIZE = 32; // Status constants public static final int TBUF_ERR = 0x00000040; public static final int RBUF_ERR = 0x00000020; public static final int ACK_ERR = 0x00000010; public static final int HDR_ERR = 0x00000008; public static final int BUS_BUSY = 0x00000004; public static final int STOP_STAT = 0x00000002; public static final int DATA_RDY = 0x00000001; public static final int OCCU_RD = 0xFFFF0000; public static final int OCCU_WR = 0x0000FFFF; // Control constants public static final int TX_FLUSH = 0x00000080; public static final int RX_FLUSH = 0x00000040; public static final int ACK = 0x00000020; public static final int STRT = 0x00000010; public static final int STOP = 0x00000008; public static final int MASL = 0x00000004; public static final int RSTA = 0x00000002; public static final int ENABLE = 0x00000001; public static final int CLEAR_STRT = 0xFFFFFFEF; // Configuration constants public static final int MASTER = ENABLE | MASL; public static final int SLAVE = ENABLE; public static final int NOT_FLUSH = 0xFFFFFF7F; // Count base for SCL timings, adjust according to // uP clock frequency public static final int CNT_BASE = 28; // These constants define the timings of the SCL signal public static final int T_HOLD_START = 5 * CNT_BASE - 1; public static final int T_RSTART = 5 * CNT_BASE - 1; public static final int T_LOW = 5 * CNT_BASE - 1; public static final int T_HIGH = 5 * CNT_BASE - 1; public static final int T_HALF_HIGH = 2 * CNT_BASE - 1; public static final int T_SUSTO = 4 * CNT_BASE - 1; public static final int T_WAIT = 8 * CNT_BASE; // Control register public volatile int control; // Status register public volatile int status; // Host slave address public volatile int devadd; // Size of the message (in bytes) to be transmitted public volatile int msg_size; // Data to send public volatile int tx_fifo_data; // Data to receive public volatile int rx_fifo_data; // Timing high public volatile int th; // Timing low public volatile int tl; // Tx buffer occupancy public volatile int tx_occu; // Rx buffer occupancy public volatile int rx_occu; /** * Load the initial configuration to the I2C device. * * @param devAdd * @param isMaster */ final public void initialize(int devAdd, boolean isMaster){ devadd = devAdd; if(isMaster){ control = MASTER; }else{ control = SLAVE; } int temp = (T_HOLD_START << 24) + (T_RSTART << 16) + (T_LOW << 8) + (T_HIGH); th = temp; temp = (T_HALF_HIGH << 24) + (T_SUSTO << 16) + (T_WAIT << 8) + (0); tl = temp; } /** * Set device in slave mode without changing the device address */ public void slaveMode(){ control = SLAVE; } /** * Display the contents of the control, status and address registers */ final public void dumpRegisters(){ System.out.println("[control]: "+control); System.out.println("[status]: "+status); System.out.println("[address]: "+devadd); } /** * Clear the transmit buffer */ public void flushTXBuff(){ int controlOld = control; control = control | TX_FLUSH; control = controlOld; } /** * Clear the receive buffer */ public void flushRXBuff(){ int controlOld = control; control = control | RX_FLUSH; control = controlOld; } /** * Write the elements of the data array into the transmit buffer * * @param data */ public void writeBuffer(int[] data) { // Check that there is still space available in buffer int occu = (tx_occu & OCCU_WR); int space = BUFFER_SIZE - occu ; if((data.length <= space) & (data.length < BUFFER_SIZE)){ for (int i=0; i< data.length; i++){ tx_fifo_data = data[i]; } }else{ System.out.println("Not enough space in buffer"); } } /** * Read ALL the bytes in the transmit buffer. Data is stored in the data * array. If buffer is empty, the array is filled with zeros. * * @param data */ public void readBuffer(int[] data) { // Read all data in buffer int occu = (rx_occu & OCCU_RD ) >>> 16; for (int i=0; i < occu; i++){ data[i] = rx_fifo_data; } } /** * Write "size" bytes to the slave identified with by the address in the first * byte of the transmit buffer.This method is particularly useful if you have * previously written data to the transmit buffer. It assumes that the first seven * bits of the byte to whom the transmit buffer points is the slave address. The LSB * of this same byte must be zero. This is a non-blocking operation. Once the * transmission is started the hardware will take care of finishing it and * clearing the BUS_BUSY flag in the status register. * * @param size * How many bytes will be written to the slave. */ public void write(int size){ // Clear STRT bit in case there was a previous transaction control = control & CLEAR_STRT; if((status & BUS_BUSY) == 0){ // Set I2C to master control = MASTER; if(size > 1){ msg_size = size + 1; }else{ msg_size = 1; } // Initiate transmission, set STRT bit = 1 control = control | STRT; }else{ System.out.println("Can't start transmission, bus busy"); } } /** * Write one byte to the slave identified with slAddress address. This is * a non-blocking operation. Once the transmission is started the hardware * will take care of finishing it and clearing the BUS_BUSY flag in the * status register. * * @param slAddress * Address of the slave target. * @param data * Byte to be written. * */ public void write(int slAddress, int data){ // Clear STRT bit in case there was a previous transaction control = control & CLEAR_STRT; if((status & BUS_BUSY) == 0){ // To write, the LSB of the address is set to zero // and the first position of buffer is used to store the // address of the slave we wish to communicate with. tx_fifo_data = slAddress*2; // Write data to tx buffer tx_fifo_data = data; } // Set I2C to master control = MASTER; msg_size = 1; // Initiate transmission, set STRT bit = 1 control = control | STRT; } /** * Write "N" bytes to the slave identified with slAddress address. "N" is * the size of the "data" array. This is a non-blocking operation. Once the * transmission is started the hardware will take care of finishing it and * clearing the BUS_BUSY flag in the status register. * * @param slAddress * Address of the slave target. * @param data * Array of data to be written. * */ public void write(int slAddress, int[] data){ // Clear STRT bit in case there was a previous transaction control = control & CLEAR_STRT; if((status & BUS_BUSY) == 0){ // To write, the LSB of the address is set to zero // and the first position of buffer is used to store the // address of the slave we wish to communicate with. tx_fifo_data = slAddress*2; // Write data to tx buffer if(data.length > BUFFER_SIZE-1){ System.out.println("Data bigger than buffer size"); }else{ for(int i = 0; i<data.length; i++){ tx_fifo_data = data[i]; } } // Set I2C to master control = MASTER; msg_size = data.length + 1; // Initiate transmission, set STRT bit = 1 control = control | STRT; }else{ System.out.println("Can't start transmission, bus busy"); } } /** * This is a very common function in I2C devices, where the master writes * one byte of data to a slave, usually to set a base address to read from, * and then it performs a read operation. This is a non-blocking operation. * The method will return after the read operation is initiated. The * hardware will take care of finishing, clearing the BUS_BUSY flag, and * setting the DATA_RDY flag in the status register. * * @param slAddress * Address of the slave target. * @param data * Base address of slave. * * @param readSize Size in bytes of the * read transaction. * */ public void writeRead(int slAddress, int data, int readSize){ // Clear STRT bit in case there was a previous transaction control = control & CLEAR_STRT; if((status & BUS_BUSY) == 0){ // To write, the LSB of the address is set to zero // and the first position of buffer is used to store the // address of the slave we wish to communicate with. tx_fifo_data = slAddress*2; tx_fifo_data = data; tx_fifo_data = slAddress*2 + 1; // Set I2C to master and initiate transmission control = MASTER | STRT; // It is safe to set the repeated start bit here since we wish // to transmit only one byte. Setting the repeated start bit // takes effect in the next WAIT_ACK or SEND_ACK state control = control | RSTA; // Message size is reduced by one since byte 0 counts as first // received byte msg_size = readSize - 1; // Now we need to wait until the controller leaves the first // ACK_HEADER state to set the master rx mode }else{ System.out.println("Can't start transmission, bus busy"); } } /** * Read "N" bytes from the slave identified with slAddress address. "N" is * specified before starting the read operation. This is a non-blocking * operation, once it is started, the hardware will take care of finishing * it, clearing the BUS_BUSY flag and setting the DATA_RDY flag in the * status register. Data in the receive buffer has to be moved explicitly to * e.g. an array for its later use. * * @param slAddress * Target slave address. * @param readSize * Size in bytes of the read transaction. */ public void read(int slAddress, int readSize){ // Clear STRT bit in case there was a previous transaction control = control & CLEAR_STRT; // A read operation starts by transmitting the slave address. // Add 1 to indicate a read transaction. tx_fifo_data = slAddress*2 + 1; control = MASTER; msg_size = readSize - 1; control = control | STRT; } int getRegister(int address){ switch (address) { case 0: return control; case 1: return status; default: return 0; } } @Override @SCJAllowed(Level.LEVEL_0) @SCJRestricted(mayAllocate = false, maySelfSuspend = false) public int get() { return 0; } @Override @SCJAllowed(Level.LEVEL_0) @SCJRestricted(mayAllocate = false, maySelfSuspend = false) public void put(int value) { // TODO Auto-generated method stub } // // Multi-byte write // //public void write(int slAddress, int[] data){ // public void write(int[] data){ // // int j = BUFFER_SIZE - 1; // // // To write, the LSB of the address is set to zero // // and the first position of buffer is used to store the // // address of the slave we wish to communicate with. // //tx_fifo_data = slAddress*2; // tx_fifo_data = data[0]; // // // Fill tx buffer // if (data.length <= BUFFER_SIZE - 1){ // for (int i = 1; i < data.length; ++i){ // tx_fifo_data = data[i]; // }; // // Set I2C to master transmitter and set STRT bit // control = 0x00000003; // while ((status & BUS_BUSY) == 0){ // ; // } // // Reset STRT bit to avoid starting a new transfer after // // finishing the current one. // control = 0x00000001; // // }else{ // for (int i = 1; i < BUFFER_SIZE ; ++i){ // tx_fifo_data = data[i]; // }; // control = 0x00000003; // while ((status & BUS_BUSY) == 0){ // ; // } // control = 0x00000001; // // while( j < data.length ){ // while((status & TX_FIFO_FULL) == 0){ // tx_fifo_data = data[j]; // j = j + 1; // } // } // // } // } // // public void CSPwrite(int slave, CSPbuffer buffer){ // // tx_fifo_data = slave; // //// for(int i = 0; i < buffer.length.length; i++){ //// tx_fifo_data = buffer.length[i]; //// } // // if (Conf.CSP_USE_CRC32) { // debug_msg("Writing CRC to buffer..."); // for (int i = 0; i < buffer.crc32.length; i++) { // tx_fifo_data = buffer.crc32[i]; // } // } // // System.out.println("Writing header to buffer..."); // for(int i = 0; i < buffer.header.length; i++){ // tx_fifo_data = buffer.header[i]; // } // // if (buffer.data != null) { // debug_msg("Writing data to buffer..."); // for (int i = 0; i < buffer.data.length; i++) { // tx_fifo_data = buffer.data[i]; // } // } // // // Set I2C to master transmitter and set STRT bit // control = 0x00000003; // // while ((status & BUS_BUSY) == 0){ // ; // } // // // Reset STRT bit to avoid starting a new transfer after // // finishing the current one. // control = 0x00000001; // // //TODO: Check transmission was successful to free buffer. // // } // // // private void debug_msg(String string) { // // TODO Auto-generated method stub // System.out.println(string); // } // // // public void slaveMode(){ // control = control | FLUSH_FIFO; // control = control & NOT_FLUSH_FIFO; // control = SLAVE; // } // // public void masterTX(){ // control = control | FLUSH_FIFO; // control = control & NOT_FLUSH_FIFO; // control = MASTER_TX; // } // // public void masterRX(){ // control = MASTER_RX; // } // // // public void CSPreadBuffer(CSPbuffer buffer) { // //// for (int i=0; i < buffer.length.length; i++){ //// buffer.length[i] = rx_fifo_data; //// } // // // If CRC is enabled, it uses the first 4 bytes // // of the received packet // if (Conf.CSP_USE_CRC32) { // for (int i=0; i < buffer.crc32.length; i++){ // buffer.crc32[i] = rx_fifo_data; // } // } // // // Header is always 4 bytes // for (int i=0; i < buffer.header.length; i++){ // buffer.header[i] = rx_fifo_data; // } // //// for (int i=0; i < buffer.data.length; i++){ // // // The remaining in the buffer is the payload ////// int data = RX_FIFO_OCCUPANCY_IN; //// if (data != 0){ //// for (int i=0; i < data; i++){ //// buffer.data[i] = rx_fifo_data; //// } //// } // // //return data; // // } }