示例#1
0
文件: i2c_api.c 项目: pan-/mbed
//New version WH, Tested OK for Start and Repeated Start
//Old version was Wrong: Calls i2c_start without setting address, i2c_do_read continues before checking status, status check for wrong value
int i2c_read(i2c_t *obj, int address, char *data, int length, int stop) {
    int count, status;
    
    //Store the address+RD and then generate STA
    I2C_DAT(obj) = address | 0x01;
    i2c_start(obj);    

    // Wait for completion of STA and Sending of SlaveAddress+RD and first Read byte
    i2c_wait_SI(obj);
    status = i2c_status(obj);    
    if (status == 0x03) { // NAK on SlaveAddress
        i2c_stop(obj);
        return I2C_ERROR_NO_SLAVE;
    }

    // Read in all except last byte
    for (count = 0; count < (length-1); count++) {
        
      // Wait for it to arrive, note that first byte read after address+RD is already waiting
      i2c_wait_SI(obj);
      status = i2c_status(obj);
      if (status != 0x01) { // RX RDY
        i2c_stop(obj);
        return count;
      }
      data[count] = I2C_DAT(obj) & 0xFF; // Store read byte

      obj->i2c->MSTCTL = (1 << 0); // Send ACK and Continue to read
    }
    
    // Read final byte
    // Wait for it to arrive
    i2c_wait_SI(obj);

    status = i2c_status(obj);
    if (status != 0x01) { // RX RDY
      i2c_stop(obj);
      return count;
    }
    data[count] = I2C_DAT(obj) & 0xFF; // Store final read byte

    // If not repeated start, send stop.
    if (stop) {
        i2c_stop(obj); // Also sends NAK for last read byte
    } else {
        repeated_start = 1;
    }
   
    return length;
}
示例#2
0
文件: i2c_api.c 项目: pan-/mbed
//New version WH, Tested OK for Start and Repeated Start
//Old version was Wrong: Calls i2c_start without setting address first
int i2c_write(i2c_t *obj, int address, const char *data, int length, int stop) {
    int i, status;

    //Store the address+/WR and then generate STA
    I2C_DAT(obj) = address & 0xFE;   
    i2c_start(obj);
    
    // Wait for completion of STA and Sending of SlaveAddress+/WR
    i2c_wait_SI(obj);
    status = i2c_status(obj);    
    if (status == 0x03) { // NAK SlaveAddress
        i2c_stop(obj);
        return I2C_ERROR_NO_SLAVE;
    }
    
    //Write all bytes
    for (i=0; i<length; i++) {
        status = i2c_do_write(obj, data[i], 0);
        if (status != 0x02) { // TX RDY. Handles a Slave NAK on datawrite
            i2c_stop(obj);
            return i;
        }
    }
    
    // If not repeated start, send stop.
    if (stop) {
        i2c_stop(obj);
    } else {
        repeated_start = 1;
    }
    
    return length;
}
示例#3
0
文件: i2c_api.c 项目: pan-/mbed
int i2c_slave_read(i2c_t *obj, char *data, int length) {
    int count = 0;
    int status;
    
    do {
        i2c_clear_SI(obj);
        i2c_wait_SI(obj);
        status = i2c_status(obj);
        if((status == 0x80) || (status == 0x90)) {
            data[count] = I2C_DAT(obj) & 0xFF;
        }
        count++;
    } while (((status == 0x80) || (status == 0x90) ||
            (status == 0x060) || (status == 0x70)) && (count < length));
 
    // Clear old status and wait for Serial Interrupt. 
    i2c_clear_SI(obj);
    i2c_wait_SI(obj);
 
    // Obtain new status.
    status = i2c_status(obj);
 
    if(status != 0xA0) {
        i2c_stop(obj);
    }
 
    i2c_clear_SI(obj);
    
    return count;
}
示例#4
0
文件: i2c_api.c 项目: pan-/mbed
static inline int i2c_do_read(i2c_t *obj, int last) {
    // wait for it to arrive
    i2c_wait_SI(obj);
    if (!last)
        obj->i2c->MSTCTL = (1 << 0);
    
    // return the data
    return (I2C_DAT(obj) & 0xFF);
}
示例#5
0
文件: i2c_api.c 项目: pan-/mbed
static inline int i2c_do_write(i2c_t *obj, int value, uint8_t addr) {
    // write the data
    I2C_DAT(obj) = value;
    
    if (!addr)
        obj->i2c->MSTCTL = (1 << 0);
    
    // wait and return status
    i2c_wait_SI(obj);
    return i2c_status(obj);
}
示例#6
0
static inline int i2c_do_write(i2c_t *obj, int value, uint8_t addr) {
    // write the data
    I2C_DAT(obj) = value;
    
    // clear SI to init a send
    i2c_clear_SI(obj);
    
    // wait and return status
    i2c_wait_SI(obj);
    return i2c_status(obj);
}
示例#7
0
文件: i2c_api.c 项目: nickmolo/ECE477
//Spec says: first check Idle and status is Ok
static inline int i2c_do_write(i2c_t *obj, int value, uint8_t addr) {
    // write the data
    I2C_DAT(obj) = value;
    
    if (!addr)
        obj->i2c->MSTCTL = (1 << 0); //Set continue for data. Should not be set for addr since that uses STA
    
    // wait and return status
    i2c_wait_SI(obj);
    return i2c_status(obj);
}
示例#8
0
static inline int i2c_do_read(i2c_t *obj, int last) {
    // we are in state 0x40 (SLA+R tx'd) or 0x50 (data rx'd and ack)
    if(last) {
        i2c_conclr(obj, 0, 0, 0, 1); // send a NOT ACK
    } else {
        i2c_conset(obj, 0, 0, 0, 1); // send a ACK
    }
    
    // accept byte
    i2c_clear_SI(obj);
    
    // wait for it to arrive
    i2c_wait_SI(obj);
    
    // return the data
    return (I2C_DAT(obj) & 0xFF);
}
示例#9
0
int i2c_slave_read(i2c_t *obj, char *data, int length) {
    int count = 0;
    int status;
    
    do {
        i2c_clear_SI(obj);
        i2c_wait_SI(obj);
        status = i2c_status(obj);
        if((status == 0x80) || (status == 0x90)) {
            data[count] = I2C_DAT(obj) & 0xFF;
        }
        count++;
    } while (((status == 0x80) || (status == 0x90) ||
            (status == 0x060) || (status == 0x70)) && (count < length));
    
    if(status != 0xA0) {
        i2c_stop(obj);
    }
    
    i2c_clear_SI(obj);
    
    return count;
}
示例#10
0
//==========================================================================
// transmit a buffer to a device
//==========================================================================
cyg_uint32 cyg_lpc2xxx_i2c_tx(const cyg_i2c_device *dev, 
                              cyg_bool              send_start, 
                              const cyg_uint8      *tx_data, 
                              cyg_uint32            count, 
                              cyg_bool              send_stop)
{
    cyg_lpc2xxx_i2c_extra* extra = 
                           (cyg_lpc2xxx_i2c_extra*)dev->i2c_bus->i2c_extra;
    extra->i2c_addr  = dev->i2c_address << 1;
    extra->i2c_count = count;
    extra->i2c_txbuf = tx_data;
  
    //
    // for a repeated start the SI bit has to be reset
    // if we continue a previous transfer, load the next byte
    //
    if(send_start) 
    {
        SET_CON(extra, CON_STA);
        if (I2C_FLAG_ACT == extra->i2c_flag)
        {
            CLR_CON(extra, CON_SI);
        }
    } 
    else 
    {
        HAL_WRITE_UINT8(I2C_DAT(extra), *(extra->i2c_txbuf));
        extra->i2c_txbuf++;
        CLR_CON(extra, CON_SI);
    }
  
    extra->i2c_flag  = 0;
  
    //
    // the isr will do most of the work, and the dsr will signal when an
    // error occured or the transfer finished
    //
    cyg_drv_mutex_lock(&extra->i2c_lock);
    cyg_drv_dsr_lock();
    cyg_drv_interrupt_unmask(I2C_ISRVEC(extra));
    while(!(extra->i2c_flag & (I2C_FLAG_FINISH | I2C_FLAG_ERROR)))
    {
        cyg_drv_cond_wait(&extra->i2c_wait);
    }
    cyg_drv_interrupt_mask(I2C_ISRVEC(extra));
    cyg_drv_dsr_unlock();
    cyg_drv_mutex_unlock(&extra->i2c_lock);
  
    // too bad we have no way to tell the caller
    if(extra->i2c_flag & I2C_FLAG_ERROR)
    {
        debug1_printf("I2C TX error flag: %x\n", extra->i2c_flag);
        extra->i2c_flag = 0;
    }
    else
    {
        if(send_stop) 
        {
            SET_CON(extra, CON_STO);
            CLR_CON(extra, CON_SI | CON_STA);
            extra->i2c_flag = 0;
        } 
        else  
        {
            extra->i2c_flag = I2C_FLAG_ACT;
        }
    }
   
    count -= extra->i2c_count;
  
    extra->i2c_addr  = 0;
    extra->i2c_count = 0;
    extra->i2c_txbuf = NULL;
  
    return count;
}
示例#11
0
//==========================================================================
// The ISR does the actual work. It is not that much work to justify
// putting it in the DSR, and it is also not clear whether this would
// even work.  If an error occurs we try to leave the bus in the same
// state as we would if there was no error.
//==========================================================================
static cyg_uint32 lpc2xxx_i2c_isr(cyg_vector_t vec, cyg_addrword_t data)
{
    cyg_lpc2xxx_i2c_extra* extra = (cyg_lpc2xxx_i2c_extra*)data;
    cyg_uint8  status;
    
    I2C_R8(I2C_STAT(extra), status);
    switch(status) 
    {
    case 0x00: // bus error, stop transfer
         SET_CON(extra, CON_STO);
         extra->i2c_flag = I2C_FLAG_ERROR | I2C_FLAG_BUS;
         break;
         
    case 0x08: // START sent, send Addr+R/W
    case 0x10: // ReSTART sent, send Addr+R/W
         CLR_CON(extra, CON_STA);
         I2C_W8(I2C_DAT(extra), extra->i2c_addr);
         break;
      
    case 0x18: // Addr ACKed, send data
         if(extra->i2c_txbuf == NULL) 
         {
             extra->i2c_flag = I2C_FLAG_ERROR | I2C_FLAG_BUF;
             cyg_drv_interrupt_mask_intunsafe(vec);
             cyg_drv_interrupt_acknowledge(vec);
             return CYG_ISR_HANDLED | CYG_ISR_CALL_DSR;
         }
         I2C_W8(I2C_DAT(extra), *extra->i2c_txbuf);
         extra->i2c_txbuf++;
         break;
         
    case 0x28: // Data ACKed, send more
         extra->i2c_count--;     
         if(extra->i2c_count == 0) 
         {
             extra->i2c_flag = I2C_FLAG_FINISH;
             cyg_drv_interrupt_mask_intunsafe(vec);
             cyg_drv_interrupt_acknowledge(vec);
             return CYG_ISR_HANDLED | CYG_ISR_CALL_DSR;
         }
         I2C_W8(I2C_DAT(extra), *extra->i2c_txbuf);
         extra->i2c_txbuf++;
         break;
      
    case 0x50: // Data ACKed, receive more
    case 0x58: // Data not ACKed, end reception
         if(extra->i2c_rxbuf == NULL) 
         {
             extra->i2c_flag = I2C_FLAG_ERROR | I2C_FLAG_BUF;
             cyg_drv_interrupt_mask_intunsafe(vec);
             cyg_drv_interrupt_acknowledge(vec);
             return CYG_ISR_HANDLED | CYG_ISR_CALL_DSR;
         }
      
         I2C_R8(I2C_DAT(extra), *extra->i2c_rxbuf);
         extra->i2c_rxbuf++;
         extra->i2c_count--;
         // fall through
         
    case 0x40: // Addr ACKed, receive data
         if(status == 0x58 || extra->i2c_count == 0) 
         {
             extra->i2c_flag = I2C_FLAG_FINISH;
             cyg_drv_interrupt_mask_intunsafe(vec);
             cyg_drv_interrupt_acknowledge(vec);
             return CYG_ISR_HANDLED | CYG_ISR_CALL_DSR;
         }
      
         if((extra->i2c_count == 1) && extra->i2c_rxnak)
         {
             CLR_CON(extra, CON_AA);
         }
         else 
         {   
             SET_CON(extra, CON_AA);
         }
         break;
      
    case 0x20: // Addr not ACKed
    case 0x48: // Addr not ACKed
         SET_CON(extra, CON_STO); // tranfer failed - force stop
         extra->i2c_flag = I2C_FLAG_ERROR | I2C_FLAG_ADDR;
         cyg_drv_interrupt_mask_intunsafe(vec);
         cyg_drv_interrupt_acknowledge(vec);
         break;
         
    case 0x30: // Data not ACKed
         SET_CON(extra, CON_STO); // tranfer failed - force stop
         extra->i2c_count++;
         extra->i2c_txbuf--;
         extra->i2c_flag = I2C_FLAG_ERROR | I2C_FLAG_DATA;
         cyg_drv_interrupt_mask_intunsafe(vec);
         cyg_drv_interrupt_acknowledge(vec);
         return CYG_ISR_HANDLED | CYG_ISR_CALL_DSR;
         break;
         
    case 0x38: // Arbitration lost
         extra->i2c_flag = I2C_FLAG_ERROR | I2C_FLAG_LOST;
         break;
         
    default: // lots of unused states
         extra->i2c_flag = I2C_FLAG_ERROR | I2C_FLAG_UNK;
         break;
    } // switch(status)
  
    CLR_CON(extra, CON_SI);
    cyg_drv_interrupt_acknowledge(vec);
    
    //
    // We need to call the DSR only if there is really something to signal,
    // that means only if extra->i2c_flag != 0
    //
    if (extra->i2c_flag)
    {
        return CYG_ISR_HANDLED | CYG_ISR_CALL_DSR;
    }
    else
    {
        return CYG_ISR_HANDLED; 
    }
}