Donker 0 12 марта, 2019 Опубликовано 12 марта, 2019 (изменено) · Жалоба Как отправить массив (uint8_t) по I2C через DMA на STM32F105RBT6 или STM32F030F4 используя CMSIS? Желательно сначала разобраться как это сделать на STM32F105RBT6 а потом перенести код на STM32F030F4. Сейчас я отправляю на STM32F105RBT6 без DMA буффер OLED экрана (SSD1306 128x32) таким образом: Спойлер //-------------------------------------------------------------------------------------------- RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE); //включаем тактирование GPIO_InitStructure.GPIO_Pin = GPIO_Pin_6 | GPIO_Pin_7; //6,7 I2C экрана GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_OD; //выход открытый коллектор GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; GPIO_Init(GPIOB, &GPIO_InitStructure); GPIOB->BSRR = GPIO_BSRR_BS6; //высокий уровень GPIOB->BSRR = GPIO_BSRR_BS7; //высокий уровень //-------------------------------------------------------------------------------------------- #define F_CPU 72000000UL #define NAME 0b01111000 //АДРЕС УСТРОЙСТВА НА ШИНЕ 0b01111000 = 0x78 #define DATS 0b01000000 //ПЕРЕДАЧА НЕСКОЛЬКИХ БАЙТ ДАННЫХ 0b01000000 = 0x40 #define DAT 0b11000000 //ПЕРЕДАЧА ОДНОГО БАЙТа ДАННЫХ 0b11000000 = 0xC0 uint8_t screen_buff[512]; //(128x32)/8 //-------------------------------------------------------------------------------------------- void I2C_init(void) { ////////////////////////////////////////////////////////////////////////////////////// RCC->APB1ENR |= RCC_APB1ENR_I2C1EN; //включаем тактирование I2C1 I2C1->CR2 &= ~I2C_CR2_FREQ; I2C1->CR2 |= 36; //частота APB1 в мгц I2C1->CCR &= ~I2C_CCR_CCR; I2C1->CCR |= 30; //частота SCL I2C1->CCR |= I2C_CCR_FS; //выбор режима SM Standart mode – 100КГц или FM Fast mode - 400КГц I2C1->TRISE = 12; //максимальное время нарастания импульса I2C1->CR1 |= I2C_CR1_PE; //включаем I2C1 ////////////////////////////////////////////////////////////////////////////////////// } void I2C_StartCondition(void) //СТАРТ { /////////////////////////////////////////////// I2C1->CR1 |= I2C_CR1_START; while (!(I2C1->SR1 & I2C_SR1_SB)){} (void) I2C1->SR1; /////////////////////////////////////////////// } void I2C_StopCondition(void) //СТОП { //////////////////////////////////////// while (!(I2C1->SR1 & I2C_SR1_BTF)){} I2C1->CR1 |= I2C_CR1_STOP; /////////////////////////////////////// } void I2C_SendByte(unsigned char data) { ////////////////////////////////////////////////////////////////////////////////////// I2C1->DR = data; while (0 == (I2C1->SR1 & I2C_SR1_TXE)){} ////////////////////////////////////////////////////////////////////////////////////// } void I2C_SendAddr(void) { ////////////////////////////////////////////////////////////////////////////////////// I2C1->DR = NAME; while (!(I2C1->SR1 & I2C_SR1_ADDR)){} (void) I2C1->SR1; (void) I2C1->SR2; ////////////////////////////////////////////////////////////////////////////////////// } void OLED_SendScreen(void) { ////////////////////////////////////////////////////////////////////////////////////// I2C_StartCondition(); I2C_SendAddr(); //посыл адреса+0 I2C_SendByte(DATS); for(unsigned int i=0; i<512; i++) { I2C_SendByte(screen_buff[i]); } I2C_StopCondition(); ////////////////////////////////////////////////////////////////////////////////////// } //-------------------------------------------------------------------------------------------- как сюда прикрутить DMA? Можно как то обойтись без функции I2C_SendAddr используя только I2C_SendByte (добавив адрес в начало массива) что бы не ждать пока отправиться байт адреса? Изменено 12 марта, 2019 пользователем Donker Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
dimka76 42 12 марта, 2019 Опубликовано 12 марта, 2019 · Жалоба Сделайте отправку по прераваниям. Или настройте прерывание по завершению отправки адреса, а в обработчике этого прерывания уже запускайте DMA на отправку данных. И Start Condition тоже в прерывание лучше перенести, а не ждать. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
Donker 0 12 марта, 2019 Опубликовано 12 марта, 2019 · Жалоба Я просто не пойму почему в версии проекта с ногодрыгом я отправлял абсолютно все байты, включая адрес, на экран одной функцией: Спойлер void I2C_SendByte(unsigned char data) //ПЕРЕДАЧА БАЙТА и АСК { ////////////////////////////////////////////////////////////////////////////////////// for(unsigned char k=8; k>0; k--) { if(data&(1<<(k-1))) { SCL_LOW; SDA_HI; _delay_us(1); //подобрать SCL_HI; _delay_us(1); //подобрать SCL_LOW; } else { SCL_LOW; SDA_LOW; _delay_us(1); //подобрать SCL_HI; _delay_us(1); //подобрать SCL_LOW; } } _delay_us(1); //подобрать //--------------ACK------------- SDA_HI; _delay_us(1); //подобрать SCL_HI; _delay_us(1); //подобрать //------------------------------ if(!SDA_inp) {SCL_LOW;} _delay_us(3); //подобрать ////////////////////////////////////////////////////////////////////////////////////// а в аппаратной версии, если попытаюсь вместо I2C_SendAddr использовать I2C_SendByte, адрес отправляется, экран нормально реагирует, но происходит бесконечное зависание на этапе ожидания бита подтверждения отправки байта: while (0 == (I2C1->SR1 & I2C_SR1_TXE)){} Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
Donker 0 13 марта, 2019 Опубликовано 13 марта, 2019 · Жалоба Что-то не работает моя переделка снипета от F0 Вот часть кода: Спойлер //-------------------------------------------------------------------------------------------- #define NAME 0b01111000 //АДРЕС УСТРОЙСТВА НА ШИНЕ 0b01111000 = 0x78 #define DATS 0b01000000 //ПЕРЕДАЧА НЕСКОЛЬКИХ БАЙТ ДАННЫХ 0b01000000 = 0x40 #define DAT 0b11000000 //ПЕРЕДАЧА ОДНОГО БАЙТа ДАННЫХ 0b11000000 = 0xC0 #define COM 0b10000000 //ПЕРЕДАЧА ОДНОГО БАЙТа КОМАНДЫ 0b10000000 = 0x80 uint8_t screen_buff[513]; //буффер экрана 512 байт ((128x32)/8) + самый первый байт для команды DATS //-------------------------------------------------------------------------------------------- void DMA_init(void) { //////////////////////////////////////////////////////////////////////// RCC->AHBENR |= RCC_AHBENR_DMA1EN; /* Enable the peripheral clock DMA1 */ /* DMA1 Channel4 I2C1_TX config */ /* Memory to peripheral */ /* 8-bit transfer */ DMA1_Channel4->CPAR = (uint32_t)&(I2C1->DR); //* (1) Peripheral address */ DMA1_Channel4->CPAR = (uint32_t)&(I2C1->TXDR); DMA1_Channel4->CMAR = (uint32_t)screen_buff; //* (2) Memory address */ DMA1_Channel4->CCR |= DMA_CCR4_MINC | DMA_CCR4_DIR; //* (3) Memory increment */ DMA1_Channel4->CCR |= DMA_CCR_MINC | DMA_CCR_DIR; //////////////////////////////////////////////////////////////////////// } void I2C_init(void) { ////////////////////////////////////////////////////////////////////////////////////// RCC->APB1ENR |= RCC_APB1ENR_I2C1EN; //включаем тактирование I2C1 I2C1->CR2 &= ~I2C_CR2_FREQ; I2C1->CR2 |= 36; //частота APB1 в мгц //36 I2C1->CCR &= ~I2C_CCR_CCR; I2C1->CCR |= 30; //частота SCL//34// I2C1->CCR |= I2C_CCR_FS; //выбор режима SM Standart mode – 100КГц или FM Fast mode - 400КГц I2C1->TRISE = 12; //максимальное время нарастания импульса //12 I2C1->CR1 |= I2C_CR1_PE; //включаем I2C1 //---------------------------------настройки для DMA-------------------------------------------------- I2C1->CR1 = I2C_CR1_PE | I2C_CR2_DMAEN; /* (2) Periph enable */ I2C1->CR2 = (512 << 16) | (NAME<<0); /* (3) Slave address = 0x5A, write transfer, 2 bytes to transmit, autoend */ //I2C_CR2_AUTOEND - это где брать? ////////////////////////////////////////////////////////////////////////////////////// } void OLED_SendScreen(void) { ////////////////////////////////////////////////////////////////////////////////////// //---------------------Посылка буфера экрана через без DMA(работает) ----------------- //I2C_StartCondition(); //I2C_SendAddr(); //I2C_SendByte(NAME); //посыл адреса+0 //for(unsigned int i=0; i<513; i++) // { // I2C_SendByte(screen_buff[i]); // } //I2C_StopCondition(); //---------------------Посылка буфера экрана через DMA(не работает) ------------------ //if((I2C1->ISR & I2C_ISR_TXE) == (I2C_ISR_TXE)) /* Check Tx empty */ /* start transmission with DMA */ DMA1_Channel4->CCR &=~ DMA_CCR4_EN; DMA1_Channel4->CNDTR = 513;/* Data size */ DMA1_Channel4->CCR |= DMA_CCR4_EN; I2C1->CR1 |= I2C_CR1_START; /* Go */ ////////////////////////////////////////////////////////////////////////////////////// } void OLED_init(void) //ИНИЦИАЛИЗАЦИЯ ДИСПЛЕЯ { ////////////////////////////////////////////////////////////////////////////////////// I2C_init(); DMA_init(); I2C_StartCondition(); I2C_SendAddr(); for(unsigned char k=0; k<31; k++) { I2C_SendByte(COM); I2C_SendByte(ini_mass[k]); } I2C_StopCondition(); screen_buff[0] = DATS; ////////////////////////////////////////////////////////////////////////////////////// } //-------------------------------------------------------------------------------------------- Если раскомментировать в функции OLED_SendScreen пересылку без DMA - тогда работает, если выполнить OLED_SendScreen в том виде как сейчас, в ЛА видно что происходит "условие старт", после чего линии лежат в нуле и ничего не передаётся. Снипет смотрел этот: Спойлер ** ****************************************************************************** * @file 03_CommunicationUsingDMA/main.c * @author MCD Application Team * @version V1.2.0 * @date 19-June-2015 * @brief This code example shows how to configure the GPIOs and I2C * in order to receive with slave and transmit with master. * =============================================================================== ##### MCU Resources ##### =============================================================================== - RCC - GPIO PB6(I2C1_SCL),PB7(I2C1_SDA),PB10(I2C2_SCL),PB11(I2C2_SDA),PA0,PC8,PC9 - I2C1 (slave), I2C2 (master) - EXTI =============================================================================== ##### How to use this example ##### =============================================================================== - this file must be inserted in a project containing the following files : o system_stm32f0xx.c, startup_stm32f072xb.s o stm32f0xx.h to get the register definitions o CMSIS files =============================================================================== ##### How to test this example ##### =============================================================================== - Plug wires between PB6/PB10 and PB7/PB11, 4K7 PU are already on the board. - Launch the program - Press the user button to initiate a transmit request by master then slave receivess a byte - The green and orange LEDs toggles if everything goes well * ****************************************************************************** * @attention * * <h2><center>© COPYRIGHT 2015 STMicroelectronics</center></h2> * * Licensed under MCD-ST Liberty SW License Agreement V2, (the "License"); * You may not use this file except in compliance with the License. * You may obtain a copy of the License at: * * http://www.st.com/software_license_agreement_liberty_v2 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * ****************************************************************************** */ /* Includes ------------------------------------------------------------------*/ #include "stm32f0xx.h" /** @addtogroup STM32F0_Snippets * @{ */ /* Private typedef -----------------------------------------------------------*/ /* Private define ------------------------------------------------------------*/ #define I2C1_OWN_ADDRESS (0x5A) #define I2C_CMD_TOGGLE_ORANGE (0x81) #define I2C_CMD_TOGGLE_GREEN (0x82) #define SIZE_OF_DATA (2) /* Private macro -------------------------------------------------------------*/ /* Private variables ---------------------------------------------------------*/ uint8_t datatosend[SIZE_OF_DATA]={I2C_CMD_TOGGLE_ORANGE,I2C_CMD_TOGGLE_GREEN}; uint8_t datatoreceive[SIZE_OF_DATA]; /* Private function prototypes -----------------------------------------------*/ void Configure_GPIO_LED(void); void Configure_GPIO_I2C1(void); void Configure_DMA_I2C1(void); void Configure_I2C1_Slave(void); void Configure_GPIO_I2C2(void); void Configure_DMA_I2C2(void); void Configure_I2C2_Master(void); void Configure_GPIO_Button(void); void Configure_EXTI(void); /* Private functions ---------------------------------------------------------*/ /** * @brief Main program. * @param None * @retval None */ int main(void) { /*!< At this stage the microcontroller clock setting is already configured, this is done through SystemInit() function which is called from startup file (startup_stm32f072xb.s) before to branch to application main. To reconfigure the default setting of SystemInit() function, refer to system_stm32f0xx.c file */ Configure_GPIO_LED(); Configure_GPIO_I2C1(); Configure_DMA_I2C1(); Configure_I2C1_Slave(); Configure_GPIO_I2C2(); Configure_DMA_I2C2(); Configure_I2C2_Master(); Configure_GPIO_Button(); Configure_EXTI(); /* Initiate I2C sequence in button IRQ handler */ /* Infinite loop */ while (1) { } } /** * @brief This function : - Enables GPIO clock - Configures the Green LED pin on GPIO PC9 - Configures the orange LED pin on GPIO PC8 * @param None * @retval None */ __INLINE void Configure_GPIO_LED(void) { /* Enable the peripheral clock of GPIOC */ RCC->AHBENR |= RCC_AHBENR_GPIOCEN; /* Select output mode (01) on PC8 and PC9 */ GPIOC->MODER = (GPIOC->MODER & ~(GPIO_MODER_MODER8 | GPIO_MODER_MODER9)) \ | (GPIO_MODER_MODER8_0 | GPIO_MODER_MODER9_0); } /** * @brief This function : - Enables GPIO clock - Configures the I2C1 pins on GPIO PB6 PB7 * @param None * @retval None */ __INLINE void Configure_GPIO_I2C1(void) { /* Enable the peripheral clock of GPIOB */ RCC->AHBENR |= RCC_AHBENR_GPIOBEN; /* (1) open drain for I2C signals */ /* (2) AF1 for I2C signals */ /* (3) Select AF mode (10) on PB6 and PB7 */ GPIOB->OTYPER |= GPIO_OTYPER_OT_6 | GPIO_OTYPER_OT_7; /* (1) */ GPIOB->AFR[0] = (GPIOB->AFR[0] & ~(GPIO_AFRL_AFRL6 | GPIO_AFRL_AFRL7)) \ | (1 << ( 6 * 4 )) | (1 << (7 * 4)); /* (2) */ GPIOB->MODER = (GPIOB->MODER & ~(GPIO_MODER_MODER6 | GPIO_MODER_MODER7)) \ | (GPIO_MODER_MODER6_1 | GPIO_MODER_MODER7_1); /* (3) */ } /** * @brief This function configures DMA for I2C1. * @param None * @retval None */ __INLINE void Configure_DMA_I2C1(void) { /* Enable the peripheral clock DMA1 */ RCC->AHBENR |= RCC_AHBENR_DMA1EN; /* DMA1 Channel2 I2C1_RX config */ /* (4) Peripheral address */ /* (5) Memory address */ /* (6) Data size */ /* (7) Memory increment */ /* Peripheral to memory*/ /* 8-bit transfer */ /* Transfer complete IT */ DMA1_Channel3->CPAR = (uint32_t)&(I2C1->RXDR); /* (4) */ DMA1_Channel3->CMAR = (uint32_t)datatoreceive; /* (5) */ DMA1_Channel3->CNDTR = SIZE_OF_DATA; /* (6) */ DMA1_Channel3->CCR |= DMA_CCR_MINC | DMA_CCR_TCIE | DMA_CCR_EN; /* (7) */ /* Configure IT */ /* (8) Set priority for DMA1_Channel2_3_IRQn */ /* (9) Enable DMA1_Channel2_3_IRQn */ NVIC_SetPriority(DMA1_Channel2_3_IRQn, 0); /* (8) */ NVIC_EnableIRQ(DMA1_Channel2_3_IRQn); /* (9) */ } /** * @brief This function configures I2C1, slave. * @param None * @retval None */ __INLINE void Configure_I2C1_Slave(void) { /* Configure RCC for I2C1 */ /* (1) Enable the peripheral clock I2C1 */ /* (2) Use SysClk for I2C CLK */ RCC->APB1ENR |= RCC_APB1ENR_I2C1EN; /* (1) */ RCC->CFGR3 |= RCC_CFGR3_I2C1SW; /* (2) */ /* Configure I2C1, slave */ /* (2) Timing register value is computed with the AN4235 xls file, fast Mode @400kHz with I2CCLK = 48MHz, rise time = 140ns, fall time = 40ns */ /* (3) Periph enable, receive DMA enable */ /* (4) 7-bit address = 0x5A */ /* (5) Enable own address 1 */ I2C1->TIMINGR = (uint32_t)0x00B00000; /* (2) */ I2C1->CR1 = I2C_CR1_PE | I2C_CR1_RXDMAEN | I2C_CR1_ADDRIE; /* (3) */ I2C1->OAR1 |= (uint32_t)(I2C1_OWN_ADDRESS << 1); /* (4) */ I2C1->OAR1 |= I2C_OAR1_OA1EN; /* (5) */ /* Configure IT */ /* (7) Set priority for I2C1_IRQn */ /* (8) Enable I2C1_IRQn */ NVIC_SetPriority(I2C1_IRQn, 0); /* (7) */ NVIC_EnableIRQ(I2C1_IRQn); /* (8) */ } /** * @brief This function : - Enables GPIO clock - Configures the I2C2 pins on GPIO PB10 PB11 * @param None * @retval None */ __INLINE void Configure_GPIO_I2C2(void) { /* Enable the peripheral clock of GPIOB */ RCC->AHBENR |= RCC_AHBENR_GPIOBEN; /* (1) Open drain for I2C signals */ /* (2) AF1 for I2C signals */ /* (3) Select AF mode (10) on PB10 and PB11 */ GPIOB->OTYPER |= GPIO_OTYPER_OT_10 | GPIO_OTYPER_OT_11; /* (1) */ GPIOB->AFR[1] = (GPIOB->AFR[1] &~ (GPIO_AFRH_AFRH2 | GPIO_AFRH_AFRH3)) \ | (1 << (2 * 4)) | (1 << (3 * 4)); /* (2) */ GPIOB->MODER = (GPIOB->MODER & ~(GPIO_MODER_MODER10 | GPIO_MODER_MODER11)) \ | (GPIO_MODER_MODER10_1 | GPIO_MODER_MODER11_1); /* (3) */ } /** * @brief This function configures DMA for I2C2. * @param None * @retval None */ __INLINE void Configure_DMA_I2C2(void) { /* Enable the peripheral clock DMA1 */ RCC->AHBENR |= RCC_AHBENR_DMA1EN; /* DMA1 Channel4 I2C2_TX config */ /* (1) Peripheral address */ /* (2) Memory address */ /* (3) Memory increment */ /* Memory to peripheral */ /* 8-bit transfer */ DMA1_Channel4->CPAR = (uint32_t)&(I2C2->TXDR); /* (1) */ DMA1_Channel4->CMAR = (uint32_t)datatosend; /* (2) */ DMA1_Channel4->CCR |= DMA_CCR_MINC | DMA_CCR_DIR; /* (3) */ } /** * @brief This function configures I2C2, master. * @param None * @retval None */ __INLINE void Configure_I2C2_Master(void) { /* Enable the peripheral clock I2C2 */ RCC->APB1ENR |= RCC_APB1ENR_I2C2EN; /* Configure I2C2, master */ /* (1) Timing register value is computed with the AN4235 xls file, fast Mode @400kHz with I2CCLK = 48MHz, rise time = 140ns, fall time = 40ns */ /* (2) Periph enable */ /* (3) Slave address = 0x5A, write transfer, 2 bytes to transmit, autoend */ I2C2->TIMINGR = (uint32_t)0x00B01A4B; /* (1) */ I2C2->CR1 = I2C_CR1_PE | I2C_CR1_TXDMAEN; /* (2) */ I2C2->CR2 = I2C_CR2_AUTOEND | (SIZE_OF_DATA << 16) | (I2C1_OWN_ADDRESS<<1); /* (3) */ } /** * @brief This function : - Enables GPIO clock - Configures the Push Button GPIO PA0 * @param None * @retval None */ __INLINE void Configure_GPIO_Button(void) { /* Enable the peripheral clock of GPIOA */ RCC->AHBENR |= RCC_AHBENR_GPIOAEN; /* Select mode */ /* Select input mode (00) on PA0 */ GPIOA->MODER = (GPIOA->MODER & ~(GPIO_MODER_MODER0)); } /** * @brief This function configures EXTI. * @param None * @retval None */ __INLINE void Configure_EXTI(void) { /* Configure Syscfg, exti and nvic for pushbutton PA0 */ /* (1) PA0 as source input */ /* (2) unmask port 0 */ /* (3) Rising edge */ /* (4) Set priority */ /* (5) Enable EXTI0_1_IRQn */ SYSCFG->EXTICR[0] = (SYSCFG->EXTICR[0] & ~SYSCFG_EXTICR1_EXTI0) | SYSCFG_EXTICR1_EXTI0_PA; /* (1) */ EXTI->IMR |= EXTI_IMR_MR0; /* (2) */ EXTI->RTSR |= EXTI_RTSR_TR0; /* (3) */ NVIC_SetPriority(EXTI0_1_IRQn, 0); /* (4) */ NVIC_EnableIRQ(EXTI0_1_IRQn); /* (5) */ } /******************************************************************************/ /* Cortex-M0 Processor Exceptions Handlers */ /******************************************************************************/ /** * @brief This function handles NMI exception. * @param None * @retval None */ void NMI_Handler(void) { } /** * @brief This function handles Hard Fault exception. * @param None * @retval None */ void HardFault_Handler(void) { /* Go to infinite loop when Hard Fault exception occurs */ while (1) { } } /** * @brief This function handles SVCall exception. * @param None * @retval None */ void SVC_Handler(void) { } /** * @brief This function handles PendSVC exception. * @param None * @retval None */ void PendSV_Handler(void) { } /** * @brief This function handles SysTick Handler. * @param None * @retval None */ void SysTick_Handler(void) { } /** * @brief This function handles EXTI 0 1 interrupt request. * @param None * @retval None */ void EXTI0_1_IRQHandler(void) { EXTI->PR |= 1; /* start I2C master transmission sequence */ if((I2C2->ISR & I2C_ISR_TXE) == (I2C_ISR_TXE)) /* Check Tx empty */ { // I2C2->TXDR = I2C_BYTE_TO_SEND; /* Byte to send */ //I2C2->CR2 |= I2C_CR2_START; /* Go */ /* start transmission with DMA */ DMA1_Channel4->CCR &=~ DMA_CCR_EN; DMA1_Channel4->CNDTR = SIZE_OF_DATA;/* Data size */ DMA1_Channel4->CCR |= DMA_CCR_EN; I2C2->CR2 |= I2C_CR2_START; /* Go */ } } /** * @brief This function handles I2C1 interrupt request. * @param None * @retval None */ void I2C1_IRQHandler(void) { uint32_t I2C_InterruptStatus = I2C1->ISR; /* Get interrupt status */ if((I2C_InterruptStatus & I2C_ISR_ADDR) == I2C_ISR_ADDR) { I2C1->ICR |= I2C_ICR_ADDRCF; /* Address match event */ } } /** * @brief This function handles DMA1 channel 2 and 3 interrupt request. * @param None * @retval None */ void DMA1_Channel2_3_IRQHandler(void) { if((DMA1->ISR & DMA_ISR_TCIF3) == DMA_ISR_TCIF3) { DMA1->IFCR |= DMA_IFCR_CTCIF3;/* Clear TC flag */ if(datatoreceive[0] == I2C_CMD_TOGGLE_ORANGE) { datatoreceive[0]=0; GPIOC->ODR ^= GPIO_ODR_8; /* Toggle orange LED */ } if(datatoreceive[1] == I2C_CMD_TOGGLE_GREEN) { datatoreceive[1]=0; GPIOC->ODR ^= GPIO_ODR_9; /* toggle green LED */ } DMA1_Channel3->CCR &=~ DMA_CCR_EN; DMA1_Channel3->CNDTR = SIZE_OF_DATA;/* Data size */ DMA1_Channel3->CCR |= DMA_CCR_EN; } else { NVIC_DisableIRQ(DMA1_Channel2_3_IRQn);/* Disable DMA1_Channel2_3_IRQn */ } } /** * @} */ /************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/ Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
Arlleex 131 13 марта, 2019 Опубликовано 13 марта, 2019 · Жалоба 21 час назад, Donker сказал: ...если попытаюсь вместо I2C_SendAddr использовать I2C_SendByte, адрес отправляется, экран нормально реагирует, но происходит бесконечное зависание на этапе ожидания бита подтверждения отправки байта: while (0 == (I2C1->SR1 & I2C_SR1_TXE)){} А Вы RM открывали хотя бы? Там же написано, какой флаг взведется после отправки адреса подчиненного, и это флаг - не TXE. Цитата void I2C_StartCondition(void) //СТАРТ { I2C1->CR1 |= I2C_CR1_START; while (!(I2C1->SR1 & I2C_SR1_SB)){} (void) I2C1->SR1; // зачем? Он итак прочитается в цикле выше } Цитата void I2C_SendAddr(void) { I2C1->DR = NAME; while (!(I2C1->SR1 & I2C_SR1_ADDR)){} // к моему первому вопросу (void) I2C1->SR1; // зачем? Он итак прочитается в цикле выше (void) I2C1->SR2; } 2 часа назад, Donker сказал: Если раскомментировать в функции OLED_SendScreen пересылку без DMA - тогда работает, если выполнить OLED_SendScreen в том виде как сейчас, в ЛА видно что происходит "условие старт", после чего линии лежат в нуле и ничего не передаётся. Опять смотрю и только убеждаюсь, что RM Вы даже не открывали Цитата void OLED_SendScreen(void) { DMA1_Channel4->CCR &=~ DMA_CCR4_EN; DMA1_Channel4->CNDTR = 513;/* Data size */ DMA1_Channel4->CCR |= DMA_CCR4_EN; I2C1->CR1 |= I2C_CR1_START; /* Go */ // дальше-то что? Думаете, тут DMA все дальше сам разрулит? Не-а. } Не забудьте, кстати, что, работая по DMA, разрешать прерывания по событиям TXE и RXNE уже нельзя, о чем можете также прочитать в RM. P.S. Приведу Вам упрощенный псевдокод работы с I2C через DMA, правда на STM32F4xx (вроде у всех линеек эти модули отличаются не сильно): void HW_I2CTransmitData(u8 *Buffer, u32 Size) { HW_DMASetup(Buffer, Size); HW_I2CGenerateStart(); } void ISR_I2C_HANDLER(void) { if(HW_I2CCheckSR(SB)) { HW_I2CSendAddress(HW_I2C_ADDRESS_ABONENT); return; } if(HW_I2CCheckSR(ADDR)) { HW_DMAEnable(); (void)HW_I2CCheckSR(TRA); } if(HW_I2CCheckSR(BTF)) { HW_I2CGenerateStop(); (void)HW_I2CReveiveData(); OS_EventGive(OS_I2C_TXEND_EVENT); } } void ISR_DMA_HANDLER(void) { if(HW_DMACheckErrors(&System.I2C.DMAErrors)) OS_EventGive(OS_I2C_TXEND_EVENT); } Думаю, комментарии не нужны, но если будут вопросы - задавайте. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
Сергей Борщ 119 13 марта, 2019 Опубликовано 13 марта, 2019 · Жалоба 59 минут назад, Arlleex сказал: (вроде у всех линеек эти модули отличаются не сильно) F0 и F4 отличаются радикально. Даже и не вспомню, какой из них более неудобный. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
Donker 0 13 марта, 2019 Опубликовано 13 марта, 2019 · Жалоба Arlleex спасибо, буду разбираться. Заметил что использую 4 канал, а надо 6. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
Donker 0 15 марта, 2019 Опубликовано 15 марта, 2019 · Жалоба Пока решил заняться STM32F030F4, для STM32F030F4 у меня работает только ногодрыг, не получается запустить аппаратный I2C, вот часть кода: Спойлер //-------------------------------------------------------------------------------------------- #define OLED_addr_127 0b00111100 //7-битный адрес OLED 0b01111000 = 0x78 //-------------------------------------------------------------------------------------------- RCC->AHBENR |= RCC_AHBENR_GPIOAEN; //включаем тактирование GPIOA->OTYPER |= GPIO_OTYPER_OT_9 | GPIO_OTYPER_OT_10; /* (1) Open drain for I2C signals */ GPIOA->AFR[1] = (GPIOA->AFR[1] &~ (GPIO_AFRH_AFRH1 | GPIO_AFRH_AFRH2)) | (0x01 << (1 * 4)) | (0x01 << (2 * 4)); /* (2) AF1 for I2C signals */ GPIOA->MODER = (GPIOA->MODER & ~(GPIO_MODER_MODER9 | GPIO_MODER_MODER10)) | (GPIO_MODER_MODER9_1 | GPIO_MODER_MODER10_1); /* (3) Select AF mode (10) on PA9 and PA10 */ //-------------------------------------------------------------------------------------------- void I2C_init(void) { RCC->APB1ENR |= RCC_APB1ENR_I2C1EN; /* Enable the peripheral clock I2C2 */ RCC->CFGR3 |= RCC_CFGR3_I2C1SW; /* Configure I2C2, master */ /* (1) Timing register value is computed with the AN4235 xls file, fast Mode @400kHz with I2CCLK = 48MHz, rise time = 140ns, fall time = 40ns */ /* (2) Periph enable */ /* (3) Slave address = 0x5A, write transfer, 1 byte to transmit, autoend */ I2C1->TIMINGR = (uint32_t)0x00B01A4B; /* (1) */ I2C1->CR1 = I2C_CR1_PE; /* (2) */ I2C1->CR2 = I2C_CR2_AUTOEND | (1<<16) | (OLED_addr_127<<1); /* (3) */ } //-------------------------------------------------------------------------------------------- void I2C_StartCondition(void) //СТАРТ { I2C1->CR2 |= I2C_CR2_START; /* Go */ } //-------------------------------------------------------------------------------------------- void I2C_StopCondition(void) //СТОП { I2C1->CR2 |= I2C_CR2_STOP; } //-------------------------------------------------------------------------------------------- void I2C_SendByte(unsigned char data) //ПЕРЕДАЧА БАЙТА и АСК { if((I2C1->ISR & I2C_ISR_TXE) == (I2C_ISR_TXE)) /* Check Tx empty */ { I2C1->TXDR = data; /* Byte to send */ I2C1->CR2 |= I2C_CR2_START; /* Go */ } //while (0 == (I2C1->ISR & I2C_ISR_TXE)){} } //-------------------------------------------------------------------------------------------- может кто нибудь заметит ошибку, пока что в ЛА невидно вообще никакой активности на линиях I2C они сидят в высоком уровне даже в момент ресета. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
Donker 0 16 марта, 2019 Опубликовано 16 марта, 2019 (изменено) · Жалоба Нашёл ошибку - перепутал AF4 на котором сидит I2C в STM32F030F4 cо смещением номера вывода, правильно так: GPIOA->OTYPER |= GPIO_OTYPER_OT_9 | GPIO_OTYPER_OT_10; /* (1) Open drain for I2C signals */ GPIOA->AFR[1] = (GPIOA->AFR[1] &~ (GPIO_AFRH_AFRH1 | GPIO_AFRH_AFRH2)) | (4 << ((9 - 8) * 4)) | (4 << ((10 - 8) * 4)); /* (2) AF4 for I2C signals */ GPIOA->MODER = (GPIOA->MODER & ~(GPIO_MODER_MODER9 | GPIO_MODER_MODER10)) | (GPIO_MODER_MODER9_1 | GPIO_MODER_MODER10_1); /* (3) Select AF mode (0b10) on PA9 and PA10 */ Поток пошёл, сейчас разбираюсь с порядком следования байт. Изменено 16 марта, 2019 пользователем Donker Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
Donker 0 17 марта, 2019 Опубликовано 17 марта, 2019 · Жалоба Возникли вопросы по регистру I2C1->CR2 в STM32F030F4: Cудя по дащиту (RM стр. 518) там есть секция "NBYTES" которая имеет размерность 8 бит и куда записывается количество байт для передачи (максимум 255), т.е. по максимуму это выглядит так: I2C1->CR2 = I2C_CR2_AUTOEND | (256<<16) | (OLED_addr_127<<1); /* (3) */ я правильно понимаю, что этота секция не даст отправить вподряд более 255 байт между "старт-адрес-..байты...-стоп"? Этот же регистр не даст передать по DMA более 255 байт вподряд, хотя у DMA есть регистр DMA1_Channel2->CNDTR куда можно записать уже 16 бит ? Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
Donker 0 17 марта, 2019 Опубликовано 17 марта, 2019 (изменено) · Жалоба Ладно, допустим с выводом за раз, и без прерываний, массива более 255 байт на STM32F0 через DMA я пролетаю, но как отправить хотя бы 255 байт? Вот так: //-------------------------------------------------------------------------------------------- uint8_t screen_buff[512]; #define OLED_addr_127 0b00111100 //7-битный адрес OLED 0b01111000 = 0x78 //-------------------------------------------------------------------------------------------- void I2C_init(void) { RCC->AHBENR |= RCC_AHBENR_DMA1EN; /* Enable the peripheral clock DMA1 */ /* DMA1 Channel4 I2C1_TX config */ /* Memory to peripheral */ /* 8-bit transfer */ DMA1_Channel2->CPAR = (uint32_t)&(I2C1->TXDR); /* (1) Peripheral address */ DMA1_Channel2->CMAR = (uint32_t)screen_buff; /* (2) Memory address */ DMA1_Channel2->CCR |= DMA_CCR_MINC | DMA_CCR_DIR; /* (3) Memory increment */ //------------------------------------------------------------------------------------ RCC->APB1ENR |= RCC_APB1ENR_I2C1EN; /* Enable the peripheral clock I2C1 */ RCC->CFGR3 |= RCC_CFGR3_I2C1SW; /* Configure I2C1, master */ /* (1) Timing register value is computed with the AN4235 xls file, fast Mode @400kHz with I2CCLK = 48MHz, rise time = 140ns, fall time = 40ns */ /* (2) Periph enable */ /* (3) Slave address = 0x5A, write transfer, 1 byte to transmit, autoend */ I2C1->TIMINGR = (uint32_t)0x00B01A4B; /* (1) */ I2C1->CR1 = I2C_CR1_PE; /* (2) */ I2C1->CR2 = I2C_CR2_AUTOEND | (255<<16) | (OLED_addr_127<<1); /* (3) */ } //-------------------------------------------------------------------------------------------- void OLED_SendScreen(void) { if((I2C1->ISR & I2C_ISR_TXE) == (I2C_ISR_TXE)) /* Check Tx empty */ { // I2C2->TXDR = I2C_BYTE_TO_SEND; /* Byte to send */ //I2C2->CR2 |= I2C_CR2_START; /* Go */ /* start transmission with DMA */ DMA1_Channel2->CCR &=~ DMA_CCR_EN; DMA1_Channel2->CNDTR = 255; /* Data size */ DMA1_Channel2->CCR |= DMA_CCR_EN; I2C1->CR2 |= I2C_CR2_START; /* Go */ } } //-------------------------------------------------------------------------------------------- не отправляется, в ЛА видно что есть старт, и правильно с нормальной скоростью отправляется адрес устройства, и всё, больше никаких байт не идёт и стопа тоже нет. Что не так? Код практически целиком взят из снипетов (см. 1 пост), только изменён I2C2 на I2C1 и канал DMA c 4 на 2 (в снипетах код для STM32F072RBT) Изменено 17 марта, 2019 пользователем Donker Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
Arlleex 131 17 марта, 2019 Опубликовано 17 марта, 2019 · Жалоба Странный у Вас RM (или у меня?), раз на 518 странице у меня раздел RTC... Приводя актуальный источник, делайте на него ссылку, чтобы не пришлось додумывать, какая версия документа у Вас используется. RM на STM32F030, стр. 537: Цитата Hardware transfer management ... The number of bytes to be transferred is programmed in the NBYTES[7:0] bit field in the I2C_CR2 register. If the number of bytes to be transferred (NBYTES) is greater than 255, or if a receiver wants to control the acknowledge value of a received data byte, the reload mode must be selected by setting the RELOAD bit in the I2C_CR2 register. In this mode, TCR flag is set when the number of bytes programmed in NBYTES has been transferred, and an interrupt is generated if TCIE is set. SCL is stretched as long as TCR flag is set. TCR is cleared by software when NBYTES is written to a non-zero value. Скорее всего, делается это так. Допустим, нужно передать 352 байта. 352 это больше 255, поэтому настраиваем DMA на 352 байта, а NBYTES на 255 байт. Запускаем DMA. В прерывании по TCR (передано 255 байт), перезаписываем NBYTES на 352-255 = 97 байт. В следующем таком прерывании формируем Stop-условие (или в первом заходе в прерывание сбрасываем RELOAD, Stop-условие сформируется автоматически). Вроде так. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
Donker 0 17 марта, 2019 Опубликовано 17 марта, 2019 · Жалоба Спасибо, я так и понял, что разработчики ST над нами издеваются. страницу я перепутал, 581 - правильно. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться