CH32V203 I2C DMA問題

我用I2C2 DMA讀取從機寄存器,問什么總是比我要讀取的多了一個字節(jié)?

icon_rar.gifI2C2_DMA.zip

我代碼里寫了DMA?bufsize是1,但邏輯分析儀看到的是讀回來兩個字節(jié),請幫忙看看是哪里配置出錯了么?

? ? logan_DMA_I2C2_RX_Init((u32)RxData,1);

? ? logan_i2c2_rx(0x5b, 0x12);

image.png

這是由于沒有提前關閉I2C的自動應答ACK造成的。DMA配置的長度只決定DMA會從I2C外設搬運幾個數(shù)據(jù),而I2C接收多少數(shù)據(jù)是由I2C邏輯控制的。瀏覽代碼發(fā)現(xiàn)I2C接收第一個字節(jié)前并未關閉自動應答ACK。這就造成從機收到主機的ACK從而認為主機需要再讀1字節(jié)而繼續(xù)發(fā)送,主機無法發(fā)出停止條件。

根據(jù)CH32FV2x_V3xRM的275頁所述:

“在接收模式時,主設備需要在最后一個數(shù)據(jù)位的應答位置 NAK,接收到 NACK 后,從設備釋放對 SCL 和 SDA 線的控制”

故對于只讀1字節(jié)的情況,需要在讀取之前關閉自動應答ACK。對于只讀取1字節(jié)的情況,代碼應如下修改:

while(?!I2C_CheckEvent(?I2C2,?I2C_EVENT_MASTER_RECEIVER_MODE_SELECTED?)?);?//?原有代碼
I2C_AcknowledgeConfig(?I2C2,?DISABLE?);?//?新增代碼,提前關閉自動應答ACK
DMA_Cmd(?DMA1_Channel5,?ENABLE?);?//?原有代碼

而對于讀取2字節(jié)或更多的情況,自動應答ACK應等到還剩1字節(jié)待讀取時再關閉。


另外附上一個X035系列I2C邏輯的狀態(tài)機實現(xiàn)代碼,樓主可以參考:(鏈接會直接跳轉到讀時序的接收階段,可以看到若只剩1字節(jié)需要接收時,程序中關閉自動應答ACK的功能)

https://github.com/WuxiProject-offical/CH32X035-HelperLibrary/blob/main/I2C/Master/i2c.c#L617


灰常感謝,那如果用DMA的話有什么方法可以處理這個“BUG”,總不能去一直循環(huán)查詢還剩多少個數(shù)據(jù)吧?


我用某業(yè)內主流32位MCU時遇到類似的問題,我的策略是DMA長度比需要讀取的長度少一個,在DMA的傳輸完成中斷里關閉自動應答ACK,然后最后一字節(jié)用中斷接收;如果只讀1字節(jié),直接用中斷讀取而不開DMA。

但V203上,似乎可以卡bug做一個非常騷的操作,即直接設置DMA長度為比需要讀取的長度少一個,不在DMA傳輸完成中斷里添加代碼。按你的測試現(xiàn)象來看,如果最后一個字節(jié)沒有被DMA取走,主機會自動發(fā)NACK并結束通信?但這一行為我不確定是否可靠,建議等周一官方工作人員回復下。


我在手冊里看到這樣一個寄存器,是解決這個問題的,如下圖。


初始化的時候加上這一句就行了 I2C_DMALastTransferCmd(I2C2,ENABLE);

image.png


如果最后一個字節(jié)沒有被DMA取走,主機會自動發(fā)NACK并結束通信?” 我在DMA完成中斷里發(fā)送了STOP。


解決了上述問題,依然有兩個BUG,幫忙看看是哪里的問題:

1.紅色圈的地方,邏輯分析儀可以看到接受了4個數(shù)據(jù),但print接受數(shù)字時,第一個字節(jié)沒有正確輸出。

2.紫色圈出來的位置,從邏輯分析儀看發(fā)送了5個字節(jié)(包括寄存器),但程序里TX的長度寫成6才能正確發(fā)送4個字節(jié)。

icon_rar.gifI2C2_DMA.zip

附件是代碼。

1.jpg


1.紅色圈的地方,邏輯分析儀可以看到接受了4個數(shù)據(jù),但print接受數(shù)字時,第一個字節(jié)沒有正確輸出。

針對這個問題如下代碼中加了一個延時解決了,但不明白為什么會這樣,如果不加延時該怎么處理?

void logan_i2c2_rx(u16 slave_add, u16 reg)

{


? ? while( I2C_GetFlagStatus( I2C2, I2C_FLAG_BUSY ) != RESET );

? ? I2C_GenerateSTART( I2C2, ENABLE);


? ? while( !I2C_CheckEvent( I2C2, I2C_EVENT_MASTER_MODE_SELECT ) );

? ? logan_send_addr( I2C2, slave_add, I2C_Direction_Transmitter);


? ? while( !I2C_CheckEvent( I2C2, I2C_EVENT_MASTER_TRANSMITTER_MODE_SELECTED ) );


#if (Address_Lenth? == Address_8bit)

? ? I2C_SendData( I2C2, (u8) (reg & 0x00FF));

? ? while( !I2C_CheckEvent( I2C2, I2C_EVENT_MASTER_BYTE_TRANSMITTED ) );


#elif (Address_Lenth? == Address_16bit)

? ? I2C_SendData( I2C1, (u8)(reg>>8) );

? ? while( !I2C_CheckEvent( I2C1, I2C_EVENT_MASTER_BYTE_TRANSMITTED ) );


? ? I2C_SendData( I2C1, (u8)(reg&0x00FF) );

? ? while( !I2C_CheckEvent( I2C1, I2C_EVENT_MASTER_BYTE_TRANSMITTED ) );


#endif


? ? I2C_GenerateSTART( I2C2, ENABLE);


? ? while( !I2C_CheckEvent( I2C2, I2C_EVENT_MASTER_MODE_SELECT ) );

? ? logan_send_addr( I2C2, slave_add, I2C_Direction_Receiver);


? ? while( !I2C_CheckEvent( I2C2, I2C_EVENT_MASTER_RECEIVER_MODE_SELECTED ) );

? ? Delay_Us(100);

? ? DMA_Cmd( DMA1_Channel5, ENABLE );


}




由于我手上并無V203的硬件,以下均為本人按照經驗所做的推測,請酌情參考。

對于問題1,我沒有什么頭緒,不確定是否與問題2有關,建議只保留讀取邏輯再次測試。

對于問題2,我個人認為是因為DMA發(fā)出最后一字節(jié)后,該字節(jié)數(shù)據(jù)剛剛裝入I2C數(shù)據(jù)寄存器還未來得及發(fā)送,DMA就因數(shù)據(jù)已全部傳輸完畢而觸發(fā)TC中斷,而程序中TC中斷立即發(fā)出了STOP信號,故I2C外設未來得及發(fā)出該字節(jié)即產生了停止序列。故,可在只寫入目標器件的操作時,在DMA傳輸完畢的中斷內開啟I2C的BTF中斷,并在I2C的BTF中斷內再發(fā)出STOP信號。



您好,@雷龍飛-Logan.lei,麻煩具體說明一下你的程序如何測試使用,我這邊打開你的程序發(fā)現(xiàn)沒有做主從的區(qū)分,下載到測試板邏輯分析儀并沒有采到波形,在收發(fā)通信時需要把另外收發(fā)代碼注釋掉么??梢愿遥╨zs@wch.cn)描述一下使用方法,我這邊具體測試一下?;蛭覀僔203 EVT有IIC DMA收發(fā)的例程,你也可以參考一下。


不用注釋掉,我是CH32V203做主機,通過I2C2(PB10,PB11)對從機AW9523BTQR進行讀寫的。


您好,附件是修改后的例程,關于發(fā)送長度以及接收問題這邊測試修改后是沒有問題的,如下圖。由于沒有你所說的從機模塊。例程是基于對EEPROM的讀寫測試的,所以對設備地址進行了修改。你拿回去測試時注意地址要改過來。

icon_rar.gifI2C2_DMA.zip

image.png


問題一。 打印讀取到的I2C數(shù)據(jù)時, 第一個數(shù)據(jù)丟失。是因為DMA還沒有傳輸完成??梢栽谠O置標志位等傳輸完成在打印。


I2C狀態(tài)轉換,全放在中斷里面進行。

I2C DMA主機模式測試沒問題 。從機 MP4247可以正常通訊 。

I2C DMA從機模式不完整未測試。

大佬們可以優(yōu)化一下。我這寫的有點爛。


#define I2C_OUTTIME 70000


uint8_t i2cDataTx[Size] = { 0 };

uint8_t i2cDataRx[Size];


void I2C1_EV_IRQHandler(void) __attribute__((interrupt("WCH-Interrupt-fast")));

void DMA1_Channel7_IRQHandler(void) __attribute__((interrupt("WCH-Interrupt-fast")));

//void DMA1_Channel6_IRQHandler(void) __attribute__((interrupt("WCH-Interrupt-fast")));

void I2C1_ER_IRQHandler(void)? __attribute__((interrupt("WCH-Interrupt-fast")));


//波特率? 本機地址 (1

void IIC_Init(u32 bound, uint8_t myadr)

{

? ? GPIO_InitTypeDef GPIO_InitStructure={0};

? ? I2C_InitTypeDef I2C_InitTSturcture={0};


? ? RCC_APB2PeriphClockCmd( RCC_APB2Periph_GPIOB, ENABLE );

? ? RCC_APB1PeriphClockCmd( RCC_APB1Periph_I2C1, ENABLE );

? ? RCC_AHBPeriphClockCmd( RCC_AHBPeriph_DMA1, ENABLE );


? ? GPIO_InitStructure.GPIO_Pin = GPIO_Pin_6;

? ? GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_OD;

? ? GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;

? ? GPIO_Init( GPIOB, &GPIO_InitStructure );


? ? GPIO_InitStructure.GPIO_Pin = GPIO_Pin_7;

? ? GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_OD;

? ? GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;

? ? GPIO_Init( GPIOB, &GPIO_InitStructure );


? ? I2C_InitTSturcture.I2C_ClockSpeed = bound;

? ? I2C_InitTSturcture.I2C_Mode = I2C_Mode_I2C;

? ? I2C_InitTSturcture.I2C_DutyCycle = I2C_DutyCycle_2;

? ? I2C_InitTSturcture.I2C_OwnAddress1 = myadr?myadr<<1:MYAdderss<<1;

? ? I2C_InitTSturcture.I2C_Ack = I2C_Ack_Enable;

? ? I2C_InitTSturcture.I2C_AcknowledgedAddress = I2C_AcknowledgedAddress_7bit;

? ? I2C_Init( I2C1, &I2C_InitTSturcture );


? ? DMA_InitTypeDef DMA_InitStructure={0};

? ? DMA_DeInit(DMA1_Channel7);


? ? DMA_InitStructure.DMA_PeripheralBaseAddr = ( u32 )&I2C1->DATAR;

? ? DMA_InitStructure.DMA_MemoryBaseAddr = ( u32)&i2cDataRx;

? ? DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralSRC;

? ? DMA_InitStructure.DMA_BufferSize = Size;

? ? DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable;

? ? DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable;

? ? DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_Byte;

? ? DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_Byte;

? ? DMA_InitStructure.DMA_Mode = DMA_Mode_Normal;

? ? DMA_InitStructure.DMA_Priority = DMA_Priority_High;

? ? DMA_InitStructure.DMA_M2M = DMA_M2M_Disable;

? ? DMA_Init(DMA1_Channel7, &DMA_InitStructure );


? ? DMA_DeInit(DMA1_Channel6);

? ? DMA_InitStructure.DMA_PeripheralBaseAddr = ( u32 )&I2C1->DATAR;

? ? DMA_InitStructure.DMA_MemoryBaseAddr =( u32)&i2cDataTx;

? ? DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralDST;

? ? DMA_InitStructure.DMA_BufferSize = Tize;

? ? DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable;

? ? DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable;

? ? DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_Byte;

? ? DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_Byte;

? ? DMA_InitStructure.DMA_Mode = DMA_Mode_Normal;

? ? DMA_InitStructure.DMA_Priority = DMA_Priority_VeryHigh;//DMA_Priority_High;DMA_Priority_VeryHigh

? ? DMA_InitStructure.DMA_M2M = DMA_M2M_Disable;

? ? DMA_Init( DMA1_Channel6, &DMA_InitStructure );


? ? I2C_DMACmd( I2C1, ENABLE );


? ? NVIC_InitTypeDef? NVIC_InitStructure = {0};

? ? NVIC_InitStructure.NVIC_IRQChannel = I2C1_EV_IRQn;//事件中斷

? ? NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 1;

? ? NVIC_InitStructure.NVIC_IRQChannelSubPriority = 5;

? ? NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;

? ? NVIC_Init(&NVIC_InitStructure);


? ? NVIC_InitStructure.NVIC_IRQChannel = DMA1_Channel7_IRQn;

? ? NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 2;

? ? NVIC_InitStructure.NVIC_IRQChannelSubPriority = 2;

//? ? NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;

? ? NVIC_Init(&NVIC_InitStructure);


//? ? NVIC_InitStructure.NVIC_IRQChannel = DMA1_Channel6_IRQn;



? ? NVIC_InitStructure.NVIC_IRQChannel = I2C1_ER_IRQn;//錯誤中斷

? ? NVIC_InitStructure.NVIC_IRQChannelSubPriority = 7;? ? ? ? ? ? ? ? ?//從優(yōu)先級

? ? NVIC_Init(&NVIC_InitStructure);


//? ? DMA_ITConfig(DMA1_Channel7, DMA1_IT_TC1, ENABLE);

? ? DMA1_Channel7->CFGR|=0x0002;//接收完成中斷

//? ? DMA1_Channel6->CFGR|=0x0002;//發(fā)送完成中斷

? ? I2C_ITConfig(I2C1, I2C_IT_EVT, ENABLE);//I2C_IT_EVT 開啟事件中斷 I? 2C_IT_BUF|接收發(fā)送緩沖器中斷? I2C_IT_ERR 錯誤中斷

? ? if(myadr)

? ? {

? ? ? ? I2C_GeneralCallCmd(I2C1,ENABLE);//響應廣播

? ? }


? ? I2C_Cmd( I2C1, ENABLE );


//? ? I2C_AcknowledgeConfig( I2C1, ENABLE );

? ? Rst_i2c_salve();

}



uint8_t I2C_READ_REG8(uint8_t addr, uint8_t reg, uint8_t* rbuf, uint16_t rsize)

{

//[狀態(tài)(bit7 1寫讀數(shù)據(jù) 0僅寫數(shù)據(jù) 其他位為狀態(tài)指示),發(fā)送數(shù)據(jù)尺寸H,發(fā)送數(shù)據(jù)尺寸L,讀取數(shù)據(jù)尺寸H,讀取數(shù)據(jù)尺寸L,發(fā)送地址? ?,(寫寄存器|讀寄存器|指令|數(shù)據(jù)1),(數(shù)據(jù)2),...]

? ? static uint8_t data[6+2];


? ? uint32_t time_out=I2C_OUTTIME;

//? ? I2C1->CTLR1 |= (uint16_t)0x0001;

? ? while( I2C_GetFlagStatus( I2C1, I2C_FLAG_BUSY ) != RESET ) //等待I2C空閑

? ? {

? ? ? ? time_out--;

? ? ? ? if(time_out==0)

? ? ? ? {


? ? ? ? ? ? Rst_i2c_salve();


? ? ? ? ? ? return I2C_BUSY;

? ? ? ? }

? ? }

? ? data[0] = 0x80;//寫讀

? ? data[1] = 0;//發(fā)送數(shù)據(jù)字節(jié)數(shù) 高位

? ? data[2] = 1;//發(fā)送數(shù)據(jù)字節(jié)數(shù) 低位

? ? data[3] = (rsize>>8)&0xFF;//接收字節(jié)數(shù) 高位

? ? data[4] = rsize&0xFF;//接收字節(jié)數(shù) 低位

? ? data[5] = addr<<1;//從機地址

? ? data[6] = reg;//寫數(shù)據(jù)



? ? //DMA接收設置

? ? DMA1_Channel7->CFGR &= (uint16_t)(~DMA_CFGR1_EN);//關閉DMA指定通道

? ? DMA1_Channel7->CNTR = 0;

? ? DMA1_Channel7->MADDR = (uint32_t)(rbuf);

? ? //DMA發(fā)送設置

? ? DMA1_Channel6->CFGR &= (uint16_t)(~DMA_CFGR1_EN);//關閉DMA指定通道

? ? DMA1_Channel6->CNTR = 7;

? ? DMA1_Channel6->MADDR = (uint32_t)(data);

? ? I2C_GenerateSTART(I2C1, ENABLE);//轉換到主機模式? 發(fā)起起始條件成功 SB狀態(tài)置1? MSL狀態(tài)置1表明當前為主機模式

? ? time_out = I2C_OUTTIME;

? ? while( !I2C_CheckEvent( I2C1, I2C_EVENT_MASTER_BYTE_TRANSMITTED ))//等待傳輸完成 BTF=1 TXE=1? ?MSL=1 TRA=1 BUSY=1

? ? {

? ? ? ? time_out--;

? ? ? ? if(time_out==0)

? ? ? ? {

? ? ? ? ? ? Rst_i2c_salve();

? ? ? ? ? ? return I2C_ERROR;

? ? ? ? }

? ? }

? ? return 0;

}


uint8_t I2C_WRITE_REG8(uint8_t addr, uint8_t reg, uint8_t*wbuf, uint16_t wsize)

{

//[狀態(tài)(bit7 1寫讀數(shù)據(jù) 0僅寫數(shù)據(jù) 其他位為狀態(tài)指示),發(fā)送數(shù)據(jù)尺寸H,發(fā)送數(shù)據(jù)尺寸L,讀取數(shù)據(jù)尺寸H,讀取數(shù)據(jù)尺寸L,發(fā)送地址? ?,(寫寄存器|讀寄存器|指令|數(shù)據(jù)1),(數(shù)據(jù)2),...]

? ? static uint8_t data[6+8];

? ? uint32_t i;

? ? uint32_t time_out=I2C_OUTTIME;


? ? wsize=wsize+1;

//? ? I2C1->CTLR1 |= (uint16_t)0x0001;

? ? while( I2C_GetFlagStatus( I2C1, I2C_FLAG_BUSY ) != RESET ) //等待I2C空閑

? ? {

? ? ? ? time_out--;

? ? ? ? if(time_out==0)

? ? ? ? {

//? ? ? ? ? ? if(DMA1_Channel6->CNTR==0 && DMA1_Channel7->CNTR==0)

//? ? ? ? ? ? {

? ? ? ? ? ? Rst_i2c_salve();

//? ? ? ? ? ? }

? ? ? ? ? ? return I2C_BUSY;

? ? ? ? }

? ? }


? ? if(wsize>8)

? ? {

? ? ? ? return 8;

? ? }

? ? data[0] = 0x00;//僅寫


? ? data[1] = (wsize>>8)&0xFF;//發(fā)送數(shù)據(jù)字節(jié)數(shù) 高位

? ? data[2] = wsize&0xFF;//發(fā)送數(shù)據(jù)字節(jié)數(shù) 低位


? ? data[3] = 0;//接收字節(jié)數(shù) 高位

? ? data[4] = 0;//接收字節(jié)數(shù) 低位


? ? data[5] = addr<<1;//從機地址

? ? data[6] = reg;//從機寄存器地址或指令


? ? for (i = 0; i < wsize; ++i) {

? ? ? ? data[i+7] = wbuf[i];

? ? }



? ? DMA1_Channel6->CFGR &= (uint16_t)(~DMA_CFGR1_EN);//關閉DMA指定通道

? ? DMA1_Channel6->CNTR = wsize;

? ? DMA1_Channel6->MADDR = (uint32_t)(data);

? ? I2C_GenerateSTART(I2C1, ENABLE);


? ? return 0;

}


void I2C1_EV_IRQHandler(void)

{

? ? volatile uint32_t temp = 0;


? ? ///////////////DMA///////////////////

? ? static uint8_t *_status;

? ? volatile uint32_t temp1 = 0;

? ? volatile uint32_t temp2 = 0;


? ? temp1 = I2C1->STAR1;//讀狀態(tài)1寄存器

? ? temp2 = I2C1->STAR2;//讀狀態(tài)2寄存器

? ? temp2 = temp2<<16;

? ? temp = (temp1|temp2);


? ? if((temp&I2C_FLAG_MSL)==I2C_FLAG_MSL)//主機模式

? ? {

? ? ? ? if((temp&I2C_IT_SB))//起始條件已發(fā)出 開始發(fā)送從機地址

? ? ? ? {

? ? ? ? ? ? if(DMA1_Channel6->CNTR)//首次發(fā)送數(shù)據(jù) 更新保存 數(shù)據(jù)基址 讀從機寄存器操作(先寫指令再讀數(shù)據(jù))第二次起始條件發(fā)出時 不應該再觸發(fā)該處

? ? ? ? ? ? {

? ? ? ? ? ? ? ? _status = (uint8_t *)DMA1_Channel6->MADDR;

? ? ? ? ? ? ? ? GPIO_WriteBit(GPIOB, GPIO_Pin_2, 1);//LED1 藍色

? ? ? ? ? ? }


? ? ? ? ? ? I2C1->DATAR = _status[5];//bit0 0發(fā)送或讀取地址bit0 1 寫地址后會清除SB

? ? ? ? ? ? _status[0]=(_status[0]&0x80)|1;//更新狀態(tài) 發(fā)送地址

? ? ? ? ? ? GPIO_WriteBit(GPIOB, GPIO_Pin_14, 0);//LED2 綠色

? ? ? ? ? ? // GPIO_WriteBit(GPIOB, GPIO_Pin_15, 0);//LED3 紅燈


? ? ? ? }


//? ? ? ? ? ADDR 用戶讀取狀態(tài)寄存器 1 后,對狀態(tài)寄存器 2 的讀操作將會清除此位

? ? ? ? if(temp&I2C_IT_ADDR)//從機地址匹配(應答) 開始寫或者讀數(shù)據(jù)

? ? ? ? {

? ? ? ? ? ? //開始DMA傳輸

? ? ? ? ? ? if(DMA1_Channel6->CNTR)//發(fā)送

? ? ? ? ? ? {

//? ? ? ? ? ? ? ? [狀態(tài)(bit7 1寫讀數(shù)據(jù) 0僅寫數(shù)據(jù) 其他位為狀態(tài)指示),發(fā)送數(shù)據(jù)尺寸H,發(fā)送數(shù)據(jù)尺寸L,讀取數(shù)據(jù)尺寸H,讀取數(shù)據(jù)尺寸L,發(fā)送地址,(寫寄存器|讀寄存器|指令|數(shù)據(jù)1),(數(shù)據(jù)2),...]

? ? ? ? ? ? ? ? DMA1_Channel6->CFGR &= (uint16_t)(~DMA_CFGR1_EN);//關閉DMA指定通道


? ? ? ? ? ? ? ? if((_status[0]&0x80))//寫讀

? ? ? ? ? ? ? ? {

? ? ? ? ? ? ? ? ? ? _status[5] = _status[5]|0x0001;//轉換為讀地址

? ? ? ? ? ? ? ? ? ? _status[0] = (_status[0]&0x80)|2;//更新狀態(tài)為讀 等待數(shù)據(jù)傳輸完成

? ? ? ? ? ? ? ? ? ? DMA1_Channel7->CNTR = (_status[3]<<8)|_status[4];

? ? ? ? ? ? ? ? ? ? GPIO_WriteBit(GPIOB, GPIO_Pin_2, 0);//LED1 藍色



? ? ? ? ? ? ? ? }else {//僅寫

? ? ? ? ? ? ? ? ? ? _status[0]=(_status[0]&0x80)|3;//更新狀態(tài)為僅寫? 等待數(shù)據(jù)傳輸完成


? ? ? ? ? ? ? ? }

? ? ? ? ? ? ? ? DMA1_Channel6->CNTR = (_status[1]<<8)|_status[2];

? ? ? ? ? ? ? ? DMA1_Channel6->MADDR = (uint32_t)(_status+6);

? ? ? ? ? ? ? ? DMA1_Channel6->CFGR |= DMA_CFGR1_EN;//開啟DMA指定通道


? ? ? ? ? ? }else if(DMA1_Channel7->CNTR)//接收

? ? ? ? ? ? {

? ? ? ? ? ? ? ? DMA1_Channel6->CFGR &= (uint16_t)(~DMA_CFGR1_EN);//關閉DMA指定通道

//? ? ? ? ? ? ? ? I2C1->CTLR1 = ((uint16_t)0x0401);//開啟應答

? ? ? ? ? ? ? ? I2C1->CTLR1 |= ((uint16_t)0x0400);//開啟應答

? ? ? ? ? ? ? ? I2C1->CTLR2 |= ((uint16_t)0x1000);//主機接收時 DMA傳輸 最后一位NACK DMA接收不觸發(fā)BTF 需要開啟DMA傳輸完成中斷處理發(fā)送停止事件

? ? ? ? ? ? ? ? DMA1_Channel7->CFGR |= DMA_CFGR1_EN;//開啟DMA指定通道

? ? ? ? ? ? ? ? _status[0]=(_status[0]&0x80)|4;

? ? ? ? ? ? }

? ? ? ? }



//? ? ? ? BTF字節(jié)發(fā)送結束標志位,用戶讀取狀態(tài)寄存器 1后,對數(shù)據(jù)寄存器的讀寫將清除此位;

? ? ? ? if(temp&I2C_IT_BTF)//數(shù)據(jù)傳輸完成 ->? 一個數(shù)據(jù)傳輸完成 (硬件延時超時) (發(fā)送 數(shù)據(jù)寄存器空) (接收 數(shù)據(jù)寄存器有數(shù)據(jù)未被讀取)觸發(fā)完成事件

? ? ? ? {

? ? ? ? ? ? (void)I2C1->DATAR;


? ? ? ? ? ? switch (_status[0]&0x7F) {

? ? ? ? ? ? ? ? case 1://地址發(fā)送完成 等待地址匹配 在此不做任何事情

? ? ? ? ? ? ? ? ? ? break;

? ? ? ? ? ? ? ? case 2://寫讀數(shù)據(jù)狀態(tài) 開始讀

? ? ? ? ? ? ? ? ? ? DMA1_Channel7->CFGR &= (uint16_t)(~DMA_CFGR1_EN);//關閉DMA指定通道

//? ? ? ? ? ? ? ? ? ? I2C1->CTLR1 = ((uint16_t)0x0101);//再次發(fā)出開始信號 準備讀取

? ? ? ? ? ? ? ? ? ? I2C1->CTLR1 |= ((uint16_t)0x0100);//再次發(fā)出開始信號 準備讀取

? ? ? ? ? ? ? ? ? ? DMA1_Channel6->CNTR = (_status[3]<<8)|_status[4];//讀取長度

? ? ? ? ? ? ? ? ? ? _status[0]=(_status[0]&0x80)|4;

? ? ? ? ? ? ? ? ? ? break;

? ? ? ? ? ? ? ? case 3://僅寫數(shù)據(jù)? ?完成

? ? ? ? ? ? ? ? ? ? _status[0]=(_status[0]&0x80)|4;

//? ? ? ? ? ? ? ? ? ? GPIO_WriteBit(GPIOB, GPIO_Pin_2, 1);//LED1 藍色

? ? ? ? ? ? ? ? case 4:// 讀寫完成


//? ? ? ? ? ? ? ? ? ? ?I2C1->CTLR1 = ((uint16_t)0x0201);

? ? ? ? ? ? ? ? ? ? ?I2C1->CTLR1 ^=((uint16_t)0x0400);// 取消應答

? ? ? ? ? ? ? ? ? ? ?I2C1->CTLR1 |= ((uint16_t)0x0200);// 發(fā)起停止事件 轉變?yōu)閺臋C模式

? ? ? ? ? ? ? ? ? ? ?_status[0]=(_status[0]&0x80)|5;

? ? ? ? ? ? ? ? ? ? ?DMA1_Channel6->CFGR &= (uint16_t)(~DMA_CFGR1_EN);//關閉DMA指定通道

? ? ? ? ? ? ? ? ? ? ?DMA1_Channel6->CNTR = 0;

//? ? ? ? ? ? ? ? ? ? ?DMA1_Channel7->CFGR &= (uint16_t)(~DMA_CFGR1_EN);//關閉DMA指定通道

//? ? ? ? ? ? ? ? ? ? ?if((_status[0]&0x7F)==4)GPIO_WriteBit(GPIOB, GPIO_Pin_14, 1);//LED2 綠燈

? ? ? ? ? ? ? ? ? ? break;

? ? ? ? ? ? ? ? default:

? ? ? ? ? ? ? ? ? ? break;

? ? ? ? ? ? }


? ? ? ? }



? ? }else {//從機模式 I2C_IT_ADDR? I2C_IT_BTF? I2C_IT_STOPF

//? ? ? ? if(temp&I2C_IT_BTF)

//? ? ? ? {

//

//? ? ? ? }

? ? ? ? if((temp&I2C_IT_STOPF)||(temp&I2C_IT_BTF))//從機檢測到停止事件 或 發(fā)送完成標志

? ? ? ? {

? ? ? ? ? ? DMA1_Channel6->CFGR &= (uint16_t)(~DMA_CFGR1_EN);//關閉DMA指定通道

? ? ? ? ? ? DMA1_Channel7->CFGR &= (uint16_t)(~DMA_CFGR1_EN);//關閉DMA指定通道

? ? ? ? }


? ? ? ? if(temp&I2C_IT_ADDR)

? ? ? ? {

? ? ? ? ? ? //主機請求數(shù)據(jù) 重復的起始條件、停止條件會清除 仲裁丟失、關閉I2C 該位硬件清零

? ? ? ? ? ? if(temp&I2C_FLAG_TRA)//主機請求數(shù)據(jù) 根據(jù)接收的值準備數(shù)據(jù)上傳

? ? ? ? ? ? {

? ? ? ? ? ? ? ? //從機 DMA發(fā)送數(shù)據(jù) 外部設置對應數(shù)據(jù)源

//? ? ? ? ? ? ? ?DMA1_Channel6->CFGR &= (uint16_t)(~DMA_CFGR1_EN);//關閉DMA指定通道

//? ? ? ? ? ? ? ?DMA1_Channel6->MADDR = ( u32)&i2cDataTx;

//? ? ? ? ? ? ? ?DMA1_Channel6->CNTR = Tize;

? ? ? ? ? ? ? ?DMA1_Channel6->CFGR |= DMA_CFGR1_EN;//開啟DMA指定通道

? ? ? ? ? ? }else//主機寫數(shù)據(jù) 從機接收

? ? ? ? ? ? {

? ? ? ? ? ? ? ? /* 準備接收數(shù)據(jù) 設置大一點的緩沖區(qū) */

? ? ? ? ? ? ? ? DMA1_Channel7->MADDR = ( u32)&i2cDataRx;

? ? ? ? ? ? ? ? DMA1_Channel7->CNTR = Size;

? ? ? ? ? ? ? ? DMA1_Channel7->CFGR |= DMA_CFGR1_EN;

? ? ? ? ? ? }

? ? ? ? }


? ? }

//////////////////DMA///////////////////


}


//SCL為高電平時,SDA由高變低表示起始信號;

//

//SCL為高電平時,SDA由低變高表示停止信號;

//

//起始信號和停止信號都是由主機發(fā)出,起始信號產生后總線處于占用狀態(tài),停止信號產生后總線被釋放,處于空閑狀態(tài)。


// 錯誤中斷

void I2C1_ER_IRQHandler(void)

{

? ? uint32_t temp = 0;


? ? I2C_GenerateSTOP(I2C1, ENABLE);

? ? DMA1_Channel6->CFGR &= (uint16_t)(~DMA_CFGR1_EN);//關閉DMA指定通道

? ? DMA1_Channel7->CFGR &= (uint16_t)(~DMA_CFGR1_EN);//關閉DMA指定通道

? ? temp = I2C1->STAR1;

? ? I2C_Cmd(I2C1, DISABLE);

? ? if(temp&0x0400)//應答錯誤

? ? {

? ? ? ? GPIO_WriteBit(GPIOB, GPIO_Pin_2, 0);//LED1 藍色

? ? }else if (temp&0x0100)//仲裁丟失

? ? {


? ? }else if (temp&0x4000)//超時

? ? {

? ? ? ? GPIO_WriteBit(GPIOB, GPIO_Pin_15, 1);//LED3 紅燈

? ? }else if (temp&0x0200)//過載? 禁止時鐘延長條件下

? ? {


? ? }else {


? ? }



? ? I2C_Cmd(I2C1, ENABLE);


}

//傳輸完成的回調函數(shù)

//extern void I2C_SlaveDMARxCpltCallback();


//I2C DMA接收

void DMA1_Channel7_IRQHandler(void)

{

? ? if(DMA_GetITStatus(DMA1_IT_TC7)==SET)

? ? {

? ? ? ? //? ? ? ? 從機 狀態(tài)下 應該解析更新數(shù)據(jù)

? ? ? ? //? ? ? ? I2C_SlaveDMARxCpltCallback();

? ? ? ? I2C1->CTLR1 ^=((uint16_t)0x0400);// 取消應答

? ? ? ? I2C1->CTLR1 |= ((uint16_t)0x0200);// 發(fā)起停止事件 轉換為從機模式? 靜默

? ? ? ? DMA1_Channel7->CFGR &= (uint16_t)(~DMA_CFGR1_EN);//關閉dma指定通道


? ? ? ? DMA_ClearITPendingBit(DMA1_IT_TC7);

? ? ? ? GPIO_WriteBit(GPIOB, GPIO_Pin_14, 1);//LED2 綠色


? ? }

}

//I2C DMA 發(fā)送完成

//void DMA1_Channel6_IRQHandler(void)

//{

//? ? if(DMA_GetITStatus(DMA1_IT_TC6)==SET)

//? ? {

//? ? ? ? DMA1_Channel6->CFGR &= (uint16_t)(~DMA_CFGR1_EN);//關閉dma指定通道

//? ? ? ? DMA_ClearITPendingBit(DMA1_IT_TC6);

//

//? ? }

//}




//主機模式 嘗試復位IIC

void Rst_i2c_salve()

{

? ? uint8_t n = 9;

//? ? GPIOB->CFGLR &= 0x00FFFFFF;// 復位

//? ? GPIOB->CFGLR |= (uint32_t)0x44000000;//輸入模式 PB6 PB7

//? ? printf("IDR:0x%08X? GPIOB:0x%08X\n",GPIOB->INDR,GPIOB->CFGLR);

? ? if((GPIOB->INDR&0x00000080)==0)//讀取SDA 總線 如果被拉低

? ? {

? ? ? ? I2C_GenerateSTART( I2C1, ENABLE );

? ? ? ? Delay_Ms(5);

? ? ? ? I2C_GenerateSTOP( I2C1, ENABLE );

? ? ? ? Delay_Ms(20);

? ? ? ? if((GPIOB->INDR&0x00000080))// SDA 為高 退出

? ? ? ? {

? ? ? ? ? ? return;

? ? ? ? }


? ? ? ? I2C_Cmd( I2C1, DISABLE );


? ? ? ? GPIOB->CFGLR &= 0x00FFFFFF;// 復位

//? ? ? ? GPIOB->CFGLR |= (uint32_t)0x33000000;//輸出模式 PB6 PB7 通用推挽輸出 50 MHz

? ? ? ? GPIOB->CFGLR |= (uint32_t)0x77000000;//輸出模式 PB6 PB7 通用開漏輸出 50 MHz

//? ? ? ? GPIOB->OUTDR |= 0x000000C0;

? ? ? ? while(n>0)//發(fā)送9個時鐘信號

? ? ? ? {

? ? ? ? ? ? GPIOB->OUTDR |= 0x00000040;//PB6 SCL 拉高

? ? ? ? ? ? Delay_Ms(5);

? ? ? ? ? ? GPIOB->OUTDR &= ~0x00000040;// SCL 拉低

? ? ? ? ? ? n--;

? ? ? ? ? ? if((GPIOB->INDR&0x00000080))// SDA 為高 退出

? ? ? ? ? ? {

? ? ? ? ? ? ? ? break;

? ? ? ? ? ? }

? ? ? ? }


//? ? ? ? GPIOB->OUTDR &= ~0x00000080; //PB7 SDA 拉低

//? ? ? ? GPIOB->OUTDR |= 0x00000040;//SCL 拉高

//? ? ? ? Delay_Ms(20);

//? ? ? ? GPIOB->OUTDR |= 0x00000080; //PB7 SDA 拉高


? ? //? ? GPIOB->CFGLR &= 0x00FFFFFF;// 復位

? ? ? ? GPIOB->CFGLR |= 0xFF000000;// 復用 開漏輸出 50 MHz

? ? ? ? I2C1->STAR1 = 0;

? ? ? ? I2C1->STAR2 = 0;

? ? ? ? I2C_Cmd( I2C1, ENABLE );

? ? }else if ((GPIOB->INDR&0x00000040)==0){//SCL 總線被拉低 嘗試 恢復

? ? ? ? I2C_GenerateSTOP( I2C1, ENABLE );

? ? ? ? Delay_Ms(10);

? ? ? ? I2C_Cmd( I2C1, DISABLE );

? ? ? ? I2C1->STAR1 = 0;

? ? ? ? I2C1->STAR2 = 0;

? ? ? ? while((GPIOB->INDR&0x00000040)==0);//等待SCL總線 拉起

//? ? ? ? Delay_Ms(500);

? ? ? ? I2C_Cmd( I2C1, ENABLE );


? ? }else {

? ? ? ? I2C_Cmd( I2C1, DISABLE );

? ? ? ? I2C1->DATAR = 0;

? ? ? ? Delay_Ms(100);

? ? ? ? I2C_Cmd( I2C1, ENABLE );

? ? }

}



只有登錄才能回復,可以選擇微信賬號登錄

国产91精品新入口,国产成人综合网在线播放,九热这里只有精品,本道在线观看,美女视频a美女视频,韩国美女激情视频,日本美女pvp视频