Anonim Napisano Luty 24, 2020 Udostępnij Napisano Luty 24, 2020 (edytowany) Nieczęsto korzystam z I2C w swoich projektach i jak do tej pory nie miałem żadnych przygód z działaniem DMA. Jednak postanowiłem urozmaicić swój projekt o wyświetlacz oled i2c przy którym siłą rzeczy użycie DMA samo się sugeruje i.. spotkała mnie niemiła niespodzianka. Otóż przy wywołaniu funkcji po przekopiowaniu bufora do oleda program kończył swoje działanie w HardFault_Handler. Okazało się, że przyczyną jest brak stopu na końcu transmisji I2C. Częściowo rozwiązałem problem wpisując stop do przerwania od końca transmisji ręcznie ale nie jestem pewien czy to rozwiązanie jest zupełnie prawidłowe. Być może da się zmusić HALa aby jednak ten stop wysyłał lub trzeba ustawić coś gdzieś tylko nie wiem jak. Może ktoś z was miał z tym podobny problem? Pozostałe funkcje obsługi I2C działają bez problemu. Edytowano Luty 24, 2020 przez Anonim aktualizacja Cytuj Link do komentarza Share on other sites More sharing options...
Zealota Luty 24, 2020 Udostępnij Luty 24, 2020 (edytowany) Jeśli chodzi o F0x2 to mamy taki wpis w RM: "Automatic end mode (AUTOEND = ‘1’ in the I2C_CR2 register). In this mode, the master automatically sends a STOP condition once the number of bytes programmed in the NBYTES[7:0] bit field has been transferred." Zacząłbym od sprawdzenia czy AUTOEND jest ustawiony w rejestrze, pod debuggerem, jeśli nie to oczywiście należy go zmodyfikować. W innych rodzinach należałoby sprawdzić czy odpowiednia funkcja jest dostępna. Edytowano Luty 24, 2020 przez Zealota Cytuj Link do komentarza Share on other sites More sharing options...
marek1707 Luty 24, 2020 Udostępnij Luty 24, 2020 To nie tak. W L4 (tych ostatnio używam najczęściej) zdefiniowano max. liczbę bajtów do przesłania po I2C (MAX_NBYTE_SIZE) na 255. Jeżeli przekroczysz tę liczbę - a przy wyświetlaczu to żaden problem, to wywołanie funkcji ..._DMA() nie może wręcz wygenerować STOPu, bo przecież transfer nie został zakończony. HAL sprawdza czy to co zleciłeś do przesłania jest większe niż 255 bajtów i jeśli tak, ustawia tryb zakończenia na I2C_RELOAD_MODE oczekując dalszych paczek danych. W przeciwnym wypadku pierwszy transfer jest ostatnim i tryb jest ustawiany na I2C_AUTOEND_MODE (plik stm32l4xx_hal_i2c.c). Dla wyjaśnienia, poniższe XferCount zostało gdzieś wcześniej załadowane wartością parametru Size z wywołania funkcji ..._DMA(): if(hi2c->XferCount > MAX_NBYTE_SIZE) { hi2c->XferSize = MAX_NBYTE_SIZE; xfermode = I2C_RELOAD_MODE; } else { hi2c->XferSize = hi2c->XferCount; xfermode = I2C_AUTOEND_MODE; } A to co się stanie po zatrzymaniu (np. kontynuację) sam musisz sobie oprogramować (UM1884 "Description of STM32L4/L4+ HAL and low-layer drivers"): DMA mode IO MEM operation - Write an amount of data in non-blocking mode with DMA to a specific memory address using HAL_I2C_Mem_Write_DMA() - At Memory end of write transfer, HAL_I2C_MemTxCpltCallback() is executed and user can add his own code by customization of function pointer HAL_I2C_MemTxCpltCallback() - Read an amount of data in non-blocking mode with DMA from a specific memory address using HAL_I2C_Mem_Read_DMA() - At Memory end of read transfer, HAL_I2C_MemRxCpltCallback() is executed and user can add his own code by customization of function pointer HAL_I2C_MemRxCpltCallback() - In case of transfer Error, HAL_I2C_ErrorCallback() function is executed and user can add his own code by customization of function pointer HAL_I2C_ErrorCallback() So, RTFM pls, a jeśli nie lubisz czytać, to zawsze możesz obejrzeć kod funkcji w bibliotece - to zwykle wszystko wyjaśnia. Cytuj Link do komentarza Share on other sites More sharing options...
Anonim Luty 25, 2020 Udostępnij Luty 25, 2020 19 godzin temu, marek1707 napisał: a jeśli nie lubisz czytać, to zawsze możesz obejrzeć kod funkcji w bibliotece - to zwykle wszystko wyjaśnia. Cóż, nie każdy ma czas żeby dokładnie i wnikliwie studiować meandry bibliotek ale faktycznie pomogło obejrzenie tych funkcji. Poradziłem sobie z tym w sposób następujący. w pliku stm32f1xx_it.c nadpisałem funkcję przerwania od zakończenia transferu DMA na kanale przypisanym do I2C Tx, żeby nie łamać konwencji zawartej w HALu wiec po kolei jak leciało: void DMA1_Channel4_IRQHandler(void) { /* USER CODE BEGIN DMA1_Channel4_IRQn 0 */ __HAL_DMA_DISABLE_IT(hdma, DMA_IT_TE | DMA_IT_TC); hdma->State = HAL_DMA_STATE_READY; /* Clear the transfer complete flag */ __HAL_DMA_CLEAR_FLAG(hdma, __HAL_DMA_GET_TC_FLAG_INDEX(hdma)); /* Process Unlocked */ __HAL_UNLOCK(hdma); I2C_HandleTypeDef *hi2c = (I2C_HandleTypeDef *)((DMA_HandleTypeDef *)hdma)->Parent; /* Derogation MISRAC2012-Rule-11.5 */ __HAL_I2C_DISABLE_IT(hi2c, I2C_IT_EVT | I2C_IT_ERR); /* Disable DMA Request */ CLEAR_BIT(hi2c->Instance->CR2, I2C_CR2_DMAEN); /* Disable Last DMA */ CLEAR_BIT(hi2c->Instance->CR2, I2C_CR2_LAST); /* Generate Stop */ SET_BIT(hi2c->Instance->CR1, I2C_CR1_STOP); hi2c->XferCount = 0U; if (hi2c->ErrorCode != HAL_I2C_ERROR_NONE) HAL_I2C_ErrorCallback(hi2c); hi2c->State = HAL_I2C_STATE_READY; hi2c->Mode = HAL_I2C_MODE_NONE; hi2c->PreviousState = I2C_STATE_NONE; ///// /// Tutaj własny kod przerwania //// return; /* USER CODE END DMA1_Channel4_IRQn 0 */ HAL_DMA_IRQHandler(&hdma_i2c2_tx); /* USER CODE BEGIN DMA1_Channel4_IRQn 1 */ /* USER CODE END DMA1_Channel4_IRQn 1 */ } Czyli wydłubałem bebechy z funkcji obsługujących koniec transferu. Analizując HALa wygląda na to, że do zwrotnego callbacka w funkcji HAL_I2C_MemWrite_DMA jest przypisywana niepoprawna funkcja I2C_DMAXferCplt. Nie rozumiem dlaczego nikt tego nie poprawił do tej pory. Błąd był powodowany przekroczeniem timeoutu na wysłanie stopu na linie I2C przy prędkoci 400kbps, nie sprawdzałem z mniejszymi prędkościami ale jest szansa, że przy niższych prędkociach funkcja I2C_DMAXferCplt zadziała prawidłowo, tj. zdąży dojechać do generowania stopu. Zaproponowane rozwiązanie dotyczy najnowszej biblioteki HAL dla F1 ale powinno działać również na innych prockach na których ten problem występuje a przynajmniej wiadomo jak sobie z tym radzić. Teraz działa prawidłowo bez względu na ilość wysyłanych danych. Cytuj Link do komentarza Share on other sites More sharing options...
Polecacz 101 Zarejestruj się lub zaloguj, aby ukryć tę reklamę. Zarejestruj się lub zaloguj, aby ukryć tę reklamę. Produkcja i montaż PCB - wybierz sprawdzone PCBWay! • Darmowe płytki dla studentów i projektów non-profit • Tylko 5$ za 10 prototypów PCB w 24 godziny • Usługa projektowania PCB na zlecenie • Montaż PCB od 30$ + bezpłatna dostawa i szablony • Darmowe narzędzie do podglądu plików Gerber Zobacz również » Film z fabryki PCBWay
Anonim Luty 25, 2020 Udostępnij Luty 25, 2020 Teraz dopiero znalazłem na gicie rozwiązanie tego problemu. Okazuje się, że nie timeout a zerowanie wskaźników miało na to wpływ, które to linie wyciąłem w tym swoim improwizowanym rozwiązaniu. Wygląda na to, że wystarczy zmodyfikować plik z biblioteki w sposób przedstawiony w tej dyskusji: https://github.com/STMicroelectronics/STM32CubeF1/issues/6 Cytuj Link do komentarza Share on other sites More sharing options...
Pomocna odpowiedź
Dołącz do dyskusji, napisz odpowiedź!
Jeśli masz już konto to zaloguj się teraz, aby opublikować wiadomość jako Ty. Możesz też napisać teraz i zarejestrować się później.
Uwaga: wgrywanie zdjęć i załączników dostępne jest po zalogowaniu!