2023-07-18 15:05:49 +02:00
|
|
|
#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,
|
|
|
|
};
|
|
|
|
|
2024-04-22 15:01:46 +02:00
|
|
|
/* store the clock acquired by each USART, so it can be release again */
|
|
|
|
static msp430_usart_clk_t _clocks_acquired[USART_NUMOF];
|
|
|
|
|
2023-07-18 15:05:49 +02:00
|
|
|
void msp430_usart_acquire(const msp430_usart_params_t *params,
|
2024-04-22 15:01:46 +02:00
|
|
|
const msp430_usart_conf_t *conf,
|
|
|
|
uint8_t enable_mask)
|
2023-07-18 15:05:49 +02:00
|
|
|
{
|
|
|
|
assume(params->num < USART_NUMOF);
|
|
|
|
|
|
|
|
mutex_lock(&usart_locks[params->num]);
|
|
|
|
msp430_usart_t *dev = params->dev;
|
|
|
|
msp430_usart_sfr_t *sfr = params->sfr;
|
|
|
|
|
2024-04-22 15:01:46 +02:00
|
|
|
_clocks_acquired[params->num] = conf->prescaler.clk_source;
|
|
|
|
switch (_clocks_acquired[params->num]) {
|
|
|
|
case USART_CLK_SUBMAIN:
|
|
|
|
msp430_clock_acquire(MSP430_CLOCK_SUBMAIN);
|
|
|
|
break;
|
|
|
|
case USART_CLK_AUX:
|
|
|
|
msp430_clock_acquire(MSP430_CLOCK_AUXILIARY);
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
/* external clock from GPIO, safe to disable internal clocks */
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
2023-07-18 15:05:49 +02:00
|
|
|
/* 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;
|
|
|
|
|
2024-04-22 15:01:46 +02:00
|
|
|
switch (_clocks_acquired[params->num]) {
|
|
|
|
case USART_CLK_SUBMAIN:
|
|
|
|
msp430_clock_release(MSP430_CLOCK_SUBMAIN);
|
|
|
|
break;
|
|
|
|
case USART_CLK_AUX:
|
|
|
|
msp430_clock_release(MSP430_CLOCK_AUXILIARY);
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
/* external clock from GPIO, not managed here */
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
2023-07-18 15:05:49 +02:00
|
|
|
/* 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;
|
|
|
|
}
|