Siswa menulis driver Uart untuk STM32F411


Kesehatan yang baik untuk semua!


Hari ini saya ingin memberi tahu Anda bagaimana secara bertahap siswa belajar mengembangkan perangkat lunak untuk mikrokontroler menggunakan driver UART pada STM32F411 sebagai contoh. Saya akan mencoba memberikan kode dan arsitektur dengan perubahan kecil dan peningkatan di sini.


, , :) ( , , - , ), . , , .


, , Uart ++.



:




, UART .



β€” UART, , .



, :



:


  • WriteData(const uint8_t *pData, uint8_t size) β€”
  • ReadData(uint8_t size) β€”

:


  • OnTransmit() β€” UART
  • OnTransmitComplete() β€” UART
  • OnReceive() β€” UART

. 2 :


  • UartDriverTransmitCompleteObservers β€” OnTransmitComplete() OnTransmitComplete()

UartDriverTransmitCompleteObservers
template<typename ...Observers>
struct UartDriverTransmitCompleteObservers
{
  __forceinline static void OnWriteComplete() 
  {
    (Observers::OnTransmitComplete(), ...) ;
  }
};

  • UartDriverReceiveObservers β€” OnReceiveComplete() OnReceiveComplete()

UartDriverReceiveObservers
template<typename ...Observers>
struct UartDriverReceiveCompleteObservers
{
  __forceinline static void OnReadComplete(tBuffer& buffer, std::size_t bytesReceived)
  {
    (Observers::OnReceiveComplete(buffer, bytesReceived), ...) ;
  }
};

, OnReceiveComplete()
OnTransmitComplete(). SomeProtocol OtherObserver.



WriteData()


, . :


:
  • ( , ( ), )
  • ,
  • UART
  • 1,

:


static void WriteData(const std::uint8_t *pData, std::uint8_t bytesTosend)
  {
    assert(bytesTosend < txRxBuffer.size()) ;
    const CriticalSection cs;
   // ,        . 
   // ..        
    if ((status != Status::Write) && (status != Status::Read))    
    {

      bufferIndex = 0U;
      bufferSize = bytesTosend;
      std::memcpy(txRxBuffer.data(), pData, static_cast<std::size_t>(bytesTosend));

      Uart::WriteByte(txRxBuffer[bufferIndex]);
      bufferIndex++;
      //  ,   
      status = Status::Write;
      Uart::StartTransmit();
    }
  }

OnTransmit()


, , ( ) UART OnTransmit() UartDriver . OnTransmit() β€” .


__forceinline static void OnTransmit()
  {
    //      ( )
    if(bufferIndex < bufferSize)    
    {
      Uart::WriteByte(txRxBuffer[bufferIndex]) ;
      bufferIndex ++ ;
    }  else    
    {
     //   ,      
     // ,        
      Uart::EnableTcInterrupt() ;
    }
  };

OnTransmitComplete()


UART : , (.. ), , , .


OnTransmitComplete() :
  • ,
  • OnTransmitComplete(), UartDriverTransmitCompleteObservers


static void OnTransmitComplete()   {
    bufferIndex = 0U;
    bufferSize = 0U;

    Uart::DisableTcInterrupt();
    Uart::DisableTxInterrupt() ;
    Uart::DisableTransmit();

    status = Status::WriteComplete;
   //    ,   
    UartDriverTransmitCompleteObservers::OnWriteComplete() ;
  }

ReadData()


.


:
  • ,

:


static auto ReadData(std::uint8_t size)  {
    assert(size < txRxBuffer.size()) ;
    const CriticalSection cs;
   //  ,         . 
   // ..        
    if ((status != Status::Write) && (status != Status::Read))
    {
      Uart::DisableTcInterrupt();
      Uart::DisableTxInterrupt();
      Uart::DisableTransmit();

      bufferIndex = 0U;      
      bufferSize = size;
        //  
      status = Status::Read;

      Uart::EnableReceive();
      Uart::EnableRxInterrupt();
    }

OnReceive()


UART , . , , .


 static void OnReceive()  
 {
    txRxBuffer[bufferIndex] = Uart::ReadByte() ;
    bufferIndex ++ ;
    if (bufferIndex == bufferSize)    
    {   
      status = Status::ReadComplete ;
      const auto length = bufferIndex ;
      bufferIndex  = 0U;   

      UartDriverReceiveObservers::OnReadComplete(txRxBuffer, bufferIndex) ;
    }
  }



uartdriver.hpp
#ifndef REGISTERS_UARTDRIVER_HPP
#define REGISTERS_UARTDRIVER_HPP

#include "susudefs.hpp" //for __forceinline
#include "hardwareuarttx.hpp" // for HardwareUartTx
#include "hardwareuarttc.hpp" //for HardwareUartTc
#include "hardwareuartrx.hpp" // for HardwareUartRx
#include <cstring> // for memcpy
#include "criticalsectionconfig.hpp" // for CriticalSection
#include "uartdriverconfig.hpp" // for tBuffer

template<typename UartModule, typename  UartDriverTransmitCompleteObservers, typename UartDriverReceiveObservers>
struct UartDriver
{
  using Uart = UartModule ;

  enum class Status: std::uint8_t
  {
    None  = 0,
    Write = 1,
    WriteComplete = 2,
    Read = 3,
    ReadComplete = 4
  } ;

  static void WriteData(const std::uint8_t *pData, std::uint8_t bytesTosend)
  {
    assert(bytesTosend < txRxBuffer.size()) ;
    const CriticalSection cs;
    if ((status != Status::Write) && (status != Status::Read))
    {

      bufferIndex = 0U;
      bufferSize = bytesTosend;
      std::memcpy(txRxBuffer.data(), pData, static_cast<std::size_t>(bytesTosend));

      Uart::WriteByte(txRxBuffer[bufferIndex]);
      bufferIndex++;

      status = Status::Write;
      Uart::StartTransmit();
      //   ,    
      if constexpr (!std::is_base_of<UartTxInterruptable, typename Uart::Base>::value)
      {
        for(; bufferIndex < bytesTosend; ++bufferIndex)
        {
          while (!Uart::IsDataRegisterEmpty())
          {

          }
          Uart::WriteByte(txRxBuffer[bufferIndex]);          
        }
        while (!Uart::IsTransmitComplete())
        {

        }

        status = Status::WriteComplete ;
        UartDriverTransmitCompleteObservers::OnWriteComplete() ;
      } else
      {

      }
    }
  }

  __forceinline static void OnTransmit()
  {
    if(bufferIndex < bufferSize)
    {
      Uart::WriteByte(txRxBuffer[bufferIndex]) ;
      bufferIndex ++ ;
    }
    else
    {
      Uart::EnableTcInterrupt() ;
    }
  };

  static void OnTransmitComplete()
  {
    bufferIndex = 0U;
    bufferSize = 0U; 

    status = Status::WriteComplete;
    Uart::DisableTcInterrupt();
    Uart::DisableTxInterrupt() ;
    Uart::DisableTransmit();

    UartDriverTransmitCompleteObservers::OnWriteComplete() ; 

  }

  static auto ReadData(std::uint8_t size)
  {
    assert(size < txRxBuffer.size()) ;
    const CriticalSection cs;
    if ((status != Status::Write) && (status != Status::Read))
    {
      Uart::DisableTcInterrupt();
      Uart::DisableTxInterrupt();
      Uart::DisableTransmit();

      bufferIndex = 0U;      
      bufferSize = size;
      status = Status::Read;

      Uart::EnableRxInterrupt();
      Uart::EnableReceive();

    }

  }

  static void OnReceive()
  {
    txRxBuffer[bufferIndex] = Uart::ReadByte() ;
    bufferIndex ++ ;
    if (bufferIndex == bufferSize)
    {   
      status = Status::ReadComplete ;
      const auto length = bufferIndex ;
      bufferIndex = 0 ;
      UartDriverReceiveObservers::OnReadComplete(txRxBuffer, static_cast<std::size_t>(length)) ;      
    }
  }

  static Status GetStatus()
  {
    return status ;
  }

  static void ResetAll()
  {
    Uart::DisableTcInterrupt();
    Uart::DisableTxInterrupt();
    Uart::DisableTransmit();

    Uart::DisableReceive();
    Uart::DisableRxInterrupt() ;

    bufferIndex = 0U;
    bufferSize = 0U;
    status = Status::None;    
  }

  friend UartDriver& operator<<(UartDriver &rOs, const char* pString)
  {
    WriteData(reinterpret_cast<const std::uint8_t*>(pString), strlen(pString)) ;
    return rOs;
  }

  friend UartDriver& operator<<(UartDriver &rOs, float value)
  {
    WriteData(reinterpret_cast<const std::uint8_t*>(&value), sizeof(float)) ;
    return rOs;
  }

private:

  inline static  tBuffer txRxBuffer = {} ;
  inline static std::uint8_t bufferSize = 0U ;
  inline static std::uint8_t bufferIndex = 0U ;
  inline static Status status = Status::None ;

};
#endif //REGISTERS_UARTDRIVER_HPP

?


, SomeProtocol, 10 10 . β€” , β€” . 8 , .. , 10, . ( , , , )


OnTransmitComplete() OnReceiveComplete().


:
template <typename UartDriver>
struct SomeProtocol 
{
  __forceinline static void OnTransmitComplete()
  {
    //   10 ; 
    Proceed() ;
  }

  __forceinline static void OnReceiveComplete(tBuffer& buffer, std::size_t length)  
  {
     //  ,  
      assert(length <= buffer.size()) ;
    //   ,     
    if (CheckData(buffer))     
    {
      //   0  .  
      //       . ..  ,  
      //  ,  ...        
      //  .      
      cmds::ProceedCmd(buffer[0], buffer); //    .
      // 
      UartDriver::WriteData(buffer.data(), length) ;
    } else    
    {
      UartDriver::ResetAll() ;
    }
  }  
  __forceinline static void Proceed()  
  {
    //   10 .
    UartDriver::ReadData(10) ;
  }
  //  
  using cmds = CmdContainer<
      Singleton<CmdWriteSomeData>::GetInstance(),
      Singleton<CmdReadSomeData>::GetInstance()
  > ;
};

//      ,    
struct TestObserver 
{
  __forceinline static void OnTransmitComplete()  
  {
    Led1::Toggle() ;
  }
};

- UartDriver


struct MyUartDriver: UartDriver<
    //   UART
    HardwareUart,
    //  SomeProtocol   TestObserver    OnTransmitComplete()
    UartDriverTransmitCompleteObservers<SomeProtocol<MyUartDriver>, TestObserver>,
   //   SomeProtocol    OnReceiveComplete()
    UartDriverReceiveCompleteObservers<SomeProtocol<MyUartDriver>>
    > { };

using MyProtocol = SomeProtocol<MyUartDriver> ;

, . , TestObserver SomeProtocol, β€” SomeProtocol. UART .


:


int main()
{
  //  
   MyProtocol::Proceed() ;

  while(true)   {  } 
  return 1 ;
}

UART


, , HardwareUart UART . :



β€” UART , 3 :


  • HardwareUartTx β€” , ,
  • HardwareUartTc β€” , ,
  • HardwareUartRx β€” , ,

HandleInterrupt() HardwareUartBase,


template<typename... Modules>
struct InterruptsList
{
  __forceinline static void OnInterrupt()
  {
    //    
    (Modules::HandleInterrupt(), ...) ; 
  }
} ;

template<typename UartModule, typename InterruptsList>
struct HardwareUartBase 
{    
  static void HandleInterrupt()  
  {
    //   HardwareUartTx, HardwareUartTc, HardwareUartRx  
    //    
    InterruptsList::OnInterrupt() ;
  }
 ...
} ;

HardwareUartTx , HardwareUartRx, HardwareUartTx
template<typename UartModule, typename UartTransmitObservers>
struct HardwareUartTx 
{
  using Uart = typename UartModule::Uart ;
  static void HandleInterrupt()  
  {
   //       
    if(Uart::SR::TXE::DataRegisterEmpty::IsSet()  && 
      Uart::CR1::TXEIE::InterruptWhenTXE::IsSet())    
    {
      UartTransmitObservers::OnTxDataRegEmpty();
    }
  }
};

template<typename UartModule, typename UartReceiveObservers>
struct HardwareUartRx 
{
   using Uart = typename UartModule::Uart ;
   static void HandleInterrupt()  
   {
     //      
     if(Uart::CR1::RXNEIE::InterruptWhenRXNE::IsSet()  && 
        Uart::SR::RXNE::DataRecieved::IsSet() )   
     {
       UartReceiveObservers::OnRxData();
     }
  }
};

template<typename UartModule, typename UartTransmitCompleteObservers>
struct HardwareUartTc 
{
  using Uart = typename UartModule::Uart ;  
  static void HandleInterrupt()  
  {
    //      
    if(Uart::SR::TC::TransmitionComplete::IsSet()  && 
      Uart::CR1::TCIE::InterruptWhenTC::IsSet())    
    {
      UartTransmitCompleteObservers::OnComplete();
      Uart::SR::TC::TransmitionNotComplete::Set() ;
    }
  }
};

HardwareUartBase
#ifndef REGISTERS_UART_HPP
#define REGISTERS_UART_HPP

#include "susudefs.hpp" //for __forceinline
#include <array> // for std::array
#include <cassert> // for assert
#include <cstring> // for memcpy
#include "criticalsectionguard.hpp" //for criticalsectionguard

template<typename UartModule,  typename InterruptsList>
struct HardwareUartBase
{
  using Uart = UartModule ;
  using Base = Interface ;

    __forceinline static void EnableTransmit()
  {
    UartModule::CR1::TE::Enable::Set();
  };

  static void DisableTransmit()
  {
    UartModule::CR1::TE::Disable::Set();
  };

  static void EnableReceive()
  {
    UartModule::CR1::RE::Enable::Set();
  };

  static void DisableReceive()
  {
    UartModule::CR1::RE::Disable::Set();
  };

  static void EnableTxInterrupt()
  {
    UartModule::CR1::TXEIE::InterruptWhenTXE::Set();
  };

  static void EnableRxInterrupt()
  {
    UartModule::CR1::RXNEIE::InterruptWhenRXNE::Set();
  };

  static void DisableRxInterrupt()
  {
    UartModule::CR1::RXNEIE::InterruptInhibited::Set();
  };

  static void DisableTxInterrupt()
  {
    UartModule::CR1::TXEIE::InterruptInhibited::Set();
  };

  static void EnableTcInterrupt()
  {
    UartModule::CR1::TCIE::InterruptWhenTC::Set();
  };

  static void DisableTcInterrupt()
  {
    UartModule::CR1::TCIE::InterruptInhibited::Set();
  };

  static void HandleInterrupt()
  {
    InterruptsList::OnInterrupt() ;
  }

  __forceinline static void ClearStatus()
  {
    UartModule::SR::Write(0);
  }

  static void WriteByte(std::uint8_t chByte)
  {
    UartModule::DR::Write(static_cast<std::uint32_t>(chByte)) ;
  }

  static std::uint8_t ReadByte()
  {
    return static_cast<std::uint8_t>(UartModule::DR::Get()) ;
  }

   static void StartTransmit()
  {
    EnableTransmit() ;
    if constexpr (std::is_base_of<UartTxInterruptable, Interface>::value)
    {
      EnableTxInterrupt() ;
    }
  }

  static bool IsDataRegisterEmpty()
  {
    return UartModule::SR::TXE::DataRegisterEmpty::IsSet() ;
  }

  static bool IsTransmitComplete()
  {
    return UartModule::SR::TC::TransmitionComplete::IsSet() ;
  }

};
#endif //REGISTERS_UART_HPP

UART :


struct HardwareUart : HardwareUartBase<
    USART2,    
    InterruptsList<
     //      
      HardwareUartTx<HardwareUart,
      //        Uart
        UartTransmitObservers<MyUartDriver>>,
      //     
      HardwareUartTc<HardwareUart,
      //      
        UartTransmitCompleteObservers<MyUartDriver>>,
      //      
      HardwareUartRx<HardwareUart,
      //       
        UartReceiveObservers<MyUartDriver>>
    >   
>
{
};

. , UartDriver, - . UART, USART2.


Uart , . Uart .


struct MyUartDriver: UartDriver<
    //   UART
    HardwareUart,
    //  SomeProtocol   TestObserver    OnTransmitComplete()
    UartDriverTransmitCompleteObservers<SomeProtocol<MyUartDriver>, TestObserver>,
   //   SomeProtocol    OnReceiveComplete()
    UartDriverReceiveCompleteObservers<SomeProtocol<MyUartDriver>>
    > { };

using MyProtocol = SomeProtocol<MyUartDriver> ;


.


inline, 1600 . : 12 Flash . , , , . , UART. :)


, 2 ( 20 ). , - , , β€” .


Kode diperiksa oleh saya di PVS-Studio. Awalnya 4 peringatan ditemukan.
Saya tidak mengingat semua peringatan lagi, saya tidak menyimpan laporan: tetapi pasti ada V2516 dan V519, kesalahannya tidak kritis, tapi saya tidak harus melakukan itu :) Semuanya diperbaiki, kecuali V2516, itu menunjuk ke kode yang digunakan untuk debugging, itu mengatur FIXME: .


Anda dapat melihat kode contoh yang berfungsi pada IAR8.40.2 di sini , tidak ada perpustakaan tambahan yang diperlukan, tetapi papan Nucleo-F411RE diperlukan, proyek itu sendiri ada di folder FlashUart \ DinamicStand .


Driver utama dan kode modul Uart ada di github .


PS: Terima kasih fougasse, apro, gleb_l dan besitzeruf untuk komentar praktis


All Articles