/*
* PIC32MZ EF Curiosity Development Board, RIOT-OS port testing example
*/
#include <stdio.h>
#include <string.h>
#include "xtimer.h"
#include "timex.h"
#include "periph/uart.h"
#include "periph/gpio.h"
#include "periph/spi.h"
/* set interval to 1 second */
#define INTERVAL (1U * US_PER_SEC)
/* serial #1 interrupt received data callback processing */
static void _rx_cb1(void* data, uint8_t c)
{
uint8_t *recd = data, rdata[4];
*recd = c;
/* write received data to TX and send SPI byte */
uart_write(1, &c, 1);
/* SPI in interrupt context for testing, bus has mutex_lock
* we receive one byte from the uart and transfer 4 bytes using SPI
*/
spi_transfer_bytes(SPI_DEV(1), 0, true, recd, rdata, 4);
}
/* serial #2 interrupt received data callback processing */
static void _rx_cb2(void* data, uint8_t c)
{
uint8_t *recd = data, rdata[4];
*recd = c;
/* write received data to TX and send SPI byte */
uart_write(2, &c, 1);
/* SPI in interrupt context for testing, bus has mutex_lock
* we receive one byte from the uart and transfer 4 bytes using SPI
*/
spi_transfer_bytes(SPI_DEV(2), 0, true, recd, rdata, 4);
}
int main(void)
{
/* variable data[1..2] byte 4 has SPI id data for testing */
uint32_t data1 = 0x0f000000, data2 = 0xf0000000;
char buffer[128];
int dd, times_count = 0;
xtimer_ticks32_t last_wakeup = xtimer_now();
/*
* setup serial ports, uart 1,2,4 @115200 bps and spi 1,2
* uart callback uses a 4 byte variable for data so SPI can
* transfer 4 bytes in the callback
*/
uart_init(1, DEBUG_UART_BAUD, _rx_cb1, &data1);
uart_init(2, DEBUG_UART_BAUD, _rx_cb2, &data2);
uart_init(4, DEBUG_UART_BAUD, NULL, 0);
spi_init(SPI_DEV(1));
spi_init(SPI_DEV(2));
spi_acquire(SPI_DEV(1), 0, SPI_MODE_0, SPI_CLK_1MHZ);
spi_acquire(SPI_DEV(2), 0, SPI_MODE_0, SPI_CLK_1MHZ);
while (1) {
/* stop unused variable warning from compiler */
(void) last_wakeup;
/*
* repeat the data stream to all serial ports by sending data to uart #4
*/
sprintf(buffer, "Times %d, Testing longer string %" PRIu32 "\n", times_count++, xtimer_usec_from_ticks(xtimer_now()));
/* send string to serial device #4, TX pin out looped to device #1 and 2 RX pin inputs */
uart_write(4, (uint8_t *) buffer, strlen(buffer));
/* cpu busy loop delay */
for (dd = 0; dd < 100000; dd++) {
last_wakeup = xtimer_now();
}
}
return 0;
}
// in the interrupt vector code, EIC_IRQ is set
/* note Compiler inserts GP context save + restore code (to current stack). */
#ifdef EIC_IRQ
/*
* This is a hack - currently the toolchain does not support correct placement
* of EIC mode vectors (it is coming though) But we can support non-vectored EIC
* mode and note the default PIC32 interrupt controller (which uses EIC +
* MCU-ASE) defaults to non vectored mode anyway with all interrupts coming via
* vector 0 which is equivalent to 'sw0' in 'VI' mode.
*
* Thus all EIC interrupts should be decoded here
*
* When toolchain support is available we could move to full vector mode but
* this does take up significant space (MCU-ASE provides 256 vectors at 32B
* spacing (the default) thats 8KB of vector space!), So a single entry point
* may be better anyway.
*
*/
void __attribute__((interrupt("vector=sw0"), keep_interrupts_masked)) _mips_isr_sw0(void)
#else
void __attribute__((interrupt("vector=hw5"))) _mips_isr_hw5(void)
#endif
{
// stuff
#ifdef _PORTS_P32MZ2048EFM100_H
/* process uart receive interrupts here */
if (IEC3bits.U1RXIE && IFS3bits.U1RXIF) {
UART_1_ISR_RX();
IFS3CLR = _IFS3_U1RXIF_MASK;
}
if (IEC4bits.U2RXIE && IFS4bits.U2RXIF) {
UART_2_ISR_RX();
IFS4CLR = _IFS4_U2RXIF_MASK;
}
if (IEC5bits.U4RXIE && IFS5bits.U4RXIF) {
UART_4_ISR_RX();
IFS5CLR = _IFS5_U4RXIF_MASK;
}
#endif
}
/* uart interrupt in single vector sw0 */
static void rx_irq(uart_t uart)
{
#ifdef _PORTS_P32MZ2048EFM100_H
PDEBUG1_TOGGLE;
#endif
if (UxSTA(pic_uart[uart]) & _U1STA_OERR_MASK) {
/* clear the FIFO */
while ((UxMODE(pic_uart[uart]) & _U1MODE_ON_MASK) && (UxSTA(pic_uart[uart]) & _U1STA_URXDA_MASK)) {
if (isr_ctx[uart].rx_cb)
isr_ctx[uart].rx_cb(isr_ctx[uart].arg, UxRXREG(pic_uart[uart]));
#ifdef _PORTS_P32MZ2048EFM100_H
PDEBUG1_TOGGLE;
#endi
}
UxSTACLR(pic_uart[uart]) = _U1STA_OERR_MASK;
}
if ((UxMODE(pic_uart[uart]) & _U1MODE_ON_MASK) && (UxSTA(pic_uart[uart]) & _U1STA_URXDA_MASK)) {
if (isr_ctx[uart].rx_cb)
isr_ctx[uart].rx_cb(isr_ctx[uart].arg, UxRXREG(pic_uart[uart]));
}
}
void UART_1_ISR_RX(void)
{
rx_irq(1);
}
void UART_2_ISR_RX(void)
{
rx_irq(2);
}
void UART_4_ISR_RX(void)
{
rx_irq(4);
}
/* L1 cache modes, boot code defaults to WB_WA, best performance
* Uncached
* Cacheable, non-coherent, write-back, write allocate
* Cacheable, non-coherent, write-through, write allocate
* Cacheable, non-coherent, write-through, no write allocate
*/
#define UNCACHED 0x02
#define WB_WA 0x03
#define WT_WA 0x01
#define WT_NWA 0x00
/* L1 cache control
* CP0 Register 16, Select 0
* bit 2-0 K0<2:0>: Kseg0 bits
* Kseg0 coherency algorithm.
* http://ww1.microchip.com/downloads/en/AppNotes/00001600C.pdf
*/
void set_cache_policy(uint32_t cc)
{
uint32_t cp0;
cp0 = _mips_mfc0(16);
cp0 &= ~0x03;
cp0 |= cc;
_mips_mtc0(16, cp0);
asm("nop"); /* re-sequence the pipeline after cp0 write */
asm("nop");
}
/* spi interrupt in single vector sw0 */
static void spi_rx_irq(spi_t bus)
{
uint8_t rdata __attribute__((unused));
#ifdef _PORTS_P32MZ2048EFM100_H
PDEBUG1_ON; // FIFO has data
#endif
while (!((SPIxSTAT(pic_spi[bus]) & _SPI1STAT_SPIRBE_MASK))) {
#ifdef _PORTS_P32MZ2048EFM100_H
PDEBUG1_TOGGLE; // FIFO has data
#endif
if (pic_spi[bus].in) {
*pic_spi[bus].in++ = SPIxBUF(pic_spi[bus]);
} else {
/* dump the received data with no callback */
rdata = SPIxBUF(pic_spi[bus]);
}
if (!--pic_spi[bus].len)
pic_spi[bus].complete = true;
#ifdef _PORTS_P32MZ2048EFM100_H
PDEBUG1_TOGGLE; // FIFO has data
#endif
}
/* time ref toggle */
#ifdef _PORTS_P32MZ2048EFM100_H
PDEBUG1_OFF; // FIFO has data
PDEBUG1_ON; // FIFO has data
PDEBUG1_OFF; // FIFO has data
#endif
}
static __inline__ void * __pic32_alloc_coherent(size_t size)
{
void *retptr;
retptr = malloc(size);
if (retptr == NULL) {
return NULL;
}
/* malloc returns a cached pointer, but convert it to an uncached pointer */
return __PIC32_UNCACHED_PTR(retptr);
}
/* Access a KSEG0 Virtual Address pointer as uncached (KSEG1) */
#define __PIC32_UNCACHED_PTR(v) __PIC32_KVA0_TO_KVA1_PTR(v)
#define __PIC32_KVA0_TO_KVA1_PTR(v) ((__typeof__(v)*)((unsigned long)(v) | 0x20000000u))
/*
* Translate a kernel virtual address in KSEG0 or KSEG1 to a real
* physical address and back.
* using compiler KVA_TO_PA macro
*/
//#define KVA_TO_PA(v) ((_paddr_t)(v) & 0x1fffffff)
#define PA_TO_KVA0(pa) ((void *) ((pa) | 0x80000000))
#define PA_TO_KVA1(pa) ((void *) ((pa) | 0xa0000000))
uint8_t tdata[20] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18};
/* allocate buffer memory in kseg1 uncached */
uint8_t* td = __pic32_alloc_coherent(32);
uint8_t* rd = __pic32_alloc_coherent(32);
uint8_t* bd = __pic32_alloc_coherent(32);
...
/* copy test-pattern data into DMA buffer */
memcpy(td, tdata, 18);
/* loop data for engine testing */
spi_transfer_bytes(SPI_DEV(1), 0, true, td, rd, 18);
spi_transfer_bytes_async(SPI_DEV(1), 0, true, rd, td, 18);
spi_transfer_bytes(SPI_DEV(2), 0, true, rd, bd, 18);
/* cpu busy loop delay */
for (dd = 0; dd < 100000; dd++) {
last_wakeup = xtimer_now();
}
/* check for spi #1 async transfer complete */
while (!spi_complete(SPI_DEV(1))) {
};
void Init_Bus_Dma_Tx1(void)
{
uint32_t physDestDma;
/* DMA channel 1 - SPI1 TX. */
physDestDma = KVA_TO_PA(&SPI1BUF);
IEC4bits.DMA1IE = 0; /* Disable the DMA interrupt. */
IFS4bits.DMA1IF = 0; /* Clear the DMA interrupt flag. */
DMACONbits.ON = 1; /* Enable the DMA module. */
DCH1SSAbits.CHSSA = physDestDma; /* Source start address. */
DCH1DSAbits.CHDSA = physDestDma; /* Destination start address. */
DCH1SSIZbits.CHSSIZ = 1; /* Source bytes. */
DCH1DSIZbits.CHDSIZ = 1; /* Destination bytes. */
DCH1CSIZbits.CHCSIZ = 1; /* Bytes to transfer per event. */
DCH1ECONbits.CHSIRQ = EIC_IRQ_SPI_1_TX; /* from board.h defines */
DCH1ECONbits.SIRQEN = 1; /* Start cell transfer if an interrupt matching CHSIRQ occurs */
DCH1INTbits.CHBCIE = 0; /* enable Channel block transfer complete interrupt. */
IPC33bits.DMA1IP = 1; /* DMA interrupt priority. */
IPC33bits.DMA1IS = 0; /* DMA subpriority. */
IEC4bits.DMA1IE = 0; /* DMA interrupt enable. */
}
void Trigger_Bus_DMA_Tx1(size_t len, uint32_t physSourceDma)
{
DCH1SSAbits.CHSSA = physSourceDma;
DCH1SSIZbits.CHSSIZ = len;
DCH1CONbits.CHEN = 1; /* Channel enable. */
}
static inline void _spi_transfer_bytes_async(spi_t bus, spi_cs_t cs, bool cont,
const void *out, void *in, size_t len)
{
const uint8_t *out_buffer = (const uint8_t*) out;
uint8_t *in_buffer = (uint8_t*) in;
uint32_t physSourceDma;
assert(bus != 0 && bus <= SPI_NUMOF);
#ifdef _PORTS_P32MZ2048EFM100_H
PDEBUG3_ON;
#endif
(void) cs;
(void) cont;
/* Translate a kernel (KSEG) virtual address to a physical address. */
physSourceDma = KVA_TO_PA(out_buffer);
/* set input buffer params */
pic_spi[bus].in = in_buffer;
pic_spi[bus].len = len;
pic_spi[bus].complete = false;
switch (bus) {
case 1:
Trigger_Bus_DMA_Tx1(len, physSourceDma);
break;
case 2:
Trigger_Bus_DMA_Tx2(len, physSourceDma);
break;
default: /* non-dma mode for testing */
while (len--) {
if (out_buffer) {
SPIxBUF(pic_spi[bus]) = *out_buffer++;
/* Wait until TX FIFO is empty */
while ((SPIxSTAT(pic_spi[bus]) & _SPI1STAT_SPITBF_MASK)) {
}
}
}
}
#ifdef _PORTS_P32MZ2048EFM100_H
PDEBUG3_OFF;
#endif
}
We use cookies and similar technologies for the following purposes:
Do you accept cookies and these technologies?
We use cookies and similar technologies for the following purposes:
Do you accept cookies and these technologies?