|
| 1 | +with Ada.Unchecked_Conversion; |
| 2 | +with STM32; use STM32; |
| 3 | +with STM32_SVD; |
| 4 | + |
| 5 | +package body Coms is |
| 6 | + |
| 7 | + use type STM32_SVD.UInt9; |
| 8 | + |
| 9 | + type DMA_Data is array (Integer range <>) of Interfaces.Unsigned_8; |
| 10 | + |
| 11 | + ------------------------------- |
| 12 | + -- Initialize_GPIO_Port_Pins -- |
| 13 | + ------------------------------- |
| 14 | + |
| 15 | + procedure Initialize_GPIO_Port_Pins is |
| 16 | + Configuration : GPIO_Port_Configuration; |
| 17 | + begin |
| 18 | + Enable_Clock (IO_Port); |
| 19 | + |
| 20 | + Configuration.Mode := Mode_AF; |
| 21 | + Configuration.Speed := Speed_50MHz; |
| 22 | + Configuration.Output_Type := Push_Pull; |
| 23 | + Configuration.Resistors := Pull_Up; |
| 24 | + |
| 25 | + Configure_IO |
| 26 | + (Port => IO_Port, |
| 27 | + Pins => Rx_Pin & Tx_Pin, |
| 28 | + Config => Configuration); |
| 29 | + |
| 30 | + Configure_Alternate_Function |
| 31 | + (Port => IO_Port, |
| 32 | + Pins => Rx_Pin & Tx_Pin, |
| 33 | + AF => Transceiver_AF); |
| 34 | + end Initialize_GPIO_Port_Pins; |
| 35 | + |
| 36 | + ---------------------- |
| 37 | + -- Initialize_USART -- |
| 38 | + ---------------------- |
| 39 | + |
| 40 | + procedure Initialize_USART is |
| 41 | + begin |
| 42 | + Enable_Clock (Transceiver); |
| 43 | + |
| 44 | + Enable (Transceiver); |
| 45 | + |
| 46 | + Set_Baud_Rate (Transceiver, 115_200); |
| 47 | + Set_Mode (Transceiver, Tx_Rx_Mode); |
| 48 | + Set_Stop_Bits (Transceiver, Stopbits_1); |
| 49 | + Set_Word_Length (Transceiver, Word_Length_8); |
| 50 | + Set_Parity (Transceiver, No_Parity); |
| 51 | + Set_Flow_Control (Transceiver, No_Flow_Control); |
| 52 | + end Initialize_USART; |
| 53 | + |
| 54 | + -------------------- |
| 55 | + -- Initialize_DMA -- |
| 56 | + -------------------- |
| 57 | + |
| 58 | + procedure Initialize_DMA is |
| 59 | + Configuration : DMA_Stream_Configuration; |
| 60 | + begin |
| 61 | + Enable_Clock (Controller); |
| 62 | + |
| 63 | + Configuration.Channel := Tx_Channel; |
| 64 | + Configuration.Direction := Memory_To_Peripheral; |
| 65 | + Configuration.Increment_Peripheral_Address := False; |
| 66 | + Configuration.Increment_Memory_Address := True; |
| 67 | + Configuration.Peripheral_Data_Format := Bytes; |
| 68 | + Configuration.Memory_Data_Format := Bytes; |
| 69 | + Configuration.Operation_Mode := Normal_Mode; |
| 70 | + Configuration.Priority := Priority_Very_High; |
| 71 | + Configuration.FIFO_Enabled := True; |
| 72 | + Configuration.FIFO_Threshold := FIFO_Threshold_Full_Configuration; |
| 73 | + Configuration.Memory_Burst_Size := Memory_Burst_Inc4; |
| 74 | + Configuration.Peripheral_Burst_Size := Peripheral_Burst_Inc4; |
| 75 | + |
| 76 | + Configure (Controller, Tx_Stream, Configuration); |
| 77 | + -- note the controller is disabled by the call to Configure |
| 78 | + end Initialize_DMA; |
| 79 | + |
| 80 | + --------------- |
| 81 | + -- Initalize -- |
| 82 | + --------------- |
| 83 | + |
| 84 | + procedure Initalize is |
| 85 | + begin |
| 86 | + Initialize_GPIO_Port_Pins; |
| 87 | + Initialize_USART; |
| 88 | + Initialize_DMA; |
| 89 | + Enable (Transceiver); |
| 90 | + Enable_Interrupts (Transceiver, Source => Received_Data_Not_Empty); |
| 91 | + end Initalize; |
| 92 | + |
| 93 | + ---------------------------- |
| 94 | + -- UART_Get_Data_Blocking -- |
| 95 | + ---------------------------- |
| 96 | + |
| 97 | + procedure UART_Get_Data_Blocking (C : out Character) is |
| 98 | + function Data_To_Character is new Ada.Unchecked_Conversion |
| 99 | + (Interfaces.Unsigned_8, Character); |
| 100 | + Rx_Byte : Interfaces.Unsigned_8; |
| 101 | + begin |
| 102 | + Rx_IRQ_Handler.Await_Byte_Reception (Rx_Byte); |
| 103 | + C := Data_To_Character (Rx_Byte); |
| 104 | + end UART_Get_Data_Blocking; |
| 105 | + |
| 106 | + --------------------------------- |
| 107 | + -- UART_Send_DMA_Data_Blocking -- |
| 108 | + --------------------------------- |
| 109 | + |
| 110 | + procedure UART_Send_DMA_Data_Blocking |
| 111 | + (Data : String) |
| 112 | + is |
| 113 | + function Character_To_Data is new Ada.Unchecked_Conversion |
| 114 | + (Character, Interfaces.Unsigned_8); |
| 115 | + Source_Block : DMA_Data (Data'Range); |
| 116 | + begin |
| 117 | + for Index in Source_Block'Range loop |
| 118 | + Source_Block (Index) := Character_To_Data (Data (Index)); |
| 119 | + end loop; |
| 120 | + |
| 121 | + Start_Transfer_with_Interrupts |
| 122 | + (Controller, |
| 123 | + Tx_Stream, |
| 124 | + Source => Source_Block'Address, |
| 125 | + Destination => Data_Register_Address (Transceiver), |
| 126 | + Data_Count => Half_Word (Source_Block'Length)); |
| 127 | + -- also enables the stream |
| 128 | + |
| 129 | + Enable_DMA_Transmit_Requests (Transceiver); |
| 130 | + |
| 131 | + Tx_IRQ_Handler.Await_Transfer_Complete; |
| 132 | + end UART_Send_DMA_Data_Blocking; |
| 133 | + ------------------------------- |
| 134 | + -- Finalize_DMA_Transmission -- |
| 135 | + ------------------------------- |
| 136 | + |
| 137 | + procedure Finalize_DMA_Transmission (Transceiver : in out USART) is |
| 138 | + -- see static void USART_DMATransmitCplt |
| 139 | + begin |
| 140 | + loop |
| 141 | + exit when Status (Transceiver, Transmission_Complete_Indicated); |
| 142 | + end loop; |
| 143 | + Clear_Status (Transceiver, Transmission_Complete_Indicated); |
| 144 | + Disable_DMA_Transmit_Requests (Transceiver); |
| 145 | + end Finalize_DMA_Transmission; |
| 146 | + |
| 147 | + -------------------- |
| 148 | + -- Tx_IRQ_Handler -- |
| 149 | + -------------------- |
| 150 | + |
| 151 | + protected body Tx_IRQ_Handler is |
| 152 | + |
| 153 | + ----------------------------- |
| 154 | + -- Await_Transfer_Complete -- |
| 155 | + ----------------------------- |
| 156 | + |
| 157 | + entry Await_Transfer_Complete when Transfer_Complete is |
| 158 | + begin |
| 159 | + Event_Occurred := False; |
| 160 | + Transfer_Complete := False; |
| 161 | + end Await_Transfer_Complete; |
| 162 | + |
| 163 | + ----------------- |
| 164 | + -- IRQ_Handler -- |
| 165 | + ----------------- |
| 166 | + |
| 167 | + procedure IRQ_Handler is |
| 168 | + begin |
| 169 | + -- Transfer Error Interrupt management |
| 170 | + if Status (Controller, Tx_Stream, Transfer_Error_Indicated) then |
| 171 | + if Interrupt_Enabled |
| 172 | + (Controller, Tx_Stream, Transfer_Error_Interrupt) |
| 173 | + then |
| 174 | + Disable_Interrupt |
| 175 | + (Controller, Tx_Stream, Transfer_Error_Interrupt); |
| 176 | + Clear_Status (Controller, Tx_Stream, Transfer_Error_Indicated); |
| 177 | + Event_Kind := Transfer_Error_Interrupt; |
| 178 | + Event_Occurred := True; |
| 179 | + return; |
| 180 | + end if; |
| 181 | + end if; |
| 182 | + |
| 183 | + -- FIFO Error Interrupt management. |
| 184 | + if Status (Controller, Tx_Stream, FIFO_Error_Indicated) then |
| 185 | + if Interrupt_Enabled |
| 186 | + (Controller, Tx_Stream, FIFO_Error_Interrupt) |
| 187 | + then |
| 188 | + Disable_Interrupt (Controller, Tx_Stream, FIFO_Error_Interrupt); |
| 189 | + Clear_Status (Controller, Tx_Stream, FIFO_Error_Indicated); |
| 190 | + Event_Kind := FIFO_Error_Interrupt; |
| 191 | + Event_Occurred := True; |
| 192 | + return; |
| 193 | + end if; |
| 194 | + end if; |
| 195 | + |
| 196 | + -- Direct Mode Error Interrupt management |
| 197 | + if Status (Controller, Tx_Stream, Direct_Mode_Error_Indicated) then |
| 198 | + if Interrupt_Enabled |
| 199 | + (Controller, Tx_Stream, Direct_Mode_Error_Interrupt) |
| 200 | + then |
| 201 | + Disable_Interrupt |
| 202 | + (Controller, Tx_Stream, Direct_Mode_Error_Interrupt); |
| 203 | + Clear_Status |
| 204 | + (Controller, Tx_Stream, Direct_Mode_Error_Indicated); |
| 205 | + Event_Kind := Direct_Mode_Error_Interrupt; |
| 206 | + Event_Occurred := True; |
| 207 | + return; |
| 208 | + end if; |
| 209 | + end if; |
| 210 | + |
| 211 | + -- Half Transfer Complete Interrupt management |
| 212 | + if Status |
| 213 | + (Controller, Tx_Stream, Half_Transfer_Complete_Indicated) |
| 214 | + then |
| 215 | + if Interrupt_Enabled |
| 216 | + (Controller, Tx_Stream, Half_Transfer_Complete_Interrupt) |
| 217 | + then |
| 218 | + if Double_Buffered (Controller, Tx_Stream) then |
| 219 | + Clear_Status |
| 220 | + (Controller, Tx_Stream, Half_Transfer_Complete_Indicated); |
| 221 | + else -- not double buffered |
| 222 | + if not Circular_Mode (Controller, Tx_Stream) then |
| 223 | + Disable_Interrupt |
| 224 | + (Controller, |
| 225 | + Tx_Stream, |
| 226 | + Half_Transfer_Complete_Interrupt); |
| 227 | + end if; |
| 228 | + Clear_Status |
| 229 | + (Controller, Tx_Stream, Half_Transfer_Complete_Indicated); |
| 230 | + end if; |
| 231 | + Event_Kind := Half_Transfer_Complete_Interrupt; |
| 232 | + Event_Occurred := True; |
| 233 | + end if; |
| 234 | + end if; |
| 235 | + |
| 236 | + -- Transfer Complete Interrupt management |
| 237 | + if Status (Controller, Tx_Stream, Transfer_Complete_Indicated) then |
| 238 | + if Interrupt_Enabled |
| 239 | + (Controller, Tx_Stream, Transfer_Complete_Interrupt) |
| 240 | + then |
| 241 | + if Double_Buffered |
| 242 | + (Controller, Tx_Stream) |
| 243 | + then |
| 244 | + Clear_Status |
| 245 | + (Controller, Tx_Stream, Transfer_Complete_Indicated); |
| 246 | + -- TODO: handle the difference between M0 and M1 callbacks |
| 247 | + else |
| 248 | + if not Circular_Mode (Controller, Tx_Stream) then |
| 249 | + Disable_Interrupt |
| 250 | + (Controller, Tx_Stream, Transfer_Complete_Interrupt); |
| 251 | + end if; |
| 252 | + Clear_Status |
| 253 | + (Controller, Tx_Stream, Transfer_Complete_Indicated); |
| 254 | + end if; |
| 255 | + Finalize_DMA_Transmission (Transceiver); |
| 256 | + Event_Kind := Transfer_Complete_Interrupt; |
| 257 | + Event_Occurred := True; |
| 258 | + Transfer_Complete := True; |
| 259 | + end if; |
| 260 | + end if; |
| 261 | + end IRQ_Handler; |
| 262 | + |
| 263 | + end Tx_IRQ_Handler; |
| 264 | + -------------------- |
| 265 | + -- Rx_IRQ_Handler -- |
| 266 | + -------------------- |
| 267 | + |
| 268 | + protected body Rx_IRQ_Handler is |
| 269 | + |
| 270 | + -------------------------- |
| 271 | + -- Await_Byte_Reception -- |
| 272 | + -------------------------- |
| 273 | + |
| 274 | + entry Await_Byte_Reception (Rx_Byte : out Interfaces.Unsigned_8) |
| 275 | + when Byte_Avalaible is |
| 276 | + begin |
| 277 | + -- Dequeue (Rx_Queue, Rx_Byte); |
| 278 | + -- Byte_Avalaible := not Is_Empty (Rx_Queue); |
| 279 | + Rx_Byte := Data; |
| 280 | + Byte_Avalaible := False; |
| 281 | + end Await_Byte_Reception; |
| 282 | + |
| 283 | + ----------------- |
| 284 | + -- IRQ_Handler -- |
| 285 | + ----------------- |
| 286 | + |
| 287 | + procedure IRQ_Handler is |
| 288 | + Received_Byte : Interfaces.Unsigned_8; |
| 289 | + begin |
| 290 | + if Status (Transceiver, Read_Data_Register_Not_Empty) then |
| 291 | + Received_Byte := |
| 292 | + Interfaces.Unsigned_8 (Current_Input (Transceiver) and 16#FF#); |
| 293 | + Clear_Status (Transceiver, Read_Data_Register_Not_Empty); |
| 294 | + -- Enqueue (Rx_Queue, Received_Byte); |
| 295 | + Data := Received_Byte; |
| 296 | + Byte_Avalaible := True; |
| 297 | + end if; |
| 298 | + end IRQ_Handler; |
| 299 | + |
| 300 | + end Rx_IRQ_Handler; |
| 301 | +end Coms; |
0 commit comments