Перейти к содержанию
    

Reystlin

Участник
  • Постов

    128
  • Зарегистрирован

  • Посещение

Весь контент Reystlin


  1. STM32f103 Custom HID USB -> HIDAPI

    Доброго времени суток пытаюсь понять как работать с Custom HID на основе статьи https://microtechnics.ru/stm32cube-usb-custom-hid-sozdanie-deskriptorov-ustrojstva/?ysclid=lcfzgdcyrl345227162 в контроллере сделал вот так Проблемы с тем на базе какой библиотеки на компе код удобней делать. в исходной статье применяли libusb но почему-то не смог найти той версии, по которой делали статью. по другим статьям тоже ничего не вышло Смотрел WinUSB там вообще не понятно как этим пользоваться взял HIDAPI на ней по примерам получилось увидеть мою плату но не получается отправить и получить данные Кто какие библиотеки использует? Может у кого есть рабочий пример для стороны контроллера и компа?
  2. stm32f4 spi dma cmsis

    Организовал в итоге работу SPI через DMA вот таким образом #include "SPI3.h" uint8_t SPI3_buff[1024]; uint8_t Empty_Flag = 1; int rxCounter = 0; void SPI3_Init(void) { //DMA1 Stream 5 SPI3_TX channel 0 RCC->AHB1ENR |= RCC_AHB1ENR_DMA1EN; RCC->APB1ENR |= RCC_APB1ENR_SPI3EN; RCC->AHB1ENR |= RCC_AHB1ENR_GPIOAEN | RCC_AHB1ENR_GPIOCEN; // GPIO GPIO_InitTypeDef GPIO_InitStruct = {0}; GPIO_InitStruct.Speed = GPIO_SPEED_FAST; GPIO_InitStruct.Alternate = GPIO_AF6_SPI3; // PA10 - SS - Выход GPIOA->MODER |= GPIO_MODER_MODE10_0; // PC10 - SCK - Выход GPIO_InitStruct.Pin = GPIO_PIN_10; GPIO_InitStruct.Mode = GPIO_MODE_AF_PP; HAL_GPIO_Init(GPIOC, &GPIO_InitStruct); // PC11 - MISO - Вход GPIO_InitStruct.Pin = GPIO_PIN_11; GPIO_InitStruct.Mode = GPIO_MODE_AF_OD; HAL_GPIO_Init(GPIOC, &GPIO_InitStruct); // PC12 - MOSI - Выход GPIO_InitStruct.Pin = GPIO_PIN_12; GPIO_InitStruct.Mode = GPIO_MODE_AF_PP; HAL_GPIO_Init(GPIOC, &GPIO_InitStruct); SPI3->CR2 = SPI_CR2_RXDMAEN| // Получение через DMA SPI_CR2_TXDMAEN; // Отправка через DMA SPI3->CR1 = 0 << SPI_CR1_DFF_Pos // Размер кадра 8 бит | 1<<SPI_CR1_SSM_Pos // Программное управление SS | 1<<SPI_CR1_SSI_Pos // SS в высоком состоянии | 0x02<<SPI_CR1_BR_Pos // Скорость передачи | 1<<SPI_CR1_MSTR_Pos // Режим Master | 0<<SPI_CR1_CPOL_Pos | 0<<SPI_CR1_CPHA_Pos | SPI_CR1_SPE; DMA1_Stream5->CR = 0; DMA1_Stream5->FCR = 0; DMA1_Stream5->PAR = (uint32_t)(&SPI3->DR); DMA1_Stream0->CR = 0; DMA1_Stream0->FCR = 0; DMA1_Stream0->PAR = (uint32_t)(&SPI3->DR); DMA1_Stream0->NDTR = 1024; DMA1_Stream0->M0AR = (uint32_t)SPI3_buff; DMA1_Stream0->CR = _VAL2FLD(DMA_SxCR_CHSEL, 0)| /// channe - tmigger _VAL2FLD(DMA_SxCR_DIR, 0)| /// peripheral to memory DMA_SxCR_MINC| /// memory increment mode DMA_SxCR_EN; } void SPI3_Send(uint8_t *data, uint16_t len) { while ((SPI3->SR & SPI_SR_BSY) | !(SPI3->SR & SPI_SR_TXE)) {} Empty_Flag = 1; GPIOA->BSRR = GPIO_BSRR_BS_10; // На прием DMA1_Stream0->CR &=~(DMA_SxCR_EN); DMA1_Stream0->NDTR = 1024; DMA1_Stream0->M0AR = (uint32_t)SPI3_buff; DMA1_Stream0->CR |=(DMA_SxCR_EN); // На передачу DMA1->HIFCR = (DMA_HIFCR_CTCIF5| DMA_HIFCR_CHTIF5 | DMA_HIFCR_CTEIF5 | DMA_HIFCR_CDMEIF5 | DMA_HIFCR_CFEIF5); DMA1_Stream5->NDTR = len; DMA1_Stream5->M0AR = (uint32_t)data; DMA1_Stream5->CR = _VAL2FLD(DMA_SxCR_CHSEL, 0)| /// channe - tmigger _VAL2FLD(DMA_SxCR_DIR, 1)| /// memory_to_peripheral DMA_SxCR_MINC| /// memory increment mode DMA_SxCR_TCIE| DMA_SxCR_EN; NVIC_EnableIRQ(SPI3_IRQn); NVIC_EnableIRQ(DMA1_Stream5_IRQn); } void DMA1_Stream5_IRQHandler(void) { if (DMA1->LISR & DMA_LISR_TCIF0) { DMA1->LIFCR = DMA_LIFCR_CTCIF0; // сброс флага события TCIF DMA1_Stream5->CR = 0; SPI3->CR2 |= SPI_CR2_TXEIE; //GPIOA->BSRR = GPIO_BSRR_BR_10; } } uint8_t SPI3_Is_Empty(void) { return Empty_Flag; } volatile uint8_t ssss; void SPI3_IRQHandler(void) { const uint32_t sr = SPI3->SR; const uint32_t cr2 = SPI3->CR2; if(READ_BIT(sr, SPI_SR_TXE)) { SPI3->SR = sr &(~SPI_SR_TXE); SPI3->CR2 = cr2 &(~SPI_CR2_TXEIE); Empty_Flag = 0; GPIOA->BSRR = GPIO_BSRR_BR_10; } else if(READ_BIT(sr, SPI_SR_OVR)) { __NOP(); } } Не могу добиться правильного варианта с опусканием вывода PA10. В прерыварии по DMA срабатывает рано, что понятно почему Прерывание по TXE не срабатывает...
  3. stm32f4 spi dma cmsis

    Методом тыка выяснил, что LWIP не дает работать, когда комментирую инициализацию LWIP то SPI через DMA заводится...
  4. stm32f4 spi dma cmsis

    При компиляции то ошибок нет, но при исполнении в статус регистрах появляются
  5. stm32f4 spi dma cmsis

    Флаги Transfer error и FIFO error устанавливаются после запуска DMA Я пытаюсь сейчас в простом виде запустить SPI+DMA чтобы что-нибудь выдало а дальше буду накручивать функционал т.к. не понятно чего оно не работает
  6. stm32f4 spi dma cmsis

    Проц STM32f407IGT6 Поместил весь код, касающийся SPI3, DMA1 и нужных GPIO в одну функцию, вызываю её один раз перед основным циклом. Проект большой, больше нигде ничего не трогается из этой периферии void SPI3_Send() { //DMA1 Stream 5 SPI3_TX channel 0 RCC->AHB1ENR |= RCC_AHB1ENR_DMA1EN; RCC->APB1ENR |= RCC_APB1ENR_SPI3EN; RCC->AHB1ENR |= RCC_AHB1ENR_GPIOCEN; // GPIO GPIO_InitTypeDef GPIO_InitStruct = {0}; GPIO_InitStruct.Speed = GPIO_SPEED_FAST; GPIO_InitStruct.Alternate = GPIO_AF6_SPI3; // PC10 - SCK - Выход GPIO_InitStruct.Pin = GPIO_PIN_10; GPIO_InitStruct.Mode = GPIO_MODE_AF_PP; HAL_GPIO_Init(GPIOC, &GPIO_InitStruct); // PC11 - MISO - Вход GPIO_InitStruct.Pin = GPIO_PIN_11; GPIO_InitStruct.Mode = GPIO_MODE_AF_OD; HAL_GPIO_Init(GPIOC, &GPIO_InitStruct); // PC12 - MOSI - Выход GPIO_InitStruct.Pin = GPIO_PIN_12; GPIO_InitStruct.Mode = GPIO_MODE_AF_PP; HAL_GPIO_Init(GPIOC, &GPIO_InitStruct); uint8_t data[] = {1,2,3}; uint8_t len = 3; DMA1_Stream5->CR = 0; DMA1_Stream5->PAR = (uint32_t)(&SPI3->DR); DMA1_Stream5->M0AR = (uint32_t)data; DMA1_Stream5->NDTR = len; DMA1_Stream5->FCR = 0; // Настройка FIFO буфера DMA1_Stream5->CR = (0x00) << DMA_SxCR_CHSEL_Pos // Выбор канала |(0x00) << DMA_SxCR_MBURST_Pos // |(0x00) << DMA_SxCR_PBURST_Pos // |0 << DMA_SxCR_CT_Pos // Текущий буфер |0 << DMA_SxCR_DBM_Pos // Двойной буфер |(0x03) << DMA_SxCR_PL_Pos // Приоритет |0 << DMA_SxCR_PINCOS_Pos // Инкремент адреса периферии |(0x00) << DMA_SxCR_MSIZE_Pos // Размер данных в памяти 8 бит |(0x00) << DMA_SxCR_PSIZE_Pos // Размер данных в периферии 8 бит |1 << DMA_SxCR_MINC_Pos // Инкремент адреса памяти |0 << DMA_SxCR_PINC_Pos // Инкремент адреса периферии |0 << DMA_SxCR_CIRC_Pos // Циркуляционный режим |(0x01) << DMA_SxCR_DIR_Pos // Направление данных из памяти в периферию |0 << DMA_SxCR_PFCTRL_Pos // DMA управляет процессом |0 << DMA_SxCR_TCIE_Pos // Прерывание по окончанию передачи |0 << DMA_SxCR_HTIE_Pos // Прерывание по половине передачи |0 << DMA_SxCR_TEIE_Pos // Прерывание по ошибке передачи |0 << DMA_SxCR_DMEIE_Pos // Прерывание по |1 << DMA_SxCR_EN_Pos; // Активация DMA SPI3->CR2 = 1<<SPI_CR2_TXDMAEN_Pos | 1<<SPI_CR2_SSOE_Pos; SPI3->CR1 = 0<<SPI_CR1_DFF_Pos //Размер кадра 8 бит | 0<<SPI_CR1_LSBFIRST_Pos //MSB first | 1<<SPI_CR1_SSM_Pos //Программное управление SS | 1<<SPI_CR1_SSI_Pos //SS в высоком состоянии | 0x04<<SPI_CR1_BR_Pos //Скорость передачи: F_PCLK/32 | 1<<SPI_CR1_MSTR_Pos //Режим Master (ведущий) | 0<<SPI_CR1_CPOL_Pos | 0<<SPI_CR1_CPHA_Pos //Режим работы SPI: 0 | 1<<SPI_CR1_SPE_Pos; //Включаем SPI } Нужно ли обработчик прерывания делать если оно у меня не используется?
  7. stm32f4 spi dma cmsis

    SPI вообще ничего не отправляет, если отправку делаю через DMA. ни один из выводов SPI не дергается.
  8. stm32f4 spi dma cmsis

    Инициализация DMA сейчас выглядит вот так //DMA1 Stream 7 SPI3_TX channel 0 DMA1_Stream7->CR = 0; DMA1_Stream7->PAR = (uint32_t)(&SPI3->DR); DMA1_Stream7->M0AR = (uint32_t)data; DMA1_Stream7->NDTR = len; DMA1_Stream7->FCR = 0; // Настройка FIFO буфера DMA1_Stream7->CR = (0x00) << DMA_SxCR_CHSEL_Pos // Выбор канала |(0x00) << DMA_SxCR_MBURST_Pos // |(0x00) << DMA_SxCR_PBURST_Pos // |0 << DMA_SxCR_CT_Pos // Текущий буфер |0 << DMA_SxCR_DBM_Pos // Двойной буфер |(0x03) << DMA_SxCR_PL_Pos // Приоритет |0 << DMA_SxCR_PINCOS_Pos // Инкремент адреса периферии |(0x00) << DMA_SxCR_MSIZE_Pos // Размер данных в памяти 8 бит |(0x00) << DMA_SxCR_PSIZE_Pos // Размер данных в периферии 8 бит |1 << DMA_SxCR_MINC_Pos // Инкремент адреса памяти |0 << DMA_SxCR_PINC_Pos // Инкремент адреса периферии |0 << DMA_SxCR_CIRC_Pos // Циркуляционный режим |(0x01) << DMA_SxCR_DIR_Pos // Направление данных из памяти в периферию |0 << DMA_SxCR_PFCTRL_Pos // DMA управляет процессом |0 << DMA_SxCR_TCIE_Pos // Прерывание по окончанию передачи |0 << DMA_SxCR_HTIE_Pos // Прерывание по половине передачи |0 << DMA_SxCR_TEIE_Pos // Прерывание по ошибке передачи |0 << DMA_SxCR_DMEIE_Pos // Прерывание по |1 << DMA_SxCR_EN_Pos; // Активация DMA
  9. stm32f4 spi dma cmsis

    Канал 0 какие я регистры не заполнил из обязательных? уже исправлено SPI3->CR1 = 0<<SPI_CR1_DFF_Pos //Размер кадра 8 бит | 0<<SPI_CR1_LSBFIRST_Pos //MSB first | 1<<SPI_CR1_SSM_Pos //Программное управление SS | 1<<SPI_CR1_SSI_Pos //SS в высоком состоянии | 0x04<<SPI_CR1_BR_Pos //Скорость передачи: F_PCLK/32 | 1<<SPI_CR1_MSTR_Pos //Режим Master (ведущий) | 0<<SPI_CR1_CPOL_Pos | 0<<SPI_CR1_CPHA_Pos; //Режим работы SPI: 0 SPI3->CR2 |= 1<<SPI_CR2_TXDMAEN_Pos; SPI3->CR2 |= 1<<SPI_CR2_SSOE_Pos; SPI3->CR2 |= 1<<SPI_CR2_RXDMAEN_Pos; SPI3->CR1 |= 1<<SPI_CR1_SPE_Pos; //Включаем SPI volatile uint8_t data[3] = {1,2,3}; SPI3_Send(data,3); Спасибо
  10. stm32f4 spi dma cmsis

    Поменял. На ситуацию не повлияло
  11. stm32f4 spi dma cmsis

    Без цикла тоже не работает. Одиночную отправку тоже не производит
  12. stm32f4 spi dma cmsis

    Доброго времени суток Подскажите пожалуйста, что я делаю не так в настройке DMA для SPI для отправки без DMA работает void SPI3_Init() { // SPI3 RCC->APB1ENR |= RCC_APB1ENR_SPI3EN; RCC->AHB1ENR |= RCC_AHB1ENR_DMA1EN; SPI3->CR1 = 0 << SPI_CR1_DFF_Pos // Размер кадра 8 бит | 0<<SPI_CR1_LSBFIRST_Pos // MSB first | 1<<SPI_CR1_SSM_Pos // Программное управление SS | 1<<SPI_CR1_SSI_Pos // SS в высоком состоянии | 0x00<<SPI_CR1_BR_Pos // Скорость передачи = Fpclk/2 | 1<<SPI_CR1_MSTR_Pos // Режим Master | 0<<SPI_CR1_CPOL_Pos | 0<<SPI_CR1_CPHA_Pos; SPI3->CR2 = SPI_CR2_TXDMAEN; // Отправка через DMA SPI3->CR1 |= SPI_CR1_SPE; // Включаем SPI3 } void SPI3_Send(volatile uint8_t *data, uint16_t len) { //DMA1 Stream 7 SPI3_TX DMA1_Stream7->CR = 0; DMA1_Stream7->CR |= 0x01 << DMA_SxCR_PSIZE_Pos; // SPI data register is 16 bit DMA1_Stream7->CR |= 0x00 << DMA_SxCR_MSIZE_Pos; // memory size is 8bit DMA1_Stream7->CR |= DMA_SxCR_MINC; // memory increment DMA1_Stream7->CR |= 0x01 << DMA_SxCR_DIR_Pos; // memory to peripheral DMA1_Stream7->CR |= 0x03 << DMA_SxCR_PL_Pos; // Priority level DMA1_Stream7->PAR = (uint32_t)(&SPI3->DR); DMA1_Stream7->M0AR = (uint32_t)data; DMA1_Stream7->NDTR = len; DMA1_Stream7->FCR = 0; // Настройка FIFO буфера DMA1_Stream7->CR |= DMA_SxCR_EN; } ................ volatile uint8_t data[3] = {1,2,3}; while(1) SPI3_Send(data,3);
  13. Степген для 8 двигателей много ресурсов жрет, да и функионала нет такого там чтобы ОС ставить. с компа через сеть получаю пакеты движений а в ответ отсылаю пакеты с положениями валов полученные по модбасу
  14. у меня нет ОС.... не добавлять же её только из-за работы с ModBUS
  15. Так у меня и так на одном таймере, на TIM7 оба события.... в зависимости от состояния перестраиваю время срабатывания прерывания. Видимо проглядел... спасибо
  16. у меня задача попроще. есть 10 серводвигателей и нужно постоянно циклически их положение получать. Без таймера нормально не работает - нужна задержка между отправкой текущего пакета и следующего. так-же таймаут нужно как-то определять Про паузу после перевода трансмиттера в режим передачи и отправку пакета добавлю. спасибо
  17. Задачи multimaster не стоит а с несколькими slave не вижу проблемы. использую дальше вот так enum ModBUS_packet_status{ IDLE, SEND, SEND_ERROR, WAIT_ANSWER, ANSWER_OK, ANSWER_ERROR, DONE }; enum ModBUS_Error{ NONE, TIMEOUT, SLAVE_ID_ERROR, CMD_ERROR, FUNCTION_CODE_ERROR, ACCESS_ADDRESS_ERROR, DATA_ERROR, CRC_ERROR }; enum ModBUS_cmd{ //Read_Coil_Status = 0x01, //Read_Input_Status = 0x02, Read_Holding_Registers = 0x03, //Read_Input_Registers = 0x04, //Force_Single_Coil = 0x05, Preset_Single_Register = 0x06, //Force_Multiple_Coils = 0x0F, //Preset_Multiple_Registers = 0x10 }; #define MODBUS_QUEUE_SIZE 2 volatile struct _ModBUS_packet_queue { uint8_t SlaveID; enum ModBUS_cmd cmd; uint16_t address; uint16_t request_data; uint32_t answer_data; enum ModBUS_packet_status status; enum ModBUS_Error error; }ModBUS_packet_queue[MODBUS_QUEUE_SIZE]= {{1, 0x03, 0x602C, 0x0002, 0, 0, 0}, {2, 0x03, 0x602C, 0x0002, 0, 0, 0}};/* {2, 0x03, 0x0B1C, 0x0002, 0, 0, 0}, {2, 0x03, 0x0B1D, 0x0002, 0, 0, 0} };*/ volatile uint8_t read_queue_USART_pointer; uint8_t Check_Error(uint8_t *Response) { if(Response[1]&0x80) return Response[2]; return 0; // Error code // 0x01 - Function code error // 0x02 - Access address error // 0x03 - Data error, such as write data exceeding the limit // 0x08 - CRC check error } void Recive_ModBUS(uint8_t *Response) { if(USART_Get_Error()== USART_NO_ERROR) { if(Response[0] != ModBUS_packet_queue[read_queue_USART_pointer].SlaveID) { ModBUS_packet_queue[read_queue_USART_pointer].answer_data = 0; ModBUS_packet_queue[read_queue_USART_pointer].error = SLAVE_ID_ERROR; } else if(Check_Error(Response)) { ModBUS_packet_queue[read_queue_USART_pointer].answer_data = 0; if(Check_Error(Response) & 0x01) ModBUS_packet_queue[read_queue_USART_pointer].error = FUNCTION_CODE_ERROR; else if(Check_Error(Response) & 0x02) ModBUS_packet_queue[read_queue_USART_pointer].error = ACCESS_ADDRESS_ERROR; else if(Check_Error(Response) & 0x03) ModBUS_packet_queue[read_queue_USART_pointer].error = DATA_ERROR; else if(Check_Error(Response) & 0x04) ModBUS_packet_queue[read_queue_USART_pointer].error = CRC_ERROR; } else if(Response[1] != Read_Holding_Registers) { ModBUS_packet_queue[read_queue_USART_pointer].answer_data = 0; ModBUS_packet_queue[read_queue_USART_pointer].error = CMD_ERROR; } else { ModBUS_packet_queue[read_queue_USART_pointer].answer_data = (Response[4]<<24) | (Response[5]<<16) | (Response[6]<<8) | Response[7]; } if(ModBUS_packet_queue[read_queue_USART_pointer].error) ModBUS_packet_queue[read_queue_USART_pointer].status = ANSWER_ERROR; else ModBUS_packet_queue[read_queue_USART_pointer].status = DONE; } else { ModBUS_packet_queue[read_queue_USART_pointer].status = SEND_ERROR; ModBUS_packet_queue[read_queue_USART_pointer].error = TIMEOUT; } if(++read_queue_USART_pointer == MODBUS_QUEUE_SIZE) read_queue_USART_pointer = 0; } void Send_ModBUS() { if(ModBUS_packet_queue[read_queue_USART_pointer].status != SEND) { char msg[8]; uint16_t reg = ModBUS_packet_queue[read_queue_USART_pointer].address; uint16_t data = ModBUS_packet_queue[read_queue_USART_pointer].request_data; msg[0] = ModBUS_packet_queue[read_queue_USART_pointer].SlaveID; msg[1] = ModBUS_packet_queue[read_queue_USART_pointer].cmd; msg[2] = (uint8_t)(reg>>8); msg[3] = (uint8_t)(reg&0xFF); msg[4] = (uint8_t)(data>>8); msg[5] = (uint8_t)(data&0xFF); uint16_t crc = ModBUS_CRC16((uint8_t*)msg,6); msg[6]=(uint8_t)(crc&0xFF); msg[7]=(uint8_t)(crc>>8)&0xFF; if(USART1_put(8, msg, Recive_ModBUS) == USART_SEND) ModBUS_packet_queue[read_queue_USART_pointer].status = SEND; } } void ModBUS_Exec() { Send_ModBUS(); }
  18. Пофиксил. Не хватало сброса флага окончания передачи из уарта в память на приеме void USART1_IRQHandler(void) { const uint32_t sr = USART1->SR, cr = USART1->CR1; if((sr & USART_SR_TC) && (cr & USART_CR1_TCIE)) { // Окончили отправку USART1->SR = ~(USART_SR_TC); DMA2_Stream5->NDTR = 255; DMA2->HIFCR = DMA_HIFCR_CTCIF5; DMA2_Stream5_En(); GPIOA->BSRR = GPIO_BSRR_BR11; // Прием USART_status = USART_READ; // Настройка таймера на Timeout TIM7->CR1 = 0; TIM7->CNT = 0; TIM7->ARR = 100000-1; TIM7_En(); } else if((sr & USART_SR_IDLE) && (cr & USART_CR1_IDLEIE)) { // Окончили прием ответа (void)USART1->DR; USART1->SR = ~(USART_SR_IDLE); DMA2_Stream5->CR = 0; GPIOA->BSRR = GPIO_BSRR_BS11; // Прием окончен USART_status = USART_WAIT; TIM7->CR1 = 0; TIM7->CNT = 0; TIM7->ARR = 500-1; // Задержка отправки второго пакета после приема TIM7_En(); // Включаем счетчик для задержки отправки второго пакета recive_fn(rx_buf); } }
  19. Видимо я что-то не так с ДМА делаю, в rx_buff заполняется первый ответный пакет и после этого данные в нём не меняются, хотя ответы разные на шине присутствуют нужно ли перед повторным включением DMA на прием сбрасывать какой-нибудь счетчик?
  20. Нашел ошибку. вот здесь GPIOA->BSRR = GPIO_BSRR_BR11; // Прием окончен надо было GPIOA->BSRR = GPIO_BSRR_BS11; // Прием окончен
  21. Продолжаю изыскания по организации общения через ModBUS поверх RS485 на текущий момент вот такой код: #include "USART1.h" #include <stdio.h> #include <string.h> uint8_t rx_buf[256]; uint8_t tx_buf[256]; #define TIM7_En() TIM7->CR1 = TIM_CR1_OPM | TIM_CR1_CEN; // Таймер задержки отправки следующего пакета #define DMA2_Stream5_En() DMA2_Stream5->CR = DMA_SxCR_EN | DMA_SxCR_CHSEL_2 | DMA_SxCR_MINC | DMA_SxCR_PFCTRL // DMA на прием #define DMA2_Stream7_En() DMA2_Stream7->CR = DMA_SxCR_EN | DMA_SxCR_CHSEL_2 | DMA_SxCR_MINC | DMA_SxCR_DIR_0 | DMA_SxCR_TCIE // DMA на отправку void Init_USART1() { // USART1 RCC->APB2ENR |= RCC_APB2ENR_USART1EN; // APB2 = 84MHz uint32_t baud_rate = 38400; uint16_t uartdiv = 168000000 / baud_rate; USART1->BRR = (( ( ( uartdiv / 16 ) << USART_BRR_DIV_Mantissa_Pos ) | ( ( uartdiv % 16 ) << USART_BRR_DIV_Fraction_Pos ) ))-2; USART1->CR1 = 0 | USART_CR1_OVER8 // Размер кадра 8 бит | USART_CR1_UE // Включаем USART1 //| USART_CR1_M // Формат кадра Start bit, 8 bits, n Stop bits //| USART_CR1_PCE // Parity mode control disable //| USART_CR1_PS // Parity mode Even //| USART_CR1_PEIE // Разрешение прерывания PEIE ошибка четности //| USART_CR1_TXEIE // Разрешение прерывания TXEIE опустошение регистра передатчика //| USART_CR1_TCIE // Разрешение прерывания TCIE завершение передачи //| USART_CR1_RXNEIE // Разрешение прерывания RXNEIE завершение приема | USART_CR1_IDLEIE // Разрешение прерывания IDLEIE обнаружение сигнала IDLE на линии | USART_CR1_TE // Разрешение передачи | USART_CR1_RE // Разрешение приема //| USART_CR1_RWU // Reciver wakeup //| USART_CR1_SBK // Send break ; USART1->CR2 = 0 // USART_CR2_LINEN // Включение режима LIN | USART_CR2_STOP_1 // 2 Стоп бита //| USART_CR2_STOP_0 //| USART_CR2_CLKEN // Включить вывод CK //| USART_CR2_CPOL // Определяет уровень сигнала на линии CK в отсутствии симпульсов //| USART_CR2_CPHA // Определяет по которому фронту импульсов на линии CK происходи захват //| USART_CR2_LBCL // Нужно ли тактировать через линию CK последний передаваемый бит //| USART_CR2_LBDIE // Разрешение прерывания по обнаружению сигнала break //| USART_CR2_LBDL // Длительность ожидаемого сигнала break ; USART1->CR3 = 0 // USART_CR3_CTSIE // Включение прерывания по линии CTS //USART_CR3_CTSE // Включение контроля линии CTS(Данные начнут передаваться когда CTS = 0) //| USART_CR3_RTSE // Включение контроля линии RTS(Dscnfdkztncz КЕЫ = 0 когда приемник пуст и готов) | USART_CR3_DMAT // Включить режим DMA для передатчика | USART_CR3_DMAR // Включить режим DMA для приемника //| USART_CR3_SCEN // Включить режим Smartcard //| USART_CR3_NACK // Поылать ли NACK в режиме Smartcard //| USART_CR3_HDSEL // Однопроводный полудуплексный режим //| USART_CR3_IRLP // Включение режима low-power для IrDA //| USART_CR3_IREN // Включение режиме IrDA //| USART_CR3_EIE // Включение прерывания по ошибкам передачи ; // DMA2 - Stream7 - Transmit RCC->AHB1ENR |= RCC_AHB1ENR_DMA2EN; DMA2_Stream7->PAR = (uint32_t)&(USART1->DR); // Адрес назначения DMA2_Stream7->M0AR = (uint32_t)(tx_buf); // Адрес источника DMA2_Stream7->FCR = 0; // Настройка FIFO буфера DMA2_Stream7->CR = 0 | DMA_SxCR_CHSEL_2 // Выбираем 4 канал | DMA_SxCR_MINC // Инкремент адреса памяти | DMA_SxCR_DIR_0 // Направление - из памяти в перефереию | DMA_SxCR_TCIE // Прерывание по окончанию пересылки пакета ; NVIC_EnableIRQ(USART1_IRQn); NVIC_SetPriority(USART1_IRQn, 0x04); NVIC_SetPriority(DMA2_Stream7_IRQn, 0x04); NVIC_EnableIRQ(DMA2_Stream7_IRQn); // DMA2 - Stream 5 - Recive DMA2_Stream5->PAR = (uint32_t)&(USART1->DR); // Адрес источника DMA2_Stream5->M0AR = (uint32_t)(rx_buf); // Адрес назначения DMA2_Stream5->FCR = 0; // Настройка FIFO буфера DMA2_Stream5->NDTR = 255; /*DMA2_Stream5->CR = 0 | DMA_SxCR_CHSEL_2 // Выбираем 4 канал | DMA_SxCR_MINC // Инкремент адреса памяти | DMA_SxCR_PFCTRL // DMA - Ведомый ;*/ //TIM7 - Таймер для Timeout и задержек RCC->APB1ENR |= RCC_APB1ENR_TIM7EN; //TIM7->CR1 = TIM_CR1_OPM; // Однократный режим TIM7->PSC=84-1; TIM7->ARR=500-1; TIM7->EGR |= TIM_EGR_UG; TIM7->SR=0; TIM7->DIER = TIM_DIER_UIE; // Разрешение прерывания NVIC_EnableIRQ(TIM7_IRQn); // GPIO RCC->AHB1ENR |= RCC_AHB1ENR_GPIOAEN; GPIO_InitTypeDef GPIO_InitStruct_ModBUS = {0}; GPIO_InitStruct_ModBUS.Speed = GPIO_SPEED_FAST; GPIO_InitStruct_ModBUS.Alternate = GPIO_AF7_USART1; // PA9 - DI - TX GPIO_InitStruct_ModBUS.Pin = GPIO_PIN_9; GPIO_InitStruct_ModBUS.Mode = GPIO_MODE_AF_PP; HAL_GPIO_Init(GPIOA, &GPIO_InitStruct_ModBUS); // PA10 - RO - RX GPIO_InitStruct_ModBUS.Pin = GPIO_PIN_10; GPIO_InitStruct_ModBUS.Mode = GPIO_MODE_AF_OD; HAL_GPIO_Init(GPIOA, &GPIO_InitStruct_ModBUS); // PA11 - DE/RE - CTS GPIO_InitStruct_ModBUS.Pin = GPIO_PIN_11; GPIO_InitStruct_ModBUS.Mode = GPIO_MODE_OUTPUT_PP; HAL_GPIO_Init(GPIOA, &GPIO_InitStruct_ModBUS); GPIOA->BSRR = GPIO_BSRR_BS11; // Передача } void (*recive_fn)(uint8_t*); volatile enum USART_RS485_Status status = USART_IDLE; // Принимает строку. enum USART_RS485_Status USART1_put(uint8_t size, char *text,void (*recive)(uint8_t*)) { if(status == USART_IDLE) { status = USART_SEND; recive_fn = recive; memcpy(tx_buf, text, size); GPIOA->BSRR = GPIO_BSRR_BS11; // Передача DMA2_Stream7->NDTR = size; DMA2_Stream7_En(); } return status; }; void DMA2_Stream7_IRQHandler(void) { if (DMA2->HISR & DMA_HISR_TCIF7) { DMA2->HIFCR = DMA_HIFCR_CTCIF7; // сброс флага события TCIF USART1->SR = ~(USART_SR_TC); USART1->CR1 |= USART_CR1_TCIE; // Разрешение прерывания TCIE завершение передачи } }; void USART1_IRQHandler(void) { const uint32_t sr = USART1->SR, cr = USART1->CR1; if((sr & USART_SR_TC) && (cr & USART_CR1_TCIE)) { // Окончили отправку USART1->SR = ~(USART_SR_TC); DMA2_Stream7->CR = 0; DMA2_Stream5_En(); GPIOA->BSRR = GPIO_BSRR_BR11; // Прием status = USART_READ; // Настройка таймера на Timeout TIM7->ARR = 5000-1; // Задержка отправки второго пакета после приема TIM7_En(); // Включаем счетчик для задержки отправки второго пакета } else if((sr & USART_SR_IDLE) && (cr & USART_CR1_IDLEIE)) { // Окончили прием ответа (void)USART1->DR; USART1->SR = ~(USART_SR_IDLE); DMA2_Stream5->CR = 0; GPIOA->BSRR = GPIO_BSRR_BR11; // Прием окончен status = USART_WAIT; TIM7->ARR = 500-1; // Задержка отправки второго пакета после приема TIM7_En(); // Включаем счетчик для задержки отправки второго пакета recive_fn(rx_buf); } } void TIM7_IRQHandler(void) { TIM7->SR = ~(TIM_SR_UIF); if(status == USART_READ) { // Timeout status = USART_IDLE; } else { // Окончили получение и задержку status = USART_IDLE; } } Slave устройство не подключено. Желтый TX Зеленёый RX Синий PA11 https://disk.yandex.ru/i/vkatL_l1n5cT2A не могу понять в чем дело почему на PA11 меняется сигнал во время отправки одного целого пакета
  22. Хороший вариант, спасибо, об константе не подумал)
  23. При выключенном, конечно, не нужны. но его же нужно будет включить. этот "паравоз" я привел вот к такому виду: DMA2_Stream5->CR = 0 | DMA_SxCR_CHSEL_2 // Выбираем 4 канал | DMA_SxCR_MINC // Инкремент адреса памяти | DMA_SxCR_PFCTRL // DMA - Ведомый При каждом включении необходимо будет вставить этот кусок кода, затрудняя возможность внесения изменений в инициализацию, через пол года можно забыть в каких местах в коде включение работы DMA происходит, а если этот код другому человеку поддеживать придется? стараюсь всегда всю конфигурацию вынести в одно место а не размазывать по коду без крайней необходимости С точки зрения эффективности со стороны работы процессора да - ваша рекомендация хороша, не спорю. с точки зрения поддержки кода не совсем... кроме инлайн функции не вижу другого выхода из ситуации, чтобы оптимизировать код со стороны работы процессора и не потерять его гибкость изменения и поддержки. В любом случае, спасибо за вашу помощь и советы
×
×
  • Создать...