聲學晶片FM2018WE-380 除錯詳解
阿新 • • 發佈:2018-12-20
FM2018WE-380晶片的主要作用是抑制聲學噪聲,消除聲學回聲,提升通話質量。 **注:**本篇底部附FM2018WE-380晶片相關文件供下載學習。
主要有以下步驟: 1.上電(VDD拉高),若需VDD_1V8拉高,檢視原理圖可知需先讓GPIO27_FM2018_EN 引腳使能(置1)
2.選擇SHI模式,拉高VDD(選擇這個模式外部主機才能初始化和更改晶片內部暫存器),這裡SHI與VDD公用一個引腳(VDD_1V8) 3.接入外部時鐘(經與硬體溝通得知為 TCXO_CLK引腳匯入時鐘),檢視原理圖可知需讓GPIO30_TCXO_PW_EN 引腳使能(置1)
相關程式碼
/***************************************************************************** * FUNCTION * fmdsp_bootup * DESCRIPTION * * Set FM2018_DSP register parameters when FM2018_DSP is turned on. * * PARAMETERS mode * * RETURNS * *****************************************************************************/ kal_uint8 fm2018_dsp_bootup(void) { fm2018dsp.read = fm2018_i2c_read; // assign read function fm2018dsp.write= fm2018_i2c_write; // assign write function //power on //SHI_S 拉高此引腳,允許外部主機初始化和更改暫存器的值(檢視晶片手冊得知) GPIO_ModeSetup(VDDSHI_FM2018_EN, 0); GPIO_InitIO(1, VDDSHI_FM2018_EN); GPIO_WriteIO(1, VDDSHI_FM2018_EN); Delayms(10); //RESET FM2018 復位 GPIO_ModeSetup(AGPIO52_RESET_2018, 0); GPIO_InitIO(1, AGPIO52_RESET_2018); GPIO_WriteIO(0, AGPIO52_RESET_2018); Delayms(30); //P WD_FM2018 掉電模式(拉高是正常模式) GPIO_ModeSetup(GPIO49_PWD, 0); GPIO_InitIO(1, GPIO49_PWD); GPIO_WriteIO(1, GPIO49_PWD); //CLK 時鐘(對應GPIO拉高表示接入外部時鐘) GPIO_ModeSetup(GPIO30_TCXO_PW_EN, 0); GPIO_InitIO(1, GPIO30_TCXO_PW_EN); GPIO_WriteIO(1, GPIO30_TCXO_PW_EN); Delayms(5); GPIO_WriteIO(1, AGPIO52_RESET_2018);//RESET FM2018 // Delayms(15); //init parameter fm2018dsp_init(&fm2018dsp); //初始化晶片內部暫存器 }
初始化暫存器
/***************************************************************************** * FUNCTION * fmdsp_bootup * DESCRIPTION * Set FM2018_DSP register parameters when FM2018_DSP is turned on. * PARAMETERS mode * RETURNS *****************************************************************************/ void fm2018dsp_init(struct fm2018dsp_t *fm2018dsp) { kal_uint8 pData[16]; // set hands free mode tr_debug("\r\n<<<<<<<<<<<<<<<<<<fmdsp_bootup enter>>>>>>>>>>>>>>>>>>>>"); // ============================================================ // // Register address and register data // ============================================================ // /*1st Parameters can only be changed at initialization stage */ fm2018dsp->write(0x1E, 0x30, 0x02, 0x31);//1E30 0231 //D9-Parser enable :1, D5-Analog line-out :1, D4-Analog line-in :1 D0-Mic_0 enbale:1 fm2018dsp->write(0x1E, 0x34, 0x00, 0x2A);//1E34 002A //Mic_pgagain Mic0 PGA gain. 0x0a : +16db fm2018dsp->write(0x1E, 0x35, 0x00, 0x0A);//1E35 000A //Linein_pgagain Line-in PGA gain. 0x0a : +16db fm2018dsp->write(0x1E, 0x36, 0x00, 0x1D);//1E36 001D //Lineout_pgagain Line-out PGA gain. 0x1d : +00db fm2018dsp->write(0x1E, 0x39, 0x00, 0x00);//1E39 0000 //Ana_comm_high D0 -1: Analog Communication Mode is triggered by rising edge //ANA_COMM //fm2018dsp->write(0x1E, 0x4A, 0x00, 0x2A);//1E4A 002A //ana_Mic_pgagain at ANA_COMM mode //fm2018dsp->write(0x1E, 0x4B, 0x00, 0x2A);//1E4A 002A //ana_linein_pgagain at ANA_COMM mode //fm2018dsp->write(0x1E, 0x4C, 0x00, 0x2A);//1E4A 002A //ana_lineout_pgagain at ANA_COMM mode /* Parameters need to be preset according to application,placement and components specs */ fm2018dsp->write(0x1E, 0x3D, 0x02, 0x00); //1E3D 0200 mic volume : 0x0100 is equal to unit gain. 0x200 is 2X gain fm2018dsp->write(0x1E, 0x3E, 0x02, 0x00); //1E3E 0200 spk volume : 0x0100 is equal to unit gain. 0x200 is 2X gain. (affect AEC_REF signal level) fm2018dsp->write(0x1E, 0x40, 0xff, 0xff);//microphone mute flag, 0xffff: no mute fm2018dsp->write(0x1E, 0x41, 0x01, 0x01);//1E41 0101 number of mics, 0x101: 1 mic //fm2018dsp->write(0x1E, 0x44, 0x00, 0x81);//1E44 0081 // .......... fm2018dsp->write(0x1E, 0x44, 0x0C, 0x89);//1E44 0081 // D12 - SPK_OUT equalizer D11 - noise residue smoother D7 - SNR_ADJUST D3 - BVE,D0-frame process fm2018dsp->write(0x1E, 0x45, 0x03, 0xcf);//1E45 03cf // .... fm2018dsp->write(0x1E, 0x46, 0x00, 0x10);//1E46 0010 // ... D4- Parser and SHI,1:on fm2018dsp->write(0x1E, 0x47, 0x20, 0x00);//1E47 2000 // Mic_NSS_level the noise suppression//Example (0x2000 / 0x7fff = -12dB) fm2018dsp->write(0x1E, 0x48, 0x80, 0x00);//1E48 8000 //Mic_NS_lowband_gain this parameter defines the noise suppression gain (in band one).0x800 is unit gain. fm2018dsp->write(0x1E, 0x49, 0x80, 0x00);//1E49 8000 //Mic_NS_highband_gain (out of band one) the bigger the value, the more noise suppression is applied. //fm2018dsp->write(0x1E, 0x4D, 0x80, 0x00);//1E4D 8000 //cancel the echo. 0x100 is unit gain. fm2018dsp->write(0x1E, 0x4D, 0xE8, 0x00);//1E4D 8000 //cancel the echo. 0x100 is unit gain. fm2018dsp->write(0x1E, 0x4F, 0x00, 0x01);//1E4F 0001 // ... normal mode fm2018dsp->write(0x1E, 0x57, 0x7E, 0x00);//1E57 7E00 //Microphone Saturate threshold(default value 0x7E00) system is put to a half duplex mode to prevent howing fm2018dsp->write(0x1E, 0x59, 0x7F, 0xFF);//1E59 7FFF //Lineout Clip Threshold fm2018dsp->write(0x1E, 0x5C, 0x10, 0x00);//1E5C 1000 //This parameter is to set the half duplex hold time. Time = st_hd_time * (1/8192)sec //fm2018dsp->write(0x1E, 0x63, 0x00, 0x10);//1E63 0010 //In order to compensate the delay of ADC / DAC fm2018dsp->write(0x1E, 0x63, 0x00, 0x10);//1E63 0010 //In order to compensate the delay of ADC / DAC fm2018dsp->write(0x1E, 0x80, 0x03, 0x3F);//1E63 0010 //In order to compensate the delay of ADC / DAC //STOP................. //fm2018dsp->write(0x1E, 0x86, 0x00, 0x07);//1E86 0007 //fm2018dsp->write(0x1E, 0x87, 0x00, 0x03);//1E87 0003 fm2018dsp->write(0x1E, 0x86, 0x00, 0x0E);//1E86 0007 fm2018dsp->write(0x1E, 0x87, 0x00, 0x0E);//1E87 0003 //fm2018dsp->write(0x1E, 0x88, 0x30, 0x00);//1E88 3000 //fm2018dsp->write(0x1E, 0x89, 0x18, 0x00);//1E89 1800 //suppress more echo under noisy environment. fm2018dsp->write(0x1E, 0x88, 0x30, 0x00);//1E88 3000 fm2018dsp->write(0x1E, 0x89, 0x18, 0x00);//1E89 1800 //suppress more echo under noisy environment. fm2018dsp->write(0x1E, 0x8B, 0x7F, 0xFF);//1E8B 7FFF //Fe_vad_th_big fm2018dsp->write(0x1E, 0x8C, 0x7F, 0xFF);//1E8C 7FFF //fe_vad_th fm2018dsp->write(0x1E, 0x90, 0xFF, 0xFF);//1E90 FFFF //Aec_nw_shift fm2018dsp->write(0x1E, 0x91, 0x00, 0xFF);//1E91 00FF //Aec_fe_vad_shift ... fm2018dsp->write(0x1E, 0x92, 0x78, 0x00);//1E92 7800 // fm2018dsp->write(0x1E, 0x93, 0x78, 0x00);//1E93 7800 // fm2018dsp->write(0x1E, 0xA0, 0x80, 0x00);//1EA0 8000 fm2018dsp->write(0x1E, 0xA1, 0x80, 0x00);//1EA1 0010 //This parameter specifies the gain applied to both main and reference channels after Linear AEC process #if 1 //agc fm2018dsp->write(0x1E, 0xA7, 0x02, 0x88);//1EA7 0288 fm2018dsp->write(0x1E, 0xA8, 0x19, 0x4C);//1EA8 194C //default mic_agc_maxgain fm2018dsp->write(0x1E, 0xAB, 0x00, 0x74);//1EAB 0074 //default mic_agc_ref sp_flag(0x1e45) #endif #if 1 //GND fm2018dsp->write(0x1E, 0xB3, 0x1F, 0x00);//1EB3 1F00 default //Gnd_div_low fm2018dsp->write(0x1E, 0xB4, 0x14, 0x00);//1EB4 1400 default //Gnd_div_mid fm2018dsp->write(0x1E, 0xB4, 0x14, 0x00);//1EB5 0800 default//Gnd_div_high #endif #if 1 // Fq fm2018dsp->write(0x1E, 0xBB, 0x00, 0x0B);//1EBB 000B default //Fq_period fm2018dsp->write(0x1E, 0xBC, 0x68, 0x00);//1EBC 6800 //Fq_beta_v1 fm2018dsp->write(0x1E, 0xBD, 0x01, 0x00);//1EBD 0100 //Fq_beta_v2 fm2018dsp->write(0x1E, 0xBE, 0x40, 0x00);//1EBE 4000 //Fq_beta_mix2 fm2018dsp->write(0x1E, 0xBF, 0x70, 0x00);//1EBF 7100 //Fq_beta_uv2 fm2018dsp->write(0x1E, 0xC0, 0x26, 0x80);//1EC0 2680 //Fq_beta_uv_fe fm2018dsp->write(0x1E, 0xC1, 0x10, 0x80);//1EC1 1080 //Fq_beta_mix_fe fm2018dsp->write(0x1E, 0xC5, 0x2B, 0x06);//1EC5 2B06 //Fq_refch_div_12 fm2018dsp->write(0x1E, 0xC6, 0x0C, 0x1F);//1EC6 0C1F //F q_refch_div_34 fm2018dsp->write(0x1E, 0xC7, 0x40, 0x00);//1EC7 0400 //Fq_fevad_gain_limit fm2018dsp->write(0x1E, 0xC8, 0x28, 0x79);//1EC8 2879 //Fq_refch_gain_band1 fm2018dsp->write(0x1E, 0xC9, 0x65, 0xAB);//1EC9 65AB //Fq_refch_gain_band2 fm2018dsp->write(0x1E, 0xCA, 0x40, 0x26);//1ECA 4026 //Fq_refch_gain_band3 fm2018dsp->write(0x1E, 0xCB, 0x7F, 0xFF);//1ECB 7FFF //Fq_refch_gain_band4 fm2018dsp->write(0x1E, 0xCC, 0x7F, 0xFE);//1ECC 7FFE //Fq_refch_gain_band5 #endif #if 1 //Eq_const_lout[1] ~ Eq_const_lout[5] fm2018dsp->write(0x1E, 0xD0, 0x7F, 0xFF);//1ED0 7FFF //Eq_const_lout[1] fm2018dsp->write(0x1E, 0xD1, 0x7F, 0xFF);//1ED1 7FFF //Eq_const_lout[2] fm2018dsp->write(0x1E, 0xD2, 0x7F, 0xFF);//1ED2 7FFF //Eq_const_lout[3] fm2018dsp->write(0x1E, 0xD3, 0x7F, 0xFF);//1ED3 7FFF //Eq_const_lout[4] fm2018dsp->write(0x1E, 0xD4, 0x7F, 0xFF);//1ED4 7FFF //Eq_const_lout[5] #endif fm2018dsp->write(0x1E, 0xDA, 0x20, 0x00);//1EDA 2000 //Fq_noise_smoother_gain fm2018dsp->write(0x1E, 0xE0, 0x00, 0x00);//1EE0 0000 //Fq_start_echo #if 1 //Bve fm2018dsp->write(0x1E, 0xE2, 0x00, 0x06);//1EE2 0006 //Bve_order fm2018dsp->write(0x1E, 0xE3, 0x04, 0x00);//1EE3 0400 //Bve_max_volume fm2018dsp->write(0x1E, 0xE4, 0x18, 0x00);//1EE4 1800 //Bve_overflow_gain #endif fm2018dsp->write(0x1E, 0xF8, 0x04, 0x00);//1EF8 0400 //Vad0_rat_thrd_fe fm2018dsp->write(0x1E, 0xF9, 0x01, 0x00);//1EF9 0620 //Vad0_rat_thrd_nofe fm2018dsp->write(0x1E, 0xFF, 0x4B, 0x00);//1EFF 4B00 //VAD3_rat_thrd fm2018dsp->write(0x1F, 0x00, 0x7F, 0xFF);//1F00 7FFF //Mic_cal_diff fm2018dsp->write(0x1F, 0x01, 0x31, 0x00);//1F01 3100 //Mic_cal_gain_center #if 1 //Eq_const_spk[1] ~ Eq_const_spk[4] fm2018dsp->write(0x1F, 0x06, 0x16, 0x52);//1F06 1652 //Eq_const_spk[1] fm2018dsp->write(0x1F, 0x07, 0x18, 0xE2);//1F07 18E2 //Eq_const_spk[2] fm2018dsp->write(0x1F, 0x08, 0x0A, 0x4E);//1F08 0A4E //Eq_const_spk[3] fm2018dsp->write(0x1F, 0x09, 0x05, 0xDF);//1F09 05DF //Eq_const_spk[4] #endif fm2018dsp->write(0x1F, 0x0A, 0x0A, 0x00);//1F0A 0A00 //VAD1_grd_min fm2018dsp->write(0x1F, 0x0B, 0x03, 0x00);//1F0B 0300 //VAD2_grd_min fm2018dsp->write(0x1F, 0x0C, 0x01, 0x00);//1F0C 0100 //VAD1_thrd fm2018dsp->write(0x1F, 0x0D, 0x78, 0x00);//1F0D 7800 //VAD2_thrd #if 1 fm2018dsp->write(0x1F, 0x28, 0x0C, 0x00);//1F28 0C00 //Spkout_drc_th1 fm2018dsp->write(0x1F, 0x29, 0x18, 0x80);//1F29 1880 //Spkout_drc_th2 fm2018dsp->write(0x1F, 0x2A, 0x34, 0x00);//1F2A 3400 //Spkout_drc_slop1 fm2018dsp->write(0x1F, 0x2B, 0x68, 0x00);//1F2B 6800 //Spkout_drc_slop2 fm2018dsp->write(0x1F, 0x30, 0x00, 0x00);//1F30 0000 //Debug_flag #endif /*1st Parameters can only be changed at initialization stage */ fm2018dsp->write(0x1E, 0x52, 0x00, 0x13);//1E52 0013 //This parameter sets the DSP Mips. DSP_mips = 1.024 * (23+17) = 40Mips //fm2018dsp->write(0x1E, 0x58, 0x00, 0x19); /* set clock */ //26m fm2018dsp->write(0x1E, 0x58, 0x00, 0x0C); /* set clock */ //13m fm2018dsp->write(0x1E, 0x60, 0x00, 0x00);//1E60 0000 //external clock source is used fm2018dsp->write(0x1E, 0x51, 0xD0, 0x00); /* no need to reload parameter */ fm2018dsp->write(0x1E, 0x70, 0x05, 0xC0); //Pwdn_device_off : This parameter has to be set to 0x05C0 to ensure reliable power down tr_debug("DSP run, must be in last\r\n"); fm2018dsp->write(0x1E, 0x3A, 0x00, 0x00); // DSP run, must be in last tr_debug("\r\n==================DSP run============="); tr_debug("\r\n......................................"); //fm2018dsp->read(0x1E,0x3A,(kal_uint8 *)pData,2); //tr_debug("2 test_clock ========== %x",*pData); }
以下是關於I2C詳細記錄
Some Define
#define FM2018_I2C_DELAY 20 //設定一個延時變數,用於程式碼中for迴圈延時
#define fm2018_I2C_SCL 43 //SCL(時鐘線)對應的GPIO為43
#define fm2018_I2C_SDA 44 //SDA(資料線)對應的GPIO為44 (此兩項根據檢視原理圖得到)
#define FM2018_I2C_CLK_OUTPUT GPIO_InitIO(1,fm2018_I2C_SCL) //初始化SCL的工作方向設定為輸出
#define FM2018_I2C_CLK_HIGH GPIO_WriteIO(1,fm2018_I2C_SCL) //給SCL引腳一個高電平
#define FM2018_I2C_CLK_LOW GPIO_WriteIO(0,fm2018_I2C_SCL) //給SCL引腳一個低電平
#define FM2018_I2C_CLK_BIT GPIO_ReadIO(fm2018_I2C_SCL) //讀取SCL引腳的電平狀態
#define FM2018_I2C_DATA_OUTPUT GPIO_InitIO(1,fm2018_I2C_SDA) //初始化SDA的工作方向設定為輸出
#define FM2018_I2C_DATA_INPUT GPIO_InitIO(0,fm2018_I2C_SDA) //初始化SDA的工作方向設定為輸入
#define FM2018_I2C_DATA_HIGH GPIO_WriteIO(1,fm2018_I2C_SDA) //給SDA引腳一個高電平
#define FM2018_I2C_DATA_LOW GPIO_WriteIO(0,fm2018_I2C_SDA) //給SDA引腳一個高電平
#define FM2018_I2C_DATA_BIT GPIO_ReadIO(fm2018_I2C_SDA) //讀取S DA引腳的電平狀態
#define FM2018_I2C_ACK_BIT \ //一個位元組傳輸完成後,第九位的應答(從機有應答,資料線對應為低電平)
do{\
kal_uint32 x;\
FM2018_I2C_CLK_LOW; \ //時鐘線拉低
for (x=0; x<FM2018_I2C_DELAY; x++); \ //延時
FM2018_I2C_DATA_OUTPUT; \ //資料線設定為輸出模式
FM2018_I2C_DATA_LOW; \ //資料線輸出低電平
for (x=0; x<FM2018_I2C_DELAY; x++); \ //延時
FM2018_I2C_CLK_HIGH; \ //時鐘線拉高
for (x=0; x<FM2018_I2C_DELAY; x++); \ //延時
FM2018_I2C_CLK_LOW; \ //時鐘線拉低
for (x=0;x<FM2018_I2C_DELAY;x++);\ //延時
}while(0)
#define FM2018_I2C_NACK_BIT \ //一個位元組傳輸完成後,第九位的應答(從機無應答,資料線對應為高電平)
do{\
kal_uint32 x;\
FM2018_I2C_CLK_LOW; \ //時鐘線拉低
for (x=0; x<FM2018_I2C_DELAY; x++); \ //延時
FM2018_I2C_DATA_OUTPUT; \ //資料線設定為輸出模式
FM2018_I2C_DATA_HIGH; \ //資料線輸出高電平
for (x=0; x<FM2018_I2C_DELAY; x++); \ //延時
FM2018_I2C_CLK_HIGH; \ //時鐘線拉高
for (x=0; x<FM2018_I2C_DELAY; x++); \ //延時
FM2018_I2C_CLK_LOW; \ //時鐘線拉低
for (x=0;x<FM2018_I2C_DELAY;x++);\ //延時
}while(0)
#define FM2018_I2C_START_TRANSMISSION \ //傳輸開始位
do{ \
kal_uint32 x; \
FM2018_I2C_CLK_OUTPUT; \ //時鐘線設定為輸出模式
FM2018_I2C_DATA_OUTPUT; \ //資料線設定為輸出模式
FM2018_I2C_CLK_HIGH; \ //時鐘線拉高
FM2018_I2C_DATA_HIGH; \ //資料線拉高
for(x=0;x<FM2018_I2C_DELAY;x++); \ //延時
FM2018_I2C_DATA_LOW; \ //資料線拉低
for(x=0;x<FM2018_I2C_DELAY;x++); \ //延時
FM2018_I2C_CLK_LOW; \ //時鐘線拉低
for(x=0;x<FM2018_I2C_DELAY;x++); \ //延時
}while(0)
#define FM2018_I2C_STOP_TRANSMISSION \ //傳輸停止位
do{ \
kal_uint32 x; \
FM2018_I2C_CLK_OUTPUT; \ //時鐘線設定為輸出模式
FM2018_I2C_DATA_OUTPUT; \ //資料線設定為輸出模式
FM2018_I2C_CLK_LOW; \ //時鐘線拉低
FM2018_I2C_DATA_LOW; \ //資料線拉低
for(x=0;x<FM2018_I2C_DELAY;x++);\ //延時
FM2018_I2C_CLK_HIGH; \ //時鐘線拉高
for(x=0;x<FM2018_I2C_DELAY;x++);\ //延時
FM2018_I2C_DATA_HIGH;\ //資料線拉高
for(x=0;x<FM2018_I2C_DELAY;x++);\ //延時
}while(0)
I2C初始化
void fm2018_i2c_init(void)
{
GPIO_ModeSetup(fm2018_I2C_SCL, 0); //設定SCL的工作模式是作為GPIO
GPIO_InitIO(1, fm2018_I2C_SCL); //初始化SCL的工作方向設定為輸出
GPIO_ModeSetup(fm2018_I2C_SDA, 0); //設定SDA的工作模式是作為GPIO
GPIO_InitIO(1, fm2018_I2C_SDA); //初始化SDA的工作方向設定為輸出
}
傳送一個位元組
//傳送一個位元組的資料
static kal_uint8 fm2018_i2c_send_byte(kal_uint8 send_byte)
{
kal_uint8 ret;
signed char i;
kal_uint32 j;
for (i=7;i>=0;i--) //傳送8個位(1個位元組)
{ /* data bit 7~0 */
if (send_byte & (1<<i)) //判斷對應位是否為1
{
FM2018_I2C_DATA_HIGH; //為1時,資料位拉高
}
else
{
FM2018_I2C_DATA_LOW; //為0時,資料位拉低
}
for(j=0;j<FM2018_I2C_DELAY;j++); //延時
FM2018_I2C_CLK_HIGH; //時鐘線拉高
for(j=0;j<FM2018_I2C_DELAY;j++); //延時
FM2018_I2C_CLK_LOW; //時鐘線拉低
for(j=0;j<FM2018_I2C_DELAY;j++); //延時
}
/* don't care bit, 9th bit */ //獲取第9位應答位有無應答
FM2018_I2C_DATA_INPUT; //將資料線設定為輸入模式
for(j=0;j<FM2018_I2C_DELAY;j++); //延時
FM2018_I2C_CLK_HIGH; //時鐘線拉高
for(j=0;j<FM2018_I2C_DELAY;j++); //延時
ret = !FM2018_I2C_DATA_BIT; //獲取此時資料位狀態(低電平有應答,高電平無應答)
for(j=0;j<FM2018_I2C_DELAY;j++); //延時
FM2018_I2C_CLK_LOW; //時鐘線拉低
FM2018_I2C_DATA_OUTPUT; //讀完應答位後要將資料線恢復到輸出狀態
for(j=0;j<FM2018_I2C_DELAY;j++); //延時
if(0==ret) //若高電平,無應答,傳送失敗
{
tr_debug("i2c send byte fail!\r\n");
}
else //若低電平,有應答,傳送成功
{
tr_debug("i2c send byte success!\r\n");
}
return ret;
}
讀取一個位元組
//讀取一個位元組的資料
static kal_uint8 fm2018_i2c_get_byte(kal_uint8 ack)
{
kal_uint8 get_byte=0;
signed char i;
kal_uint32 j;
FM2018_I2C_CLK_LOW; //時鐘線拉低
FM2018_I2C_DATA_INPUT; //資料線設定為輸入模式
while(!FM2018_I2C_CLK_BIT) //判斷時鐘線狀態
FM2018_I2C_CLK_HIGH; //時鐘線拉高
for (i=7; i>=0; i--) //讀取8個位(1個位元組)
{ /* data bit 7~0 */
for(j=0;j<FM2018_I2C_DELAY;j++); //延時
FM2018_I2C_CLK_HIGH; //時鐘線拉高
for(j=0;j<FM2018_I2C_DELAY;j++); //延時
if (FM2018_I2C_DATA_BIT) //判斷資料位狀態
get_byte |= (1<<i); //將對應資料位狀態儲存到變數中
for(j=0;j<FM2018_I2C_DELAY;j++); //延時
FM2018_I2C_CLK_LOW; //時鐘線拉低
}
if(ack)
{
FM2018_I2C_ACK_BIT; //應答位設定為有應答
}
else
{
FM2018_I2C_NACK_BIT; //應答位設定為無應答
tr_debug("\r\n FM2018_I2C_NACK_BIT");
}
return get_byte;
}
I2C寫入資料
寫入流程圖及程式碼
kal_uint8 fm2018_i2c_write(kal_uint8 address_high, kal_uint8 address_low, kal_uint8 data_high, kal_uint8 data_low)
{
kal_uint16 i=0;
kal_uint8 device_id = 0xC0; //FM2018的裝置ID為"0xC0"
kal_uint8 sync_bit1 = 0xFC; //同步高位元組
kal_uint8 sync_bit2 = 0xF3; //同步低位元組
kal_uint8 command_start = 0x3B; //命令啟動,寫入記憶體(mem_write)
//start condition
FM2018_I2C_START_TRANSMISSION; //I2C開始傳輸
//write addr
fm2018_i2c_send_byte(device_id); //傳送裝置地址位元組
fm2018_i2c_send_byte(sync_bit1); //傳送同步高位元組
fm2018_i2c_send_byte(sync_bit2); //傳送同步低位元組
fm2018_i2c_send_byte(command_start); //傳送命令位元組(0x3B)
//write reg addr
fm2018_i2c_send_byte(address_high); //傳送暫存器地址高位元組
fm2018_i2c_send_byte(address_low); //傳送暫存器地址低位元組
//write data
fm2018_i2c_send_byte(data_high); //傳送資料高位元組
fm2018_i2c_send_byte(data_low); //傳送資料低位元組
//stop condition
FM2018_I2C_STOP_TRANSMISSION; //I2C停止傳輸
return KAL_SUCCESS;
}
#I2C讀取資料 讀取流程圖及程式碼
kal_uint8 fm2018_i2c_read(kal_uint8 address_high, kal_uint8 address_low, kal_uint8 *pData, kal_uint8 datasize)
{
kal_uint16 i=0;
kal_uint8 device_id = 0xC0; //FM2018的裝置ID為"0xC0"
kal_uint8 sync_bit1 = 0xFC; //同步高位元組
kal_uint8 sync_bit2 = 0xF3; //同步低位元組
kal_uint8 command_start = 0x37; //命令啟動,讀取記憶體(mem_read)
//start condition
FM2018_I2C_START_TRANSMISSION; //I2C開始傳輸
//write addr
fm2018_i2c_send_byte(device_id); //傳送裝置地址位元組
fm2018_i2c_send_byte(sync_bit1); //傳送同步高位元組
fm2018_i2c_send_byte(sync_bit2); //傳送同步低位元組
fm2018_i2c_send_byte(command_start); //傳送命令位元組(0x37)
fm2018_i2c_send_byte(address_high); //傳送暫存器地址高位元組
fm2018_i2c_send_byte(address_low); //傳送暫存器地址低位元組
FM2018_I2C_STOP_TRANSMISSION; //I2C停止傳輸
//0X25
//start condition
FM2018_I2C_START_TRANSMISSION; //I2C開始傳輸
fm2018_i2c_send_byte(device_id); //傳送裝置地址位元組
fm2018_i2c_send_byte(sync_bit1); //傳送同步高位元組
fm2018_i2c_send_byte(sync_bit2); //傳送同步低位元組
command_start = 0x60;
fm2018_i2c_send_byte(command_start); //傳送命令位元組(0x60)(reg_read)
fm2018_i2c_send_byte(0x25); //傳送資料埠實體地址低位元組(0x25)
FM2018_I2C_STOP_TRANSMISSION; //I2C停止傳輸
FM2018_I2C_START_TRANSMISSION; //I2C開始傳輸
//read data
fm2018_i2c_send_byte(0xC1); //可能是告訴FM2018即將需要讀取一個位元組的資料
*pData = fm2018_i2c_get_byte(0); //讀取一個位元組的資料(這裡讀取低地址0x25內的資料)
//其中這裡的引數0表示無應答,從機停止傳輸,等待主機的停止訊號,若設定為1有應答,從機收到主機的應答訊號之後,從機繼續輸出下一位元組
tr_debug("fm2018_i2c_read fm2018_i2c_get_byte(0x25) = %x",*pData);
i++;
//0X26
//start condition
FM2018_I2C_START_TRANSMISSION; //I2C開始傳輸
fm2018_i2c_send_byte(device_id); //傳送裝置地址位元組
fm2018_i2c_send_byte(sync_bit1); //傳送同步高位元組
fm2018_i2c_send_byte(sync_bit2); //傳送同步低位元組
command_start = 0x60;
fm2018_i2c_send_byte(command_start); //傳送命令位元組(0x60)(reg_read)
fm2018_i2c_send_byte(0x26); //傳送資料埠實體地址高位元組(0x26)
FM2018_I2C_STOP_TRANSMISSION; //I2C停止傳輸
FM2018_I2C_START_TRANSMISSION; //I2C開始傳輸
//read data
fm2018_i2c_send_byte(0xC1); //可能是告訴FM2018即將需要讀取一個位元組的資料
*pData = fm2018_i2c_get_byte(0); //讀取一個位元組的資料(這裡讀取低地址0x26內的資料)
//其中這裡的引數0表示無應答,從機停止傳輸,等待主機的停止訊號,若設定為1有應答,從機收到主機的應答訊號之後,從機繼續輸出下一位元組
tr_debug("fm2018_i2c_read fm2018_i2c_get_byte(0x26) = %x",*pData);
i++;
datasize = i; //計數一共讀取了多少位元組的資料
//stop condition
FM2018_I2C_STOP_TRANSMISSION; //I2C停止傳輸
return KAL_SUCCESS;
}
針對裝置地址與同步位的規定,由晶片自身決定,參見下圖:
針對程式中的不同的命令位元組,是由由晶片自身特性決定的。詳見下圖: