Merhabalar .
uart dma üzerinden veri alıyorum gelen datanın uzunluğu belli değil o yüzden line idle kesmesi oluşturdum sorunsuz çalışıyor.
Kesme ayarları:
__HAL_UART_ENABLE_IT(&huart1, UART_IT_IDLE);
HAL_UART_Receive_DMA(&huart1, (uint8_t*)receive_buff, 255);
DMA Ayarları:
hdma_usart1_rx.Instance = DMA2_Stream2;
hdma_usart1_rx.Init.Channel = DMA_CHANNEL_4;
hdma_usart1_rx.Init.Direction = DMA_PERIPH_TO_MEMORY;
hdma_usart1_rx.Init.PeriphInc = DMA_PINC_DISABLE;
hdma_usart1_rx.Init.MemInc = DMA_MINC_ENABLE;
hdma_usart1_rx.Init.PeriphDataAlignment = DMA_PDATAALIGN_BYTE;
hdma_usart1_rx.Init.MemDataAlignment = DMA_MDATAALIGN_BYTE;
hdma_usart1_rx.Init.Mode = DMA_CIRCULAR;
hdma_usart1_rx.Init.Priority = DMA_PRIORITY_VERY_HIGH;
hdma_usart1_rx.Init.FIFOMode = DMA_FIFOMODE_DISABLE;
if (HAL_DMA_Init(&hdma_usart1_rx) != HAL_OK)
buffer boyutu normalde uint16_t tanımlı olmasına rağmen 255'in üstüne çıktığında çalışmıyor.
gelen tüm datalar 50-100 byte arasında sadece 1 tanesi 300 byte üzerinde bir burst.
buffer size'ı 255 iken 300 btye'lık mesajı almaya çalışırsam startup dosyasında aşağıdaki satıra düşüyorum ve orada kalıyor.
buffer size'ı 400 yapıyorum yine aynı şekilde aynı satıra düşüyorum.
Default_Handler PROC
EXPORT WWDG_IRQHandler [WEAK]
EXPORT PVD_IRQHandler [WEAK]
EXPORT TAMP_STAMP_IRQHandler [WEAK]
EXPORT RTC_WKUP_IRQHandler [WEAK]
....
....
....
DMA2_Stream7_IRQHandler
USART6_IRQHandler
I2C3_EV_IRQHandler
I2C3_ER_IRQHandler
FPU_IRQHandler
SPI4_IRQHandler
B . (BURAYA DÜŞÜYOR)
ENDP
ALIGN
DMA buffer size'ı 255'i geçemez mi? yoksa uart kaynaklı bir sorunla mı karşı karşıyayım?
Bilgisi olan beni yönlendirebilir mi?
DMA'nın transfer limiti 65535 transfer, ki bu transferler 8 bit olabileceği gibi 16 veya 32 bit de olabilir. Yani donanımsal olarak 255 gibi bir sınır yok, o kesin.
Programda
uint8_t receive_buff[400]; gibi yeterince büyük bir buffer tanımladığını varsayıyorum.
HAL'ı hiç bilmiyorum, ancak tahminimce
HAL_UART_Receive_DMA() içindeki 255 değeri ilgili DMA'nın
NDTR register'ını ayarlıyor olsa gerek. Bu register normalde byte değil transfer sayısını belirliyor ama sen yine de foksiyonun dokümanına bak. Gerçi sende veri genişliği 8 bit, bu sebeple zaten byte sayısı ile transfer sayısı aynı şey senin durumda.
DMA'yı
circular olarak tanımlamana gerek yok bence. Bunu yaptığında, senin girdiğin boyut aşıldıktan sonra DMA buffer'ın başına dönüp yazmaya devam edecek ve muhtemelen eski mesajı bozacak.
Ben DMA kullanan Modbus uygulamamda şöyle yapmıştım:
Idle kesmesi gelince DMA'yı kapatıp durumu ana programa bir bayrak ile bildiriyordum. Ama bundan önce kesme içinde USART ve DMA kesme bayraklarını temizleyip, DMA'yı yeni bir alım için tekrar kuruyordum. Buffer'ı da ana programda işliyordum.
Daha önce STM32F407 için yazdığım Modbus kodunun ilgili kesme bölümü aşağıda (olduğu gibi kopyala yapıştır yapıyorum, içinde doğrudan ilgili olmayan şeyler de olabilir):
void USARTn_IRQHandler(void) {
uint32_t dummy;
// Idle detection - End of Modbus package
if ((USARTn->SR & USART_SR_IDLE) != 0) {
DMA_RX->CR &= ~DMA_SxCR_EN; // "Idle detected" means RX frame is completed
if (rxBuffer[0] != slaveAddress) { // Was it for us?
state = IDLE;
reArmRxDMA();
}
else {
state = FRAME_COMPLETE; // Address matches
}
dummy = USARTn->SR; // Dummy read for IDLE clear sequence
dummy = USARTn->DR; // Dummy read for IDLE clear sequence
}
// Transfer completed interrupt (USART TX, for disabling RS485 DE signal)
if ((USARTn->SR & USART_SR_TC) != 0) {
USARTn->CR1 &= ~USART_CR1_TCIE; // Disable TC interrupt
USARTn->SR &= ~USART_SR_TC; // Clear TC flag
RESET_PIN(RS485_DE);
}
}
inline void reArmRxDMA() {
DMA_RX->NDTR = RX_BUFFER_SIZE;
DMA2->LIFCR |= DMA_LIFCR_CFEIF2 | DMA_LIFCR_CTCIF2 | DMA_LIFCR_CHTIF2; // Clear interrupt flags
DMA_RX->CR |= DMA_SxCR_EN; // Enable DMA
}
Bu mesaja denk gelen ve başka ailelerden (F0, F1 gibi) işlemciler kullanan arkadaşlara bir uyarı: F4 ile F0 & F1 arasında DMA ayarlarında farklılıklar bulunur. Kodu biraz elden geçirmeden taşımanız mümkün değil.
Bu arada, debug sırasında
Fault durumunun oluşup oluşmadığını bir kontrol et. Sanki tanımsız bir kesme koduna sıçrıyor gibi ama bu hatalı bir kesme aktivasyonu olabileceği gibi bir
Fault durumu da olabilir.
@Tagli hocam cevabınız için teşekkür ederim.
Alıntı yapılan: Tagli - 17 Şubat 2021, 11:44:47Programda uint8_t receive_buff[400]; gibi yeterince büyük bir buffer tanımladığını varsayıyorum.
Aynen öyle yaptım.
hem uart hem dma handlerda errorcode oluşmuyordu ama fault durumlarına akşam tekrar bakarım.
aslında dma buffer'da mesajın tamamını görüyorum 300 bytelık mesaj geldiğinde dma bufferda mesajı tam olarak görmeme rağmen line idle tetiklenmiyor ve bahsettiğiniz gibi sanırım tanımlı olmayan bir kesmeye sıçramaya çalışıyor.