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

Reystlin

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

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

  • Посещение

Сообщения, опубликованные Reystlin


  1. Доброго времени суток

    пытаюсь понять как работать с Custom HID

    на основе статьи https://microtechnics.ru/stm32cube-usb-custom-hid-sozdanie-deskriptorov-ustrojstva/?ysclid=lcfzgdcyrl345227162

    в контроллере сделал вот так

    Spoiler
    __ALIGN_BEGIN static uint8_t CUSTOM_HID_ReportDesc_FS[USBD_CUSTOM_HID_REPORT_DESC_SIZE] __ALIGN_END =
    {
      /* USER CODE BEGIN 0 */
        0x06, 0x00, 0xff,            // USAGE_PAGE (Generic Desktop)
        0x09, 0x01,                  // USAGE (Vendor Usage 1)
        
        // System Parameters
        0xa1, 0x01,                  // COLLECTION (Application)
        0x85, 0x01,                  // REPORT_ID (1)
        0x09, 0x01,                  // USAGE (Vendor Usage 1)
        0x15, 0x00,                  // LOGICAL_MINIMUM (0)
        0x25, 0x01,                  // LOGICAL_MAXIMUM (1)
        0x75, 0x08,                  // REPORT_SIZE (8)
        0x95, 4,                     // REPORT_COUNT (4)
        0xb1, 0x82,                  // FEATURE (Data,Var,Abs,Vol)
        0x85, 0x01,                  // REPORT_ID (1)
        0x09, 0x01,                  // USAGE (Vendor Usage 1)
        0x91, 0x82,                  // OUTPUT (Data,Var,Abs,Vol)
        0x85, 0x02,                  // REPORT_ID (2)
        0x09, 0x02,                  // USAGE (Vendor Usage 2)
        0x75, 0x08,                  // REPORT_SIZE (8)
        0x95, 4,                     // REPORT_COUNT (4)
        0x81, 0x82,                  // INPUT (Data,Var,Abs,Vol)
      /* USER CODE END 0 */
      0xC0    /*     END_COLLECTION	             */
    };
    
    static int8_t CUSTOM_HID_OutEvent_FS(uint8_t event_idx, uint8_t state)
    {
      /* USER CODE BEGIN 6 */
       USBD_CUSTOM_HID_HandleTypeDef     *hhid = (USBD_CUSTOM_HID_HandleTypeDef*)hUsbDeviceFS.pClassData;
    
      for (uint8_t i = 0; i < 4; i++)
    
      {
    
        dataToReceive[i] = hhid->Report_buf[i];
    
      } 
      
      if(dataToReceive[0]==0x01)
        HAL_GPIO_WritePin(GPIOA, GPIO_PIN_3, GPIO_PIN_SET);
      else
        HAL_GPIO_WritePin(GPIOA, GPIO_PIN_3, GPIO_PIN_RESET);
      return (USBD_OK);
      /* USER CODE END 6 */
    }
        
    В мейне:
        
      /* USER CODE BEGIN 2 */
      dataToSend[0] = 'S';
      dataToSend[1] = 'n';
      dataToSend[2] = 'd';
      dataToSend[3] = '\0';
      /* USER CODE END 2 */
    
      /* Infinite loop */
      /* USER CODE BEGIN WHILE */
      while (1)
      {
        /* USER CODE END WHILE */
        HAL_Delay(1000);
        USBD_CUSTOM_HID_SendReport(&hUsbDeviceFS, dataToSend, 4);
        /* USER CODE BEGIN 3 */
      }

    Проблемы с тем на базе какой библиотеки на компе код удобней делать. в исходной статье применяли libusb но почему-то не смог найти той версии, по которой делали статью. по другим статьям тоже ничего не вышло

    Смотрел WinUSB там вообще не понятно как этим пользоваться

    взял HIDAPI на ней по примерам получилось увидеть мою плату но не получается отправить и получить данные

    Spoiler
    #include <iostream>
    #include <windows.h>
    #include <winusb.h>
    #include <usb.h>
    
    #include "hidapi.h"
    
    void print_device(struct hid_device_info* cur_dev) {
        printf("Device Found\n  type: %04hx %04hx\n  path: %s\n  serial_number: %ls", cur_dev->vendor_id, cur_dev->product_id, cur_dev->path, cur_dev->serial_number);
        printf("\n");
        printf("  Manufacturer: %ls\n", cur_dev->manufacturer_string);
        printf("  Product:      %ls\n", cur_dev->product_string);
        printf("  Release:      %hx\n", cur_dev->release_number);
        printf("  Interface:    %d\n", cur_dev->interface_number);
        printf("  Usage (page): 0x%hx (0x%hx)\n", cur_dev->usage, cur_dev->usage_page);
        printf("  Bus type: %d\n", cur_dev->bus_type);
        printf("\n");
    }
    
    void print_devices(struct hid_device_info* cur_dev) {
        while (cur_dev) {
            print_device(cur_dev);
            cur_dev = cur_dev->next;
        }
    }
    
    int main(int argc, char* argv[])
    {
        (void)argc;
        (void)argv;
    
        int res;
        unsigned char buf[256];
    #define MAX_STR 255
        wchar_t wstr[MAX_STR];
        hid_device* handle;
        int i;
    
       // struct hid_device_info* devs;
    
        if (hid_init())
            return -1;
    
       // devs = hid_enumerate(0x0, 0x0);
       // print_devices(devs);
       // hid_free_enumeration(devs);
    
        // Set up the command buffer.
        memset(buf, 0x00, sizeof(buf));
        buf[0] = 0x01;
        buf[1] = 0x81;
    
    
        // Open the device using the VID, PID,
        // and optionally the Serial number.
        ////handle = hid_open(0x4d8, 0x3f, L"12345");
        handle = hid_open(0x0485, 0x5752, NULL);
        if (!handle) {
            printf("unable to open device\n");
            hid_exit();
            return 1;
        }
    
        // Read the Manufacturer String
        wstr[0] = 0x0000;
        res = hid_get_manufacturer_string(handle, wstr, MAX_STR);
        if (res < 0)
            printf("Unable to read manufacturer string\n");
        printf("Manufacturer String: %ls\n", wstr);
    
        // Read the Product String
        wstr[0] = 0x0000;
        res = hid_get_product_string(handle, wstr, MAX_STR);
        if (res < 0)
            printf("Unable to read product string\n");
        printf("Product String: %ls\n", wstr);
    
        // Read the Serial Number String
        wstr[0] = 0x0000;
        res = hid_get_serial_number_string(handle, wstr, MAX_STR);
        if (res < 0)
            printf("Unable to read serial number string\n");
        printf("Serial Number String: (%d) %ls", wstr[0], wstr);
        printf("\n");
    
        struct hid_device_info* info = hid_get_device_info(handle);
        if (info == NULL) {
            printf("Unable to get device info\n");
        }
        else {
            print_devices(info);
        }
    /*
        // Read Indexed String 1
        wstr[0] = 0x0000;
        res = hid_get_indexed_string(handle, 1, wstr, MAX_STR);
        if (res < 0)
            printf("Unable to read indexed string 1\n");
        printf("Indexed String 1: %ls\n", wstr);
        */
        // Set the hid_read() function to be non-blocking.
        hid_set_nonblocking(handle, 1);
    
    
        struct
        {
            uint8_t reportID;
            uint8_t data[4];
        } report;
    
        report.reportID = 0x01;
        report.data[0] = 0x01;
        res = hid_write(handle, (const unsigned char*)&report, sizeof(report));
        if (res < 0) {
            printf("Unable to write(report): %ls\n", hid_error(handle));
        }
    
        res = hid_send_feature_report(handle, (const unsigned char*)&report, sizeof(report));
        if (res < 0) {
            printf("((Unable to send a feature report)).\n");
        }
    
    
    
    
    
    
        buf[0] = 0x81;
        res = hid_get_feature_report(handle, buf, 5);
        if (res < 0) {
            printf("Unable to get a feature report: %ls\n", hid_error(handle));
        }
        else {
            // Print out the returned buffer.
            printf("Feature Report\n   ");
            for (i = 0; i < res; i++)
                printf("%02x ", (unsigned int)buf[i]);
            printf("\n");
        }
        memset(buf, 0, sizeof(buf));
        // Send a Feature Report to the device
        buf[0] = 0x01;
        buf[1] = 0x01;
        buf[2] = 0x01;
        buf[3] = 0x01;
        buf[4] = 0x01;
        res = hid_send_feature_report(handle, buf, 4);
        if (res < 0) {
            printf("Unable to send a feature report.\n");
        }
    
        
        
        
        
        memset(buf, 0, sizeof(buf));
    
        // Toggle LED (cmd 0x80). The first byte is the report number (0x1).
        buf[0] = 0x01;
        buf[1] = 0x01;
        buf[2] = 0x01;
        res = hid_write(handle, buf, 4);
        if (res < 0) {
            printf("Unable to write(): %ls\n", hid_error(handle));
        }
        memset(buf, 0, sizeof(buf));
    
        // Request state (cmd 0x81). The first byte is the report number (0x1).
        buf[0] = 0x01;
        buf[1] = 0x81;
        hid_write(handle, buf, 4);
        if (res < 0) {
            printf("Unable to write()/2: %ls\n", hid_error(handle));
        }
        
        // Read requested state. hid_read() has been set to be
        // non-blocking by the call to hid_set_nonblocking() above.
        // This loop demonstrates the non-blocking nature of hid_read().    res = 0;
        i = 0;
        while (res == 0) {
            res = hid_read(handle, buf, 4);
            if (res == 0) {
                printf("waiting...\n");
            }
            if (res < 0) {
                printf("Unable to read(): %ls\n", hid_error(handle));
                break;
            }
    
            i++;
            if (i >= 10) { /* 10 tries by 500 ms - 5 seconds of waiting*/
                printf("read() timeout\n");
                break;
            }
    
            Sleep(500);
    
        }
    
        if (res > 0) {
            printf("Data read:\n   ");
            // Print out the returned buffer.
            for (i = 0; i < res; i++)
                printf("%02x ", (unsigned int)buf[i]);
            printf("\n");
        }
    
        hid_close(handle);
    
        /* Free static HIDAPI objects. */
        hid_exit();
    
    #ifdef _WIN32
        system("pause");
    #endif
    
        return 0;
    }

    Кто какие библиотеки использует? Может у кого есть рабочий пример для стороны контроллера и компа?

  2. Организовал в итоге работу 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. 22 часа назад, AVI-crak сказал:
      Скрыть контент
    #include "gpio_one.h" /// https://github.com/AVI-crak/gpio_one
    
    void SPI3_Init()
    {
    	RCC->APB1ENR |= RCC_APB1ENR_SPI3EN;
        RCC->AHB1ENR |= RCC_AHB1ENR_DMA1EN;
    	RCC->AHB1ENR |= RCC_AHB1ENR_GPIOCEN;
    	RCC->AHB1ENR |= RCC_AHB1ENR_GPIOAEN;
    
    	gpio_one_pin(zap_gpio.C.pin10.v_af06_i2s3_ck_spi3_sck.speed4.lock_on);
        gpio_one_pin(zap_gpio.C.pin11.v_af06_spi3_miso.speed4.lock_on);
        gpio_one_pin(zap_gpio.C.pin12.v_af06_i2s3_sd_spi3_mosi.speed4.lock_on);
        gpio_one_pin(zap_gpio.A.pin15.v_af06_i2s3_ws_spi3_nss.speed4.lock_on);
    
        SPI3->CR1  = 0x0;
        SPI3->CR2 = SPI_CR2_SSOE |              //Вывод NSS - выход управления
                    SPI_CR2_TXDMAEN;
    
        SPI3->CR1 = _VAL2FLD(SPI_CR1_BR, 2)|    // Baud rate control /8
                    SPI_CR1_MSTR |              // Режим Master
                    SPI_CR1_BIDIMODE |          // 1 линия
                    SPI_CR1_BIDIOE  |           // только передача
                    SPI_CR1_SPE;                // вкл
    };
    
    
    void SPI3_Send(volatile uint8_t *data, uint16_t len)
    {
    	DMA1->LIFCR = (DMA_LIFCR_CTCIF0 | DMA_LIFCR_CHTIF0 | DMA_LIFCR_CTEIF0 | DMA_LIFCR_CDMEIF0 | DMA_LIFCR_CFEIF0);
        DMA1_Stream5->CR = 0;
        DMA1_Stream5->FCR = 0;
        DMA1_Stream5->NDTR = len;
        DMA1_Stream5->M0AR = (uint32_t)data;
        DMA1_Stream5->PAR = (uint32_t)(&SPI3->DR);
        DMA2_Stream5->CR =
    		_VAL2FLD(DMA_SxCR_CHSEL, 0)|	/// channe - tmigger
            _VAL2FLD(DMA_SxCR_DIR, 1)|		/// memory_to_peripheral
            _VAL2FLD(DMA_SxCR_MBURST, 1)|	/// incremental_burst_of_4_beats
            DMA_SxCR_MINC|					/// memory increment mode
            DMA_SxCR_EN;
        while(!(DMA1->LISR & DMA_LISR_TCIF0 ));
    	while((SPI3->SR & (SPI_SR_BSY | SPI_SR_TXE)) != SPI_SR_TXE);
    };

     

    DMA2_Stream5->CR  заменил на DMA1_Stream5->CR

    так-же у DMA1->HISR TEIF5 и FEIF5 = 1

     

     

  4. Проц 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
    }

     

    Нужно ли обработчик прерывания делать если оно у меня не используется?

  5. Инициализация 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

     

  6. 13 минут назад, AVI-crak сказал:

    Желательно использовать макрос _VAL2FLD(field, value) для заполнения полей регистра, он позволяет избежать ошибки переполнения. DMA кроме номера потока (в названии), имеет номер канала - по которому принимает управление на запись/чтение CHSEL[3:0]. Информация о каналах DMA находится Reference manual для вашего мк.

     Регистр DMAx_Streamx->CR имеет 19 обязательных полей для заполнения, буквально 19 строк. Каждый раз печатать одинаковые буквы весьма утомительно, одинаковые буквы для любого дма. Проще один раз напечатать запись в переменную всех обязательных полей, и при copy/paste - удалять ненужное в данный момент. Удалять проще чем печатать заново.

    Канал 0

    какие я регистры не заполнил из обязательных?

    19 минут назад, Сергей Борщ сказал:

     

    уже исправлено

    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);

    Спасибо

  7. Доброго времени суток

    Подскажите пожалуйста, что я делаю не так в настройке 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);
        

     

  8. 13 hours ago, tonyk_av said:

    Если МК мастер, то тебе достаточно перед отправкой сделать паузу >1.75мс (заметь, "больше", а не строго "равно" ), что при работе под FreeRTOS не вызывает проблем. Пишешь код под ОС РВ, а софтовые таймеры ОС упорно игнорируешь, хотя тут они очень удобны.

     

    у меня нет ОС.... не добавлять же её только из-за работы с ModBUS

  9. 39 minutes ago, jcxz said:

    Это всё элементарно делается на одном таймере.

    Так у меня и так на одном таймере, на TIM7 оба события....

    в зависимости от состояния перестраиваю время срабатывания прерывания.

    40 minutes ago, jcxz said:

    Я про неё ещё несколько десятков постов назад писал. Странно что не заметили.....

    Видимо проглядел... спасибо

  10. у меня задача попроще. есть 10 серводвигателей и нужно постоянно циклически их положение получать.

    Без таймера нормально не работает - нужна задержка между отправкой текущего пакета и следующего.

    так-же таймаут нужно как-то определять

    Про паузу после перевода трансмиттера в режим передачи и отправку пакета добавлю. спасибо

  11. Задачи 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();
    }

     

  12. Пофиксил. Не хватало сброса флага окончания передачи из уарта в память на приеме

    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);
    	}
    }

     

  13. Видимо я что-то не так с ДМА делаю, в rx_buff заполняется первый ответный пакет и после этого данные в нём не меняются, хотя ответы разные на шине присутствуют

    нужно ли перед повторным включением DMA на прием сбрасывать какой-нибудь счетчик?

  14. Продолжаю изыскания по организации общения через 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 меняется сигнал во время отправки одного целого пакета

  15. При выключенном, конечно, не нужны. но его же нужно будет включить.

    этот "паравоз" я привел вот к такому виду:

    DMA2_Stream5->CR = 0
            | DMA_SxCR_CHSEL_2                                // Выбираем 4 канал
            | DMA_SxCR_MINC                                    // Инкремент адреса памяти
            | DMA_SxCR_PFCTRL                                // DMA - Ведомый

    При каждом включении необходимо будет вставить этот кусок кода, затрудняя возможность внесения изменений в инициализацию, через пол года можно забыть в каких местах в коде включение работы DMA происходит, а если этот код другому человеку поддеживать придется?

    стараюсь всегда всю конфигурацию вынести в одно место а не размазывать по коду без крайней необходимости

    С точки зрения эффективности со стороны работы процессора да - ваша рекомендация хороша, не спорю.

    с точки зрения поддержки кода не совсем...

    кроме инлайн функции не вижу другого выхода из ситуации, чтобы оптимизировать код со стороны работы процессора и не потерять его гибкость изменения и поддержки.

    В любом случае, спасибо за вашу помощь и советы

×
×
  • Создать...