111 lines
4.2 KiB
C++
111 lines
4.2 KiB
C++
|
#include "STM32F0x1.h"
|
||
|
#include "CortexM0.h" // NVIC_EnableIRQ
|
||
|
#include "gpio.h"
|
||
|
#include "usart.h"
|
||
|
|
||
|
extern "C" uint32_t SystemCoreClock;
|
||
|
static Usart * Instance = nullptr;
|
||
|
|
||
|
void Usart::irq (void) {
|
||
|
volatile USART1_Type::ISR_DEF status (USART1.ISR); // načti status přerušení
|
||
|
char tdata;
|
||
|
volatile char rdata;
|
||
|
if (status.B.TC) { // od vysílače
|
||
|
if (tx_ring.Read (tdata)) { // pokud máme data
|
||
|
USART1.TDR.R = (uint32_t) tdata & 0xFFu;// zapíšeme do výstupu
|
||
|
} else { // pokud ne
|
||
|
//USART1.CR1.B.RE = SET; // povol prijem
|
||
|
USART1.CR1.B.TCIE = RESET; // je nutné zakázat přerušení od vysílače
|
||
|
}
|
||
|
}
|
||
|
if (status.B.RXNE) { // od přijímače
|
||
|
rdata = (USART1.RDR.R) & 0xFFu; // načteme data
|
||
|
(void) rdata; // zahodime
|
||
|
}
|
||
|
}
|
||
|
/// Voláno z čistého C - startup.c
|
||
|
extern "C" void USART1_IRQHandler (void) {
|
||
|
if (Instance) Instance->irq();
|
||
|
};
|
||
|
//! [MembersConstructorExample]
|
||
|
Usart::Usart(const uint32_t baud) noexcept : BaseLayer(), tx_ring() {
|
||
|
//! [MembersConstructorExample]
|
||
|
if (Instance) return; // Chyba - jedina instance
|
||
|
Instance = this;
|
||
|
// 1. Clock Enable
|
||
|
RCC.APB2ENR.B.USART1EN = SET;
|
||
|
// 2. GPIO Alternate Config
|
||
|
GpioClass txp (GpioPortA, 9, GPIO_Mode_AF);
|
||
|
GpioClass rxp (GpioPortA, 10, GPIO_Mode_AF);
|
||
|
txp.setAF (1);
|
||
|
rxp.setAF (1);
|
||
|
// 4. NVIC
|
||
|
NVIC_EnableIRQ (USART1_IRQn);
|
||
|
uint32_t tmp = 0;
|
||
|
// 5. USART registry 8.bit bez parity
|
||
|
USART1.CR1.modify([] (USART1_Type::CR1_DEF & r) -> uint32_t { // pro ilustraci, co by bylo auto
|
||
|
r.B.TE = SET;
|
||
|
//r.B.RE = SET; // příjem je zde zbytečný
|
||
|
//r.B.RXNEIE = SET;
|
||
|
return r.R;
|
||
|
});
|
||
|
USART1.CR2.R = 0;
|
||
|
USART1.CR3.B.OVRDIS = SET;
|
||
|
// Tuhle část už vezmeme přímo z knihovny, jen ty hodiny zjednodušíme na SystemCoreClock
|
||
|
uint32_t apbclock = SystemCoreClock;
|
||
|
uint32_t integerdivider, fractionaldivider;
|
||
|
/* Determine the integer part */
|
||
|
if (USART1.CR1.B.OVER8 != RESET) {
|
||
|
/* Integer part computing in case Oversampling mode is 8 Samples */
|
||
|
integerdivider = ((25u * apbclock) / (2u * (baud)));
|
||
|
} else {
|
||
|
/* Integer part computing in case Oversampling mode is 16 Samples */
|
||
|
integerdivider = ((25u * apbclock) / (4u * (baud)));
|
||
|
}
|
||
|
tmp = (integerdivider / 100u) << 4;
|
||
|
/* Determine the fractional part */
|
||
|
fractionaldivider = integerdivider - (100u * (tmp >> 4));
|
||
|
/* Implement the fractional part in the register */
|
||
|
if (USART1.CR1.B.OVER8 != RESET) {
|
||
|
tmp |= ((((fractionaldivider * 8u ) + 50u) / 100u)) & ((uint8_t)0x07u);
|
||
|
} else {
|
||
|
tmp |= ((((fractionaldivider * 16u) + 50u) / 100u)) & ((uint8_t)0x0Fu);
|
||
|
}
|
||
|
/* Write to USART BRR */
|
||
|
USART1.BRR.R = (uint16_t)tmp;
|
||
|
USART1.CR1.B.UE = SET; // nakonec povolit globálně
|
||
|
}
|
||
|
//! [VirtualMethodBottom]
|
||
|
uint32_t Usart::Down (const char * data, const uint32_t len) {
|
||
|
uint32_t res; // výsledek, musí žít i po ukončení smyčky
|
||
|
for (res=0; res<len; res++) if (!tx_ring.Write(data[res])) break;
|
||
|
USART1.CR1.B.TCIE = SET; // po povolení přerušení okamžitě přeruší
|
||
|
return res;
|
||
|
}
|
||
|
//! [VirtualMethodBottom]
|
||
|
void Usart::SetHalfDuplex (const bool on) const {
|
||
|
USART1.CR1.B.UE = RESET; // zakázat, jinak nelze nastavovat
|
||
|
if (on) USART1.CR3.B.HDSEL = SET; // poloduplex on
|
||
|
else USART1.CR3.B.HDSEL = RESET; // poloduplex off
|
||
|
USART1.CR1.B.UE = SET; // nakonec povolit globálně
|
||
|
}
|
||
|
void Usart::SetRS485 (const bool polarity) const {
|
||
|
USART1.CR1.B.UE = RESET; // zakázat, jinak nelze nastavovat
|
||
|
// Nastavit pin DE (RTS)
|
||
|
GpioClass de (GpioPortA, 12u, GPIO_Mode_AF);
|
||
|
de.setAF (1u);
|
||
|
// Nastavení driveru
|
||
|
USART1.CR3.B.DEM = SET; // povolit DE v USARTu
|
||
|
if (polarity) USART1.CR3.B.DEP = SET;
|
||
|
else USART1.CR3.B.DEP = RESET;
|
||
|
// A nakonec doby vybavení (přesah) - to je hodně užitečné
|
||
|
//! [LambdaExampleUsage]
|
||
|
USART1.CR1.modify([] (auto & r) -> auto {
|
||
|
r.B.DEAT = 1u; // doba vybavení před start bitem - 16 ~= 1 bit, 0..31
|
||
|
r.B.DEDT = 1u; // doba vybavení po stop bitu - 16 ~= 1 bit, 0..31
|
||
|
return r.R;
|
||
|
});
|
||
|
//! [LambdaExampleUsage]
|
||
|
USART1.CR1.B.UE = SET;
|
||
|
}
|