stm32F401 UART DMA Sourunu

Başlatan e-zeki, 17 Şubat 2021, 12:57:54

e-zeki

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(&huart1UART_IT_IDLE);
HAL_UART_Receive_DMA(&huart1, (uint8_t*)receive_buff255);

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?

Tagli

17 Şubat 2021, 14:44:47 #1 Son düzenlenme: 17 Şubat 2021, 14:46:48 Tagli
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.
Gökçe Tağlıoğlu

e-zeki

@Tagli hocam cevabınız için teşekkür ederim.

Alıntı yapılan: Tagli - 17 Şubat 2021, 14: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.

Yasal Uyarı: Picproje.org sitemizde 5651 sayılı kanunun 8. maddesine ve T.C.Knın 125. maddesine göre tüm üyelerimiz yaptıkları paylaşımlardan kendileri sorumludur. Picproje.org hakkında yapılacak tüm hukuksal şikayetleri İletişim sayfamızdan bize bildirdikten en geç 3 (üç) iş günü içerisinde ilgili kanunlar ve yönetmelikler çerçevesinde tarafımızca incelenerek gereken işlemler yapılacak ve site yöneticilerimiz tarafından bilgi verilecektir.