214 lines
5.1 KiB
C
214 lines
5.1 KiB
C
|
#include <stdio.h>
|
||
|
#include "rpi-aux.h"
|
||
|
#include "rpi-base.h"
|
||
|
#include "rpi-gpio.h"
|
||
|
#include "startup.h"
|
||
|
#include "stdlib.h"
|
||
|
|
||
|
#include "rpiHardware.h"
|
||
|
|
||
|
#ifdef INCLUDE_DEBUGGER
|
||
|
#include "debugger/debugger.h"
|
||
|
#endif
|
||
|
|
||
|
/* Define the system clock frequency in MHz for the baud rate calculation.
|
||
|
This is clearly defined on the BCM2835 datasheet errata page:
|
||
|
http://elinux.org/BCM2835_datasheet_errata */
|
||
|
#define FALLBACK_SYS_FREQ 250000000
|
||
|
|
||
|
//#define USE_IRQ
|
||
|
|
||
|
#define TX_BUFFER_SIZE 65536 // Must be a power of 2
|
||
|
|
||
|
static aux_t* auxillary = (aux_t*) AUX_BASE;
|
||
|
|
||
|
aux_t* RPI_GetAux(void)
|
||
|
{
|
||
|
return auxillary;
|
||
|
}
|
||
|
|
||
|
#if defined(USE_IRQ)
|
||
|
|
||
|
#include "rpi-interrupts.h"
|
||
|
|
||
|
// Note, at the point the MiniUART is initialized, low vectors are in use
|
||
|
#define IRQ_VECTOR 0x38
|
||
|
|
||
|
static char *tx_buffer;
|
||
|
static volatile int tx_head;
|
||
|
static volatile int tx_tail;
|
||
|
|
||
|
static void __attribute__((interrupt("IRQ"))) RPI_AuxMiniUartIRQHandler() {
|
||
|
|
||
|
_data_memory_barrier();
|
||
|
|
||
|
while (1) {
|
||
|
|
||
|
int iir = auxillary->MU_IIR;
|
||
|
|
||
|
if (iir & AUX_MUIIR_INT_NOT_PENDING) {
|
||
|
/* No more interrupts */
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
/* Handle RxReady interrupt */
|
||
|
if (iir & AUX_MUIIR_INT_IS_RX) {
|
||
|
#ifdef INCLUDE_DEBUGGER
|
||
|
/* Forward all received characters to the debugger */
|
||
|
debugger_rx_char(auxillary->MU_IO & 0xFF);
|
||
|
#else
|
||
|
/* Else just exho characters */
|
||
|
RPI_AuxMiniUartWrite(auxillary->MU_IO & 0xFF);
|
||
|
#endif
|
||
|
}
|
||
|
|
||
|
/* Handle TxEmpty interrupt */
|
||
|
if (iir & AUX_MUIIR_INT_IS_TX) {
|
||
|
if (tx_tail != tx_head) {
|
||
|
/* Transmit the character */
|
||
|
tx_tail = (tx_tail + 1) & (TX_BUFFER_SIZE - 1);
|
||
|
auxillary->MU_IO = tx_buffer[tx_tail];
|
||
|
} else {
|
||
|
/* Disable TxEmpty interrupt */
|
||
|
auxillary->MU_IER &= ~AUX_MUIER_TX_INT;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
_data_memory_barrier();
|
||
|
}
|
||
|
#endif
|
||
|
|
||
|
void RPI_AuxMiniUartInit(int baud, int bits)
|
||
|
{
|
||
|
volatile int i;
|
||
|
|
||
|
// Data memory barrier need to be places between accesses to different peripherals
|
||
|
//
|
||
|
// See page 7 of the BCM2853 manual
|
||
|
|
||
|
_data_memory_barrier();
|
||
|
|
||
|
int sys_freq = get_clock_rate(CORE_CLK_ID);
|
||
|
|
||
|
if (!sys_freq) {
|
||
|
sys_freq = FALLBACK_SYS_FREQ;
|
||
|
}
|
||
|
|
||
|
_data_memory_barrier();
|
||
|
|
||
|
/* Setup GPIO 14 and 15 as alternative function 5 which is
|
||
|
UART 1 TXD/RXD. These need to be set before enabling the UART */
|
||
|
RPI_SetGpioPinFunction(RPI_GPIO14, FS_ALT5);
|
||
|
RPI_SetGpioPinFunction(RPI_GPIO15, FS_ALT5);
|
||
|
|
||
|
_data_memory_barrier();
|
||
|
|
||
|
// Enable weak pullups
|
||
|
RPI_GpioBase->GPPUD = 2;
|
||
|
// Note: the delay values are important, with 150 the receiver did not work!
|
||
|
for (i = 0; i < 1000; i++)
|
||
|
{
|
||
|
}
|
||
|
RPI_GpioBase->GPPUDCLK0 = (1 << 14) | (1 << 15);
|
||
|
// Note: the delay values are important, with 150 the receiver did not work!
|
||
|
for (i = 0; i < 1000; i++)
|
||
|
{
|
||
|
}
|
||
|
RPI_GpioBase->GPPUD = 2;
|
||
|
RPI_GpioBase->GPPUDCLK0 = 0;
|
||
|
|
||
|
_data_memory_barrier();
|
||
|
|
||
|
/* As this is a mini uart the configuration is complete! Now just
|
||
|
enable the uart. Note from the documentation in section 2.1.1 of
|
||
|
the ARM peripherals manual:
|
||
|
|
||
|
If the enable bits are clear you will have no access to a
|
||
|
peripheral. You can not even read or write the registers */
|
||
|
auxillary->ENABLES = AUX_ENA_MINIUART;
|
||
|
|
||
|
_data_memory_barrier();
|
||
|
|
||
|
/* Disable flow control,enable transmitter and receiver! */
|
||
|
auxillary->MU_CNTL = 0;
|
||
|
|
||
|
/* Decide between seven or eight-bit mode */
|
||
|
if (bits == 8)
|
||
|
auxillary->MU_LCR = AUX_MULCR_8BIT_MODE;
|
||
|
else
|
||
|
auxillary->MU_LCR = 0;
|
||
|
|
||
|
auxillary->MU_MCR = 0;
|
||
|
|
||
|
/* Disable all interrupts from MU and clear the fifos */
|
||
|
auxillary->MU_IER = 0;
|
||
|
auxillary->MU_IIR = 0xC6;
|
||
|
|
||
|
/* Transposed calculation from Section 2.2.1 of the ARM peripherals manual */
|
||
|
auxillary->MU_BAUD = ( sys_freq / (8 * baud)) - 1;
|
||
|
|
||
|
#ifdef USE_IRQ
|
||
|
tx_buffer = malloc(TX_BUFFER_SIZE);
|
||
|
tx_head = tx_tail = 0;
|
||
|
*((uint32_t *) IRQ_VECTOR) = (uint32_t) RPI_AuxMiniUartIRQHandler;
|
||
|
_data_memory_barrier();
|
||
|
RPI_GetIrqController()->Enable_IRQs_1 = (1 << 29);
|
||
|
_data_memory_barrier();
|
||
|
auxillary->MU_IER |= AUX_MUIER_RX_INT;
|
||
|
#endif
|
||
|
|
||
|
_data_memory_barrier();
|
||
|
|
||
|
/* Disable flow control,enable transmitter and receiver! */
|
||
|
auxillary->MU_CNTL = AUX_MUCNTL_TX_ENABLE | AUX_MUCNTL_RX_ENABLE;
|
||
|
|
||
|
_data_memory_barrier();
|
||
|
|
||
|
}
|
||
|
|
||
|
void RPI_AuxMiniUartWrite(char c)
|
||
|
{
|
||
|
#ifdef USE_IRQ
|
||
|
int tmp_head = (tx_head + 1) & (TX_BUFFER_SIZE - 1);
|
||
|
|
||
|
/* Test if the buffer is full */
|
||
|
if (tmp_head == tx_tail) {
|
||
|
int cpsr = _get_cpsr();
|
||
|
if (cpsr & 0x80) {
|
||
|
/* IRQ disabled: drop the character to avoid deadlock */
|
||
|
return;
|
||
|
} else {
|
||
|
/* IRQ enabled: wait for space in buffer */
|
||
|
while (tmp_head == tx_tail) {
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
/* Buffer the character */
|
||
|
tx_buffer[tmp_head] = c;
|
||
|
tx_head = tmp_head;
|
||
|
|
||
|
_data_memory_barrier();
|
||
|
|
||
|
/* Enable TxEmpty interrupt */
|
||
|
auxillary->MU_IER |= AUX_MUIER_TX_INT;
|
||
|
|
||
|
_data_memory_barrier();
|
||
|
|
||
|
#else
|
||
|
/* Wait until the UART has an empty space in the FIFO */
|
||
|
while ((auxillary->MU_LSR & AUX_MULSR_TX_EMPTY) == 0)
|
||
|
{
|
||
|
}
|
||
|
/* Write the character to the FIFO for transmission */
|
||
|
auxillary->MU_IO = c;
|
||
|
#endif
|
||
|
}
|
||
|
|
||
|
extern void RPI_EnableUart(char* pMessage)
|
||
|
{
|
||
|
RPI_AuxMiniUartInit(115200, 8); // Initialise the UART
|
||
|
|
||
|
printf(pMessage);
|
||
|
}
|