mirror of
https://github.com/RIOT-OS/RIOT.git
synced 2025-01-18 12:52:44 +01:00
675dcc381c
- Move common code for USART (shared SPI / UART peripheral) to its own file and allow sharing the USART peripheral to provide both UART and SPI in round-robin fashion. - Configure both UART and SPI bus via a `struct` in the board's `periph_conf.h` - this allows allocating the two UARTs as needed by the use case - since both USARTs signals have a fixed connection to a single GPIO, most configuration is moved to the CPU - the board now only needs to decide which bus is provided by which USART Note: Sharing an USART used as UART requires cooperation from the app: - If the UART is used in TX-only mode (no RX callback), the driver will release the USART while not sending - If the UART is used to also receive, the application needs to power the UART down while not expecting something to send. An `spi_acquire()` will be blocked while the UART is powered up.
164 lines
4.4 KiB
C
164 lines
4.4 KiB
C
#include "macros/math.h"
|
|
#include "mutex.h"
|
|
#include "periph_conf.h"
|
|
#include "periph_cpu.h"
|
|
|
|
const msp430_usart_uart_params_t usart0_as_uart = {
|
|
.usart_params = {
|
|
.num = 0,
|
|
.dev = &USART_0,
|
|
.sfr = &USART_0_SFR,
|
|
.tx_irq_mask = UTXE0,
|
|
.rx_irq_mask = URXE0,
|
|
},
|
|
.tx_enable_mask = UTXE0,
|
|
.rxtx_enable_mask = URXE0 | UTXE0,
|
|
.txd = GPIO_PIN(P3, 4),
|
|
.rxd = GPIO_PIN(P3, 5),
|
|
};
|
|
|
|
const msp430_usart_uart_params_t usart1_as_uart = {
|
|
.usart_params = {
|
|
.num = 1,
|
|
.dev = &USART_1,
|
|
.sfr = &USART_1_SFR,
|
|
.tx_irq_mask = UTXE1,
|
|
.rx_irq_mask = URXE1,
|
|
},
|
|
.tx_enable_mask = UTXE1,
|
|
.rxtx_enable_mask = URXE1 | UTXE1,
|
|
.txd = GPIO_PIN(P3, 6),
|
|
.rxd = GPIO_PIN(P3, 7),
|
|
};
|
|
|
|
const msp430_usart_spi_params_t usart0_as_spi = {
|
|
.usart_params = {
|
|
.num = 0,
|
|
.dev = &USART_0,
|
|
.sfr = &USART_0_SFR,
|
|
.tx_irq_mask = UTXE0,
|
|
.rx_irq_mask = URXE0,
|
|
},
|
|
.enable_mask = USPIE0,
|
|
.mosi = GPIO_PIN(P3, 1),
|
|
.miso = GPIO_PIN(P3, 2),
|
|
.sck = GPIO_PIN(P3, 3),
|
|
};
|
|
|
|
const msp430_usart_spi_params_t usart1_as_spi = {
|
|
.usart_params = {
|
|
.num = 1,
|
|
.dev = &USART_1,
|
|
.sfr = &USART_1_SFR,
|
|
.tx_irq_mask = UTXE1,
|
|
.rx_irq_mask = URXE1,
|
|
},
|
|
.enable_mask = USPIE1,
|
|
.mosi = GPIO_PIN(P5, 1),
|
|
.miso = GPIO_PIN(P5, 2),
|
|
.sck = GPIO_PIN(P5, 3),
|
|
};
|
|
|
|
static mutex_t usart_locks[USART_NUMOF] = {
|
|
MUTEX_INIT,
|
|
MUTEX_INIT,
|
|
};
|
|
|
|
void msp430_usart_acquire(const msp430_usart_params_t *params,
|
|
const msp430_usart_conf_t *conf,
|
|
uint8_t enable_mask)
|
|
{
|
|
assume(params->num < USART_NUMOF);
|
|
|
|
mutex_lock(&usart_locks[params->num]);
|
|
msp430_usart_t *dev = params->dev;
|
|
msp430_usart_sfr_t *sfr = params->sfr;
|
|
|
|
/* first, make sure USART is off before reconfiguring it */
|
|
sfr->ME = 0;
|
|
/* reset USART */
|
|
dev->CTL = SWRST;
|
|
|
|
/* apply given configuration */
|
|
dev->CTL = conf->ctl | SWRST;
|
|
dev->MCTL = conf->prescaler.mctl;
|
|
dev->TCTL = conf->prescaler.clk_source;
|
|
dev->BR0 = conf->prescaler.br0;
|
|
dev->BR1 = conf->prescaler.br1;
|
|
|
|
/* disable USART IRQs and clear any spurious IRQ flags */
|
|
sfr->IE = 0;
|
|
sfr->IFG = 0;
|
|
/* enable USART as specified */
|
|
sfr->ME = enable_mask;
|
|
}
|
|
|
|
void msp430_usart_release(const msp430_usart_params_t *params)
|
|
{
|
|
assume(params->num < USART_NUMOF);
|
|
|
|
msp430_usart_sfr_t *sfr = params->sfr;
|
|
|
|
/* Disable USART */
|
|
sfr->ME = 0;
|
|
/* disable USART IRQs and clear any spurious IRQ flags */
|
|
sfr->IE = 0;
|
|
sfr->IFG = 0;
|
|
|
|
/* Release mutex */
|
|
mutex_unlock(&usart_locks[params->num]);
|
|
}
|
|
|
|
msp430_usart_prescaler_t msp430_usart_prescale(uint32_t clock, uint16_t min_br)
|
|
{
|
|
msp430_usart_prescaler_t result = { .mctl = 0 };
|
|
uint32_t clk_hz;
|
|
|
|
/* If a watch crystal is used for the auxiliary clock, allow using the
|
|
* auxiliary clock to be used as clock source for well-known
|
|
* symbol rates, so that enabling low power modes is possible while
|
|
* UART RX is active */
|
|
if ((clock_params.lfxt1_frequency == 32768)
|
|
&& (clock_params.auxiliary_clock_divier == AUXILIARY_CLOCK_DIVIDE_BY_1)) {
|
|
clk_hz = msp430_auxiliary_clock_freq();
|
|
assume(clk_hz == 32768);
|
|
result.clk_source = USART_CLK_AUX;
|
|
/* Rather than calculating the correct modulation control register
|
|
* values, just hard-code it for four well-known symbol rates. If the
|
|
* symbol rate is something else, we go for the high frequency
|
|
* subsystem main clock, where bit timings are easier to hit even
|
|
* without fine-tuning it via the modulation control register */
|
|
switch (clock) {
|
|
case 9600:
|
|
result.mctl = 0x4a;
|
|
break;
|
|
case 4800:
|
|
result.mctl = 0x6f;
|
|
break;
|
|
case 2400:
|
|
result.mctl = 0x6b;
|
|
break;
|
|
case 1200:
|
|
result.mctl = 0x03;
|
|
break;
|
|
default:
|
|
clk_hz = msp430_submain_clock_freq();
|
|
result.clk_source = USART_CLK_SUBMAIN;
|
|
}
|
|
}
|
|
else {
|
|
clk_hz = msp430_submain_clock_freq();
|
|
result.clk_source = USART_CLK_SUBMAIN;
|
|
}
|
|
|
|
uint16_t br = DIV_ROUND(clk_hz, clock);
|
|
|
|
if (br < min_br) {
|
|
br = min_br;
|
|
}
|
|
|
|
result.br0 = (uint8_t)br;
|
|
result.br1 = (uint8_t)(br >> 8);
|
|
return result;
|
|
}
|