發新話題
打印

C8051F330的SMBus搭配I/O to I2C

C8051F330的SMBus搭配I/O to I2C

目前有一個應用:
想把MCU當作一個轉送器
就是PC下一個command給MCU(這邊使用SMBus)
MCU接收到後,馬上使用I/O to I2C下command給EEPROM要值
MCU接收到EEPROM的值後再丟到SMBus上給PC接收
請問有人做過類似的應用嗎??

目前我的做法如下:
void SMBus_ISR (void) interrupt 7
{
   if (ARBLOST == 0)
   {
      if(SR_Addr_Cnt==0)                 
          {
                  W_Addr[0]=SMB0DAT;
                SR_Addr_Cnt++;
          }                  

      switch (SMB0CN & 0xF0)           // Decode the SMBus status vector
      {
         case  SMB_SRADD:

            STA = 0;                   // Clear STA bit
            if((SMB0DAT&0xFE) == 0xA0 || (SMB0DAT&0xFE) == 0xA2 )
            {                          
                           ACK = 1;                                                // If the received address matches,
                                                       // ACK the received slave address
               if((SMB0DAT&0x01) == READ) // If the transfer is a master READ,
               {
                  W_Addr[0]=SMB0DAT;                            
                                  cnt_plus=W_Addr[1]+ST_Addr_Cnt;
                                                                                                                                       
                                  if(W_Addr[0]==A1_SlvAddr)       
                                  {
                                        I2CReadByte(0xA0,cnt_plus,&Data_buf[0],1,1);
                                        SMB0DAT = Data_buf[0];  // Prepare outgoing byte
                                  }
                                  else if(W_Addr[0]==A3_SlvAddr)
                                  {
                                                I2CReadByte(0xA2,cnt_plus,&Data_buf[0],1,1);
                                                SMB0DAT = Data_buf[0];  // Prepare outgoing byte
                                  }       
                           }
            }
            else                       // If received slave address does not
            {                          // match,
               ACK = 0;                // NACK received address
            }
            break;

         // Slave Receiver: Data received
         case  SMB_SRDB:

            W_Addr[SR_Addr_Cnt] = SMB0DAT;        // Store incoming data
            SR_Addr_Cnt++;                 
                        ACK = 1;                  // ACK received data
                              
            break;

         // Slave Receiver: Stop received while either a Slave Receiver or
         // Slave Transmitter
         case  SMB_SRSTO:

                        if(W_Addr[0]==0xA0 || W_Addr[0]==0xA2)
            {
                                STO = 0;                   // STO must be cleared by software when
                                       // a STOP is detected as a slave
                                ST_Addr_Cnt=0;                          
                                W_to_Flash=1;
                                Flash_Write();
                        }
                        else if(W_Addr[0]==0xA1 || W_Addr[0]==0xA3)
                        {
                                STO=0;
                                W_to_Flash=0;
                                ST_Addr_Cnt=0;                          
                                SR_Addr_Cnt=0;
                        }
                       
                        PCA0CPH2 = 0x00;   // watchdog clear timer
                        break;

         // Slave Transmitter: Data byte transmitted
         case  SMB_STDB:
                       
                        if(ACK==1)
                        {
                                ST_Addr_Cnt++;
                                cnt_plus=W_Addr[1]+ST_Addr_Cnt;
                                if(W_Addr[0]==0xA1)
                                {
                                        I2CReadByte(0xA0,cnt_plus,&Data_buf[0],1,1);
                                        SMB0DAT = Data_buf[0];  // Prepare outgoing byte
                                }
                                else if(W_Addr[0]==0xA3)
                                {
                                                I2CReadByte(0xA2,cnt_plus,&Data_buf[0],1,1);
                                                SMB0DAT = Data_buf[0];  // Prepare outgoing byte
                                }
            }
                        break;

         case  SMB_STSTO:

            STO = 0;                   // STO must be cleared by software when
                                       // a STOP is detected as a slave
                        ST_Addr_Cnt=0;                         
                        SR_Addr_Cnt=0;
            break;

         // Default: all other cases undefined
         default:

            SMB0CF &= ~0x80;           // Reset communication
            SMB0CF |= 0x80;
            STA = 0;
            STO = 0;
            ACK = 0;
            break;
      }
   }
   // ARBLOST = 1, Abort failed transfer
   else
   {
      STA = 0;
      STO = 0;
      ACK = 0;
   }

   SI = 0;                             // Clear SMBus interrupt flag
}

主要的問題是在以下的部分
I2CReadByte(0xA0,cnt_plus,&Data_buf[0],1,1); //I2CReadByte(slave_Addr,word_Addr,DataByte,讀取幾個byte,port);
SMB0DAT = Data_buf[0];  
目前的結果來看,從PC端下ByteRead可以讀取到值
但是MultiByte-Read讀到PC上會有錯誤
用Debug模式看到在:
         // Slave Transmitter: Data byte transmitted
         case  SMB_STDB:
有進入這個程式中,執行完I2CReadByte()後,Data_buf[0]有讀取到想要的值,SMB0DAT也有放上想要的值,但是有沒有被PC接收就不清楚,應該是沒有,因為我PC是一次讀取5個byte,但是debug模式下,執行到SMB0DAT = Data_buf[0]之後就會跳到STOP的部分,所以我PC讀取上一直有問題

目前我是用print port to I2C來讓PC和MCU溝通,人機介面是用Labview編寫

TOP

1. 你有去量測 你用IO 去讀取 EEPROM 的速度嗎?
2. Labview 在讀取資料的時候 IIC 在多少時間會判斷是NACK?還是沒收到資料失敗?

我想這個應該是時序上的問題
IIC_address command data ack data ack

我不確定在 data 接 ack <Nack> 的時間 在MCU 的部份
是否足夠讓你在IO去讀取 EEPROM 之後再回傳 data

TOP

1. 量過,大約30KHz左右
2. 設定上是3秒,不過Labview讀取時並不是失敗,而是資料是讀取錯誤
   例如:EEPROM上5個byte:AA BB CC 05 AA
   讀取到:00 00 00 AA FE
   感覺很像是Clock stretch有錯
   不過,如果沒有轉傳時,這個問題比較少發生

我也有想過是否是時序的問題,而且SMBus Timeout的Timer設定好像是25ms,
怕的是SMBus Timeout的問題,如果是print port to i2c的問題倒還好,

對了,那一個完整的I2C ByteRead 的時間會花多少呢? 如果以400kHz,會是5ms嗎?

感謝回覆~
謝謝!!

TOP

不好意思
順便問一下
C8051F330的ADC
如果要monitor VDD(MCU的工作電壓)
AMX0P選擇VDD為input
AMX0N選擇GND為input
這樣就可以了嗎?

我的參考電壓設定為internal Vref = 2.44V

這樣是不是會讓monitor的電壓一直都是最大值呢?

我用test board測試一直有問題

TOP

不好意思
順便問一下
C8051F330的ADC
如果要monitor VDD(MCU的工作電壓)
AMX0P選擇VDD為input
AMX0N選擇GND為input
這樣就可以了嗎?

我的參考電壓設定為internal Vref = 2.44V

這樣是不是會讓monitor的電壓一直都是最大值呢?

我用test board測試一直有問題

TOP

VDD monitor
如果是使用F330 內部的功用
你應該是要參考 datasheet P100
只要將功能開啟即可

VDM0CN: VDD Monitor Control <-- 內部參數

TOP

有開啟
但是AD轉換出來的都是0x3FF

設定上為:
AMX0P選擇VDD為input
AMX0N選擇GND為input
right-adjusted
參考電壓設定為internal Vref = 2.44V

TOP

1.VDD Monitor 當電壓 小於2.7V <有個範圍 請參考 datasheet> MCU H/W
  會做 reset 動作 要知道是否被 reset 要參考RSTSRC 這個參數
2.ADC 的部份 你的 vref 多高 量測到的電壓就多高
  假測你 Vref 電壓是 2.44 你2.44V 就會是10bit 最高
  所以你接去VDD 只會量側到 最高bit 數
3.假設你真的要看VDD 的電壓 你可以透過電組分壓的方式
  進到 AD in 去讓VDD 電壓降到 2.44V 以下準位
  前提 2.7V 是MCU 的工作電壓 不可小於此工作電壓

TOP

發新話題