Turgenev 1 6 октября, 2023 Опубликовано 6 октября, 2023 · Жалоба Запускаю ЦАП AD5320BRTZ-500RL7 на STM32F407 при помощи HAL, использую SPI на скорости 62 кб/с и софтовый чип-селект, настроенный как GPIO_SPEED_FREQ_VERY_HIGH. Вот таким кодом в блокирующем режиме я успешно устанавливаю требуемое напряжение на выходе ЦАП: Спойлер HAL_StatusTypeDef DAC_send_spi (DAC_config_packet_t config_packet) { uint8_t mode; /// - переменная для хранения режима ЦАП, извлеченного из переданного в функцию экземпляра; uint16_t value; /// - переменная для хранения значения ЦАП, извлеченного из переданного в функцию экземпляра; uint8_t dac_spi_tx_packet[2]; /// - массив для отправки в ЦАП; /// - парсим экземпляр; mode = config_packet.dac_mode; value = config_packet.dac_value; /// - обнуление не значащих бит; mode &= ~0xFC; value &= ~0xF000; /// - формирование массива из двух байт для отправки в ЦАП; dac_spi_tx_packet[0] = (uint8_t) ((mode<<4) | (value>>8)); dac_spi_tx_packet[1] = (uint8_t) value; /// - опускаем чип-селект SPI1; HAL_GPIO_WritePin(DAC_SYNC_1_GPIO_Port, DAC_SYNC_1_Pin, GPIO_PIN_RESET); /// - отправка команды в ЦАП по SPI1 в блокирующем режиме; HAL_StatusTypeDef status = HAL_SPI_Transmit(&hspi1, dac_spi_tx_packet, 2, 100); HAL_GPIO_WritePin(DAC_SYNC_1_GPIO_Port, DAC_SYNC_1_Pin, GPIO_PIN_SET); return status; } Но стало интересно передать при помощи DMA. Меняю код, у DMA приоритет very high. Чип-селект поднимаю в прерывании по окончанию передачи: Спойлер HAL_StatusTypeDef DAC_send_spi (DAC_config_packet_t config_packet) { uint8_t mode; /// - переменная для хранения режима ЦАП, извлеченного из переданного в функцию экземпляра; uint16_t value; /// - переменная для хранения значения ЦАП, извлеченного из переданного в функцию экземпляра; uint8_t dac_spi_tx_packet[2]; /// - массив для отправки в ЦАП; /// - парсим экземпляр; mode = config_packet.dac_mode; value = config_packet.dac_value; /// - обнуление не значащих бит; mode &= ~0xFC; value &= ~0xF000; /// - формирование массива из двух байт для отправки в ЦАП; dac_spi_tx_packet[0] = (uint8_t) ((mode<<4) | (value>>8)); dac_spi_tx_packet[1] = (uint8_t) value; /// - опускаем чип-селект SPI1; HAL_GPIO_WritePin(DAC_SYNC_1_GPIO_Port, DAC_SYNC_1_Pin, GPIO_PIN_RESET); /// - отправка команды в ЦАП по SPI1 в блокирующем режиме; HAL_StatusTypeDef status = HAL_SPI_Transmit_DMA(&hspi1, dac_spi_tx_packet, 2); return status; } void HAL_SPI_TxCpltCallback(SPI_HandleTypeDef *hspi) { /// Включает в себя следующие операции: /// - если переданный в структуру экземпляр это hspi1, то: if (hspi == &hspi1) { /// - поднимаем чип-селект SPI1; HAL_GPIO_WritePin(DAC_SYNC_1_GPIO_Port, DAC_SYNC_1_Pin, GPIO_PIN_SET); } } В итоге получается, что ЦАП устанавливает значение напряжения, смещенное на 1 бит вправо относительно требуемого (напряжение в 2 раза меньше требуемого). При передаче по прерыванию та же самая проблема. Читал что писали здесь про подобные проблемы, про жертвы SPL и отслеживания флагов в интерфейсе SPI. Сомневаюсь, что HAL библиотекой не добиться нормальной передачи. Был бы признателен, если подскажите куда копать, чтобы решить проблему только библиотекой HAL. Код инициализации SPI: Спойлер hspi1.Instance = SPI1; hspi1.Init.Mode = SPI_MODE_MASTER; hspi1.Init.Direction = SPI_DIRECTION_2LINES; hspi1.Init.DataSize = SPI_DATASIZE_8BIT; hspi1.Init.CLKPolarity = SPI_POLARITY_HIGH; hspi1.Init.CLKPhase = SPI_PHASE_1EDGE; hspi1.Init.NSS = SPI_NSS_SOFT; hspi1.Init.BaudRatePrescaler = SPI_BAUDRATEPRESCALER_256; hspi1.Init.FirstBit = SPI_FIRSTBIT_MSB; hspi1.Init.TIMode = SPI_TIMODE_DISABLE; hspi1.Init.CRCCalculation = SPI_CRCCALCULATION_DISABLE; hspi1.Init.CRCPolynomial = 10; if (HAL_SPI_Init(&hspi1) != HAL_OK) { Error_Handler(); } Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
dimka76 62 6 октября, 2023 Опубликовано 6 октября, 2023 · Жалоба On 10/6/2023 at 11:30 AM, Turgenev said: Был бы признателен, если подскажите куда копать, чтобы решить проблему только библиотекой HAL. Осциллографом надо посмотреть, что там на SPI твориться. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
deni 6 6 октября, 2023 Опубликовано 6 октября, 2023 · Жалоба Надо использовать событие по окончанию RX, даже если прием не используете. Событие по TX это когда освободился буфер передатчика, но передача ещё продолжается из сдвигового регистра. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
Turgenev 1 6 октября, 2023 Опубликовано 6 октября, 2023 · Жалоба 1 минуту назад, deni сказал: Надо использовать событие по окончанию RX, даже если прием не используете. Событие по TX это когда освободился буфер передатчика, но передача ещё продолжается из сдвигового регистра. Читал про это на форуме и попробовал поднимать чип-селект по колбеку приема: Спойлер void HAL_SPI_RxCpltCallback(SPI_HandleTypeDef *hspi) { /// Включает в себя следующие операции: /// - если переданный в структуру экземпляр это hspi1, то: if (hspi == &hspi1) { /// - поднимаем чип-селект SPI1; HAL_GPIO_WritePin(DAC_SYNC_1_GPIO_Port, DAC_SYNC_1_Pin, GPIO_PIN_SET); } } Ничего не изменилось- так же сдвинут пакет на ЦАПе. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
deni 6 6 октября, 2023 Опубликовано 6 октября, 2023 · Жалоба 4 минуты назад, Turgenev сказал: Ничего не изменилось- так же сдвинут пакет на ЦАПе. Прием никак не может закончится раньше, чем когда придет последний клок. Может у вас полярность и фаза клока неверно настроена? Надо смотреть логическим анализатором, что происходит на линиях. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
Edit2007 3 6 октября, 2023 Опубликовано 6 октября, 2023 · Жалоба проверьте фазу формирования сигнала относительно CLK. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
Turgenev 1 6 октября, 2023 Опубликовано 6 октября, 2023 · Жалоба 21 минуту назад, deni сказал: Может у вас полярность и фаза клока неверно настроена? 20 минут назад, Edit2007 сказал: проверьте фазу формирования сигнала относительно CLK. C ней я много намучался. Но если было бы неправильно настроено, смог бы я отправлять правильно в блокирующем режиме? А ведь в нем у меня проблем нет. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
deni 6 6 октября, 2023 Опубликовано 6 октября, 2023 (изменено) · Жалоба 26 минут назад, Turgenev сказал: C ней я много намучался. Но если было бы неправильно настроено, смог бы я отправлять правильно в блокирующем режиме? А ведь в нем у меня проблем нет. В блокирующем режиме в конце опрашивается флаг SPI_FLAG_BSY. Возможно в режиме DMA код HAL не дожидается окончания передачи. И если даже использовать окончание по RX, оно будет вызвано раньше на пол клока окончания передачи. Так как частота SPI у вас не высокая, контроллер успевает выставить CS на GPIO раньше окончания передачи. Изменено 6 октября, 2023 пользователем deni Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
Turgenev 1 6 октября, 2023 Опубликовано 6 октября, 2023 · Жалоба 1 минуту назад, deni сказал: Так как частота SPI у вас не высокая контроллер успевает выставить CS на GPIO раньше окончания передачи. Ок. Попробую передавать по DMA на бОльшей скорости и со всеми режимами полярности и фазы. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
Turgenev 1 6 октября, 2023 Опубликовано 6 октября, 2023 · Жалоба Хотя. Так надоело гадать. Подскажите как по ДШ надо было это все понять и настроить с первого раза. Судя по временной диаграмме (скрин) на полярность тактового сигнала все равно. Судя по той же диаграмме и описанию (скрин), смотреть надо по ниспадающему фронту, то есть hspi1.Init.CLKPhase = SPI_PHASE_1EDGE; Спойлер Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
deni 6 6 октября, 2023 Опубликовано 6 октября, 2023 · Жалоба 22 минуты назад, Turgenev сказал: Хотя. Так надоело гадать. Подскажите как по ДШ надо было это все понять и настроить с первого раза. Выкинуть Cube и HAL, сделать на LL. 25 минут назад, Turgenev сказал: Судя по временной диаграмме (скрин) на полярность тактового сигнала все равно. Судя по диаграмме, нужно установить CS (SYNC), потом снять CS (SYNC) и потом по SPI выдать данные привязанные к падающему фронту. Если хочется полной автоматизации передачи, то проще по таймеру по одному из каналов выдать импульс SYNC через PWM и по далее по событию от таймера через DMA в SPI выдать данные. 1 Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
jcxz 239 6 октября, 2023 Опубликовано 6 октября, 2023 · Жалоба 14 минут назад, deni сказал: Если хочется полной автоматизации передачи, то проще по таймеру по одному из каналов выдать импульс SYNC через PWM и по далее по событию от таймера через DMA в SPI выдать данные. Именно так и работаю сейчас с аналогичной AD5322: LDAC формируется ШИМ-ом, а передачи 2-х слов между импульсами LDAC - посредством таймер->DMA->SPI(с аппаратным формированием CS). Таймер, раз в период, пинает DMA, тот читает 1 слово из ОЗУ и пишет 2 полуслова в SPI (2 фрейма получается). Работает как часы. Без всяких Кубов и Калов. На скорости на ~порядок выше. При том, что процессор у меня гораздо слабее чем у ТС. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
dimka76 62 6 октября, 2023 Опубликовано 6 октября, 2023 · Жалоба On 10/6/2023 at 2:11 PM, jcxz said: Без всяких Кубов и Калов. Это же надо в Reference Manual вникать On 10/6/2023 at 2:00 PM, deni said: Судя по диаграмме, нужно установить CS (SYNC), потом снять CS (SYNC) и потом по SPI выдать данные привязанные к падающему фронту. Немного не так. SYNC должен быть в единице между транзакциями. Это тот же самый переименованный CS. Quote Level Triggered Control Input (Active Low). This is the frame synchronization signal for the input data. When SYNC goes low, it enables the input shift register and data is transferred in on the falling edges of the following clocks. The DAC is updated following the 16th clock cycle unless SYNC is taken high before this edge, in which case the rising edge of SYNC acts as an interrupt and the write sequence is ignored by the DAC. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
Turgenev 1 6 октября, 2023 Опубликовано 6 октября, 2023 · Жалоба 35 минут назад, deni сказал: Если хочется полной автоматизации передачи, то проще по таймеру по одному из каналов выдать импульс SYNC через PWM и по далее по событию от таймера через DMA в SPI выдать данные. Чем моя реализация плоха с установкой/сброса пина чип-селекта, зачем делать это именно через ШИМ? Все в свое время выполняется же, кроме окончания- но я ради интереса подождал пару секунд перед очередным подъемом чип-селекта после передачи пакета. Без разницы. 38 минут назад, deni сказал: Выкинуть Cube и HAL, сделать на LL. Тогда конкретный вопрос: чисто на HAL-функциях нормальную передачу по SPI не сделать что ли? Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
dimka76 62 6 октября, 2023 Опубликовано 6 октября, 2023 · Жалоба On 10/6/2023 at 2:39 PM, Turgenev said: Чем моя реализация плоха с установкой/сброса пина чип-селекта, зачем делать это именно через ШИМ? Все в свое время выполняется же, кроме окончания- но я ради интереса подождал пару секунд перед очередным подъемом чип-селекта после передачи пакета. Без разницы В вашем случае смысл передачи по DMA пропадает, т.к. все равно приходится отвлекаться на дергание ножкой CS. Для такого режима передачи проще использовать прерывания от SPI. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться