1
0
mirror of https://github.com/RIOT-OS/RIOT.git synced 2026-01-01 01:41:18 +01:00

Merge pull request #13094 from francois-berder/pic32-uart-3

UART RX implementation on PIC32 devices
This commit is contained in:
Alexandre Abadie 2020-03-31 10:45:43 +02:00 committed by GitHub
commit 934f68ead8
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
24 changed files with 591 additions and 381 deletions

View File

@ -14,5 +14,6 @@ ifeq ($(PROGRAMMER),pic32prog)
# * https://docs.creatordev.io/wifire/guides/wifire-programming/
# * The triangle `▶` goes into the port number 1 (a hole with a square around it)
# opposite side of the JP1 ICSP text.
FLASHFILE ?= $(HEXFILE)
include $(RIOTMAKE)/tools/pic32prog.inc.mk
endif

View File

@ -15,13 +15,6 @@ extern void dummy(void);
void board_init(void)
{
/*
* Setup pin mux for UART3 this is the one connected
* to the mickroBUS
*/
U3RXR = 0x2; /*connect pin RPF5 to UART3 RX*/
RPF4R = 0x1; /*connect pin RPF4 to UART3 TX*/
/* Turn off all LED's */
gpio_init(LED1_PIN, GPIO_OUT);
gpio_init(LED2_PIN, GPIO_OUT);
@ -34,8 +27,3 @@ void board_init(void)
/* Stop the linker from throwing away the PIC32 config register settings */
dummy();
}
void pm_reboot(void)
{
/* TODO, note this is needed to get 'default' example to build */
}

View File

@ -39,18 +39,6 @@ extern "C" {
*/
#define TICKS_PER_US (48)
/**
* @brief Use the 3rd UART for STDIO on this board
*
* This is the UART connected to the MikroBus.
*/
#define STDIO_UART_DEV UART_DEV(3)
/**
* @brief We are using an External Interrupt Controller (all pic32 devices use this mode)
*/
#define EIC_IRQ (1)
/**
* @name LED pin configuration
* @{

View File

@ -21,6 +21,7 @@
#ifndef PERIPH_CONF_H
#define PERIPH_CONF_H
#include "cpu.h"
#include "periph_cpu.h"
#ifdef __cplusplus
@ -45,14 +46,25 @@ extern "C" {
/**
* @name UART Definitions
* There are 4 UARTS available on this CPU.
* We route debug via UART3 on this board,
* this is the UART connected to the MikroBUS
*
* Note Microchip number the UARTS 1->4
* @{
*/
#define UART_NUMOF (4)
static const uart_conf_t uart_config[] = {
{ /* UART port available on MikroBus */
.base = (volatile unsigned int *)_UART3_BASE_ADDRESS,
.clock = PERIPHERAL_CLOCK,
.rx_pin = GPIO_PIN(PORT_F, 5),
.tx_pin = GPIO_PIN(PORT_F, 4),
.rx_mux_reg = &U3RXR,
.tx_mux_reg = &RPF4R,
.rx_af = GPIO_AF2,
.tx_af = GPIO_AF1,
.vector = _UART_3_VECTOR,
.irq = _UART3_RX_IRQ,
},
};
#define UART_0_ISR (isr_usart3)
#define UART_NUMOF ((unsigned int)ARRAY_SIZE(uart_config))
/** @} */
#ifdef __cplusplus

View File

@ -17,6 +17,7 @@ ifeq ($(PROGRAMMER),pic32prog)
# * https://docs.creatordev.io/wifire/guides/wifire-programming/
# * The triangle `▶` goes into the port number 1 (a hole with a square around it)
# opposite side of the JP1 ICSP text.
FLASHFILE ?= $(HEXFILE)
include $(RIOTMAKE)/tools/pic32prog.inc.mk
else ifeq ($(PROGRAMMER),jlink)
FLASHFILE ?= $(HEXFILE)

View File

@ -38,11 +38,6 @@ extern "C" {
*/
#define TICKS_PER_US (100)
/**
* @brief We are using an External Interrupt Controller (all pic32 devices use this mode)
*/
#define EIC_IRQ (1)
/**
* @name LED pin configuration
* @{
@ -79,13 +74,6 @@ extern "C" {
*/
void board_init(void);
/**
* @brief Use the 4th UART for STDIO on this board
*
* This is the UART connected to the FTDI USB <-> UART device.
*/
#define STDIO_UART_DEV UART_DEV(4)
#ifdef __cplusplus
}
#endif

View File

@ -20,6 +20,7 @@
#ifndef PERIPH_CONF_H
#define PERIPH_CONF_H
#include "cpu.h"
#include "periph_cpu.h"
#ifdef __cplusplus
@ -42,12 +43,24 @@ extern "C" {
/**
* @name UART Definitions
* There are 6 UARTS available on this CPU.
*
* Note Microchip number the UARTS 1->6.
* @{
*/
#define UART_NUMOF (6)
static const uart_conf_t uart_config[] = {
{ /* Virtual COM port */
.base = (volatile unsigned int *)_UART4_BASE_ADDRESS,
.clock = PERIPHERAL_CLOCK,
.rx_pin = GPIO_PIN(PORT_F, 2),
.tx_pin = GPIO_PIN(PORT_F, 8),
.rx_mux_reg = &U4RXR,
.tx_mux_reg = &RPF8R,
.rx_af = GPIO_AF11,
.tx_af = GPIO_AF2,
.vector = _UART4_RX_VECTOR,
},
};
#define UART_0_ISR (isr_usart4)
#define UART_NUMOF ((unsigned int)ARRAY_SIZE(uart_config))
/** @} */
#ifdef __cplusplus

View File

@ -19,13 +19,6 @@ extern void dummy(void);
void board_init(void)
{
/*
* Setup pin mux for UART4 this is the one connected
* to the ftdi chip (usb<->uart)
*/
U4RXR = 0xb; /* connect pin RPF2 to UART 4 RX */
RPF8R = 0x2; /* connect pin RPF8 to UART 4 TX */
/* Turn off all LED's */
gpio_init(LED1_PIN, GPIO_OUT);
gpio_init(LED2_PIN, GPIO_OUT);
@ -42,8 +35,3 @@ void board_init(void)
/* Stop the linker from throwing away the PIC32 config register settings */
dummy();
}
void pm_reboot(void)
{
/* TODO, note this is needed to get 'default' example to build */
}

View File

@ -25,6 +25,7 @@
#include <stdint.h>
#include "cpu_conf.h"
#include "thread.h"
#include "irq.h"
#ifdef __cplusplus
@ -46,6 +47,18 @@ static inline void cpu_print_last_instruction(void)
*/
void cpu_init(void);
/**
* @brief Trigger a conditional context scheduler run / context switch
*
* This function is supposed to be called in the end of each ISR.
*/
static inline void mips32r2_isr_end(void)
{
if (sched_context_switch_request) {
thread_yield_higher();
}
}
#ifdef __cplusplus
}
#endif

View File

@ -0,0 +1,72 @@
/*
* Copyright 2016, Imagination Technologies Limited and/or its
* affiliated group companies.
* This file is subject to the terms and conditions of the GNU Lesser
* General Public License v2.1. See the file LICENSE in the top level
* directory for more details.
*/
/**
* @ingroup cpu
* @brief Imagination Technologies MIPS32R2 Common implementation
* @{
*
* @file
* @brief API for supporting External Interrupt Controllers (EIC mode)
*
* @author Neil Jones <neil.jones@imgtec.com>
*/
#ifndef EIC_H
#define EIC_H
#ifdef __cplusplus
extern "C" {
#endif
/**
* @brief External ISR callback
*/
typedef void (*external_isr_ptr_t)(void);
/**
* @brief Set External ISR callback
*/
void set_external_isr_cb(int vecNum, external_isr_ptr_t cbFunc);
/**
* @brief Configure interrupt priority
*
* @param[in] vecNum
* @param[in] priority
* @param[in] subpriority
*/
void eic_configure_priority(int vecNum, int priority, int subpriority);
/**
* @brief Enable interrupt
*
* @param[in] vecNum
*/
void eic_enable(int vecNum);
/**
* @brief Disable interrupt
*
* @param[in] vecNum
*/
void eic_disable(int vecNum);
/**
* @brief Clear interrupt flag
*
* @param[in] vecNum
*/
void eic_clear_flag(int vecNum);
#ifdef __cplusplus
}
#endif
#endif /* EIC_H */
/** @} */

View File

@ -1,69 +0,0 @@
/*
* Copyright 2016, Imagination Technologies Limited and/or its
* affiliated group companies.
* This file is subject to the terms and conditions of the GNU Lesser
* General Public License v2.1. See the file LICENSE in the top level
* directory for more details.
*/
/**
* @ingroup cpu_mips32r2_common
* @brief Imagination Technologies MIPS32R2 Common implementation
* @{
*
* @file
* @brief API for supporting External Interrupt Controllers (EIC mode)
*
* @author Neil Jones <neil.jones@imgtec.com>
*/
#ifndef EIC_IRQ_H
#define EIC_IRQ_H
#ifdef __cplusplus
extern "C" {
#endif
/**
* @ brief Internal Interrupt numbers
*
* MIPS cores have a few internally generated interrupts from the Timer,
* Performance Counters and Fast Debug Channel hardware, in EIC mode these
* become outputs from the core and are connected to the external controller,
* the external control then loops these back at whichever IPL it decides
*
* We use negative numbers to represent these, leaving positive numbers free for
* the SoC specific interrupts
* @{
*/
#define EIC_IRQ_TIMER (-1)
#define EIC_IRQ_FDC (-2)
#define EIC_IRQ_PC (-3)
/** @} */
/**
* @brief Configure and route the interrupt
*/
void eic_irq_configure(int irq_num);
/**
* @brief Enable an interrupt
*/
void eic_irq_enable(int irq_num);
/**
* @brief Disable an interrupt
*/
void eic_irq_disable(int irq_num);
/**
* @brief Acknowledge an interrupt
*/
void eic_irq_ack(int irq_num);
#ifdef __cplusplus
}
#endif
#endif /* EIC_IRQ_H */
/** @} */

View File

@ -0,0 +1,100 @@
/*
* Copyright 2014-2015, Imagination Technologies Limited and/or its
* affiliated group companies.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
* 3. Neither the name of the copyright holder nor the names of its
* contributors may be used to endorse or promote products derived from this
* software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
#
# Keep each function in a separate named section
#define _FUNCTION_SECTIONS_
.set nomips16
#include <mips/regdef.h>
#include <mips/asm.h>
#include <mips/cpu.h>
#define VEC_SPACE (SZPTR * 8)
LEAF(__isr_vec)
.set push
.set noat
AENT(__isr_vec_sw0)
.weak _mips_isr_sw0
LA k1, _mips_isr_sw0
beqz k1, 1f
jr k1
.org VEC_SPACE
AENT(__isr_vec_sw1)
.weak _mips_isr_sw1
LA k1, _mips_isr_sw1
beqz k1, 1f
jr k1
.org 2 * VEC_SPACE
AENT(__isr_vec_hw0)
.weak _mips_isr_hw0
LA k1, _mips_isr_hw0
beqz k1, 1f
jr k1
.org 3 * VEC_SPACE
AENT(__isr_vec_hw1)
.weak _mips_isr_hw1
LA k1, _mips_isr_hw1
beqz k1, 1f
jr k1
.org 4 * VEC_SPACE
AENT(__isr_vec_hw2)
.weak _mips_isr_hw2
LA k1, _mips_isr_hw2
beqz k1, 1f
jr k1
.org 5 * VEC_SPACE
AENT(__isr_vec_hw3)
.weak _mips_isr_hw3
LA k1, _mips_isr_hw3
beqz k1, 1f
jr k1
.org 6 * VEC_SPACE
AENT(__isr_vec_hw4)
.weak _mips_isr_hw4
LA k1, _mips_isr_hw4
beqz k1, 1f
jr k1
.org 7 * VEC_SPACE
AENT(__isr_vec_hw5)
.weak _mips_isr_hw5
LA k1, _mips_isr_hw5
beqz k1, 1f
jr k1
.org 8 * VEC_SPACE
AENT(__isr_vec_fallback)
.weak _mips_interrupt
1:
LA k1, _mips_interrupt
beqz k1, 1b
jr k1
.set pop
END(__isr_vec)

View File

@ -233,10 +233,15 @@ _mips_handle_exception(struct gpctx *ctx, int exception)
irq_restore(status);
return;
}
else if (ctx->t2[1] == __MIPS_UHI_READ && ctx->a[0] == STDIN_FILENO) {
ctx->v[0] = stdio_read((void *)ctx->a[1], ctx->a[2]);
ctx->epc += 4; /* move PC past the syscall */
return;
}
else if (ctx->t2[1] == __MIPS_UHI_FSTAT &&
(ctx->a[0] == STDOUT_FILENO || ctx->a[0] == STDERR_FILENO)) {
(ctx->a[0] == STDOUT_FILENO || ctx->a[0] == STDIN_FILENO || ctx->a[0] == STDERR_FILENO)) {
/*
* Printf fstat's the stdout/stderr file so
* Printf fstat's the stdout/stdin/stderr file so
* fill out a minimal struct stat.
*/
struct stat *sbuf = (struct stat *)ctx->a[1];

View File

@ -1,4 +1,7 @@
USEMODULE += mips_pic32_common
USEMODULE += mips_pic32_common_periph
# mips32 needs periph_timer for its gettimeofday() implementation
USEMODULE += periph_timer
include $(RIOTCPU)/mips32r2_common/Makefile.dep

View File

@ -1,3 +1,5 @@
include $(RIOTCPU)/mips32r2_common/Makefile.include
CFLAGS += -DCPU_FAM_$(call uppercase_and_underscore,$(CPU_FAM))
INCLUDES += -I$(RIOTCPU)/mips_pic32_common/include

View File

@ -0,0 +1,95 @@
/*
* Copyright (C) 2019 Francois Berder
*
* This file is subject to the terms and conditions of the GNU Lesser
* General Public License v2.1. See the file LICENSE in the top level
* directory for more details.
*
*/
#include "cpu_conf.h"
#include "eic.h"
#include <stdint.h>
#if defined(CPU_FAM_PIC32MX)
#define VEC_NUMOF (64)
#elif defined (CPU_FAM_PIC32MZ)
#define VEC_NUMOF (256)
#endif
#define IECSET(V) *(volatile uint32_t *)((uintptr_t)&IEC0SET + 0x10 * ((V) / 32))
#define IECCLR(V) *(volatile uint32_t *)((uintptr_t)&IEC0CLR + 0x10 * ((V) / 32))
#define IFSCLR(V) *(volatile uint32_t *)((uintptr_t)&IFS0CLR + 0x10 * ((V) / 32))
#define IPC(V) *(volatile uint32_t *)((uintptr_t)&IPC0 + 0x10 * ((V) / 4))
static external_isr_ptr_t vectors[VEC_NUMOF];
void set_external_isr_cb(int vecNum, external_isr_ptr_t cbFunc)
{
if (vecNum < VEC_NUMOF)
vectors[vecNum] = cbFunc;
}
/* note Compiler inserts GP context save + restore code (to current stack). */
/*
* 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) that's 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)
{
#if defined(CPU_FAM_PIC32MX)
int vecNum = INTSTAT & _INTSTAT_VEC_MASK;
#elif defined (CPU_FAM_PIC32MZ)
int vecNum = INTSTAT & _INTSTAT_SIRQ_MASK;
#endif
if (vectors[vecNum])
vectors[vecNum]();
}
void eic_configure_priority(int vecNum, int priority, int subpriority)
{
unsigned int offset;
if (vecNum >= VEC_NUMOF)
return;
offset = 8 * (vecNum & 0x3);
IPC(vecNum) &= ~(0x1F << offset);
IPC(vecNum) |= ((priority << 2) | (subpriority)) << offset;
}
void eic_enable(int vecNum)
{
if (vecNum >= VEC_NUMOF)
return;
IECSET(vecNum) = 1U << (vecNum & 0x1F);
}
void eic_disable(int vecNum)
{
if (vecNum >= VEC_NUMOF)
return;
IECCLR(vecNum) = 1U << (vecNum & 0x1F);
}
void eic_clear_flag(int vecNum)
{
if (vecNum >= VEC_NUMOF)
return;
IFSCLR(vecNum) = 1U << (vecNum & 0x1F);
}

View File

@ -78,6 +78,47 @@ enum {
*/
#define PERIPH_TIMER_PROVIDES_SET
/**
* @brief Available MUX values for configuring a pin's alternate function
*/
typedef enum {
GPIO_AF0 = 0, /**< use alternate function 0 */
GPIO_AF1, /**< use alternate function 1 */
GPIO_AF2, /**< use alternate function 2 */
GPIO_AF3, /**< use alternate function 3 */
GPIO_AF4, /**< use alternate function 4 */
GPIO_AF5, /**< use alternate function 5 */
GPIO_AF6, /**< use alternate function 6 */
GPIO_AF7, /**< use alternate function 7 */
GPIO_AF8, /**< use alternate function 8 */
GPIO_AF9, /**< use alternate function 9 */
GPIO_AF10, /**< use alternate function 10 */
GPIO_AF11, /**< use alternate function 11 */
GPIO_AF12, /**< use alternate function 12 */
GPIO_AF13, /**< use alternate function 13 */
GPIO_AF14, /**< use alternate function 14 */
GPIO_AF15 /**< use alternate function 15 */
} gpio_af_t;
/**
* @brief Structure for UART configuration data
*/
typedef struct {
volatile unsigned int * base; /**< UART device base register address */
uint32_t clock; /**< Peripheral clock frequency */
gpio_t rx_pin; /**< RX pin */
gpio_t tx_pin; /**< TX pin */
volatile unsigned int *rx_mux_reg; /**< Address of RX mux register*/
volatile unsigned int *tx_mux_reg; /**< Address of TX mux register */
gpio_af_t rx_af; /**< alternate function for RX pin */
gpio_af_t tx_af; /**< alternate function for TX pin */
uint32_t vector; /**< vector number */
#ifdef CPU_FAM_PIC32MX
uint32_t irq; /**< interrupt number */
#endif
} uart_conf_t;
#ifdef __cplusplus
}
#endif

View File

@ -0,0 +1,38 @@
/*
* Copyright 2020 Francois Berder
*
* This file is subject to the terms and conditions of the GNU Lesser
* General Public License v2.1. See the file LICENSE in the top level
* directory for more details.
*/
/**
* @ingroup cpu_mips_pic32_common
* @ingroup drivers_periph_pm
* @{
*
* @file
* @brief common periph/pm functions
*
* @author Francois Berder <fberder@outlook.fr >
*
* @}
*/
#include "periph/pm.h"
void pm_reboot(void)
{
/* Unlock OSCCON */
SYSKEY = 0x00000000;
SYSKEY = 0xAA996655;
SYSKEY = 0x556699AA;
/* Set SWRST bit to arm reset */
RSWRSTSET = 1;
/* Read RSWRST register to trigger reset */
RSWRST;
while(1);
}

View File

@ -34,9 +34,7 @@
#include "div.h"
#include <sys/time.h>
#ifdef EIC_IRQ
#include "eic_irq.h"
#endif
#include "eic.h"
/*
* setting TIMER_ACCURACY_SHIFT lower will improve accuracy
@ -70,7 +68,39 @@
static timer_isr_ctx_t timer_isr_ctx;
volatile unsigned int counter;
volatile unsigned int compares[CHANNELS];
static volatile int spurious_int;
static void timer_isr(void)
{
IFS0CLR =_IFS0_CTIF_MASK;
uint32_t status = irq_disable();
counter += TIMER_ACCURACY;
irq_restore(status);
if (counter == compares[0]) {
/*
* The Xtimer code expects the ISR to take some time
* but our counter is a fake software one, so bump it a
* bit to give the impression some time elapsed in the ISR.
* Without this the callback ( _shoot(timer) on xtimer_core.c )
* never fires.
*/
counter += TIMER_ACCURACY;
timer_isr_ctx.cb(timer_isr_ctx.arg, 0);
mips32r2_isr_end();
}
if (counter == compares[1]) {
timer_isr_ctx.cb(timer_isr_ctx.arg, 1);
mips32r2_isr_end();
}
if (counter == compares[2]) {
timer_isr_ctx.cb(timer_isr_ctx.arg, 2);
mips32r2_isr_end();
}
mips_setcompare(mips_getcount() + TICKS_PER_US * TIMER_ACCURACY);
}
/*
* The mips toolchain C library does not implement gettimeofday()
@ -111,12 +141,9 @@ int timer_init(tim_t dev, unsigned long freq, timer_cb_t cb, void *arg)
mips32_bc_c0(C0_CAUSE, CR_DC);
/* Enable Timer Interrupts */
#ifdef EIC_IRQ
eic_irq_configure(EIC_IRQ_TIMER);
#else
mips32_bs_c0(C0_STATUS, SR_HINT5);
#endif
set_external_isr_cb(_CORE_TIMER_VECTOR, timer_isr);
eic_configure_priority(_CORE_TIMER_VECTOR, 1, 0);
eic_enable(_CORE_TIMER_VECTOR);
return 0;
}
@ -189,95 +216,3 @@ void timer_stop(tim_t dev)
(void)dev;
mips32_bs_c0(C0_CAUSE, CR_DC);
}
void timer_irq_enable(tim_t dev)
{
(void)dev;
#ifdef EIC_IRQ
eic_irq_enable(EIC_IRQ_TIMER);
#else
mips32_bs_c0(C0_STATUS, SR_HINT5);
#endif
}
void timer_irq_disable(tim_t dev)
{
(void)dev;
#ifdef EIC_IRQ
eic_irq_disable(EIC_IRQ_TIMER);
#else
mips32_bc_c0(C0_STATUS, SR_HINT5);
#endif
}
/* 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 (currently only Timer is
* used)
*
* 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) that's 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
{
register int cr = mips_getcr();
if (cr & CR_TI) {
#ifdef EIC_IRQ
eic_irq_ack(EIC_IRQ_TIMER);
#endif
uint32_t status = irq_disable();
counter += TIMER_ACCURACY;
irq_restore(status);
if (counter == compares[0]) {
/*
* The Xtimer code expects the ISR to take some time
* but our counter is a fake software one, so bump it a
* bit to give the impression some time elapsed in the ISR.
* Without this the callback ( _shoot(timer) on xtimer_core.c )
* never fires.
*/
counter += TIMER_ACCURACY;
timer_isr_ctx.cb(timer_isr_ctx.arg, 0);
if (sched_context_switch_request) {
thread_yield();
}
}
if (counter == compares[1]) {
timer_isr_ctx.cb(timer_isr_ctx.arg, 1);
if (sched_context_switch_request) {
thread_yield();
}
}
if (counter == compares[2]) {
timer_isr_ctx.cb(timer_isr_ctx.arg, 2);
if (sched_context_switch_request) {
thread_yield();
}
}
mips_setcompare(mips_getcount() + TICKS_PER_US * TIMER_ACCURACY);
}
else {
spurious_int++;
}
}

View File

@ -18,74 +18,176 @@
*
* @}
*/
#include <assert.h>
#include "cpu.h"
#include "eic.h"
#include "sched.h"
#include "thread.h"
#include "assert.h"
#include "periph/uart.h"
#include "board.h"
#include "periph/gpio.h"
#define UxMODE(U) (U.regs[0x00/4])
#define UxMODECLR(U) (U.regs[0x04/4])
#define UxMODESET(U) (U.regs[0x08/4])
#define UxSTA(U) (U.regs[0x10/4])
#define UxSTACLR(U) (U.regs[0x14/4])
#define UxSTASET(U) (U.regs[0x18/4])
#define UxTXREG(U) (U.regs[0x20/4])
#define UxRXREG(U) (U.regs[0x30/4])
#define UxBRG(U) (U.regs[0x40/4])
#define REGS_SPACING (_UART2_BASE_ADDRESS - _UART1_BASE_ADDRESS)
#define UxMODE(U) ((U)[0x00/4])
#define UxMODECLR(U) ((U)[0x04/4])
#define UxMODESET(U) ((U)[0x08/4])
#define UxSTA(U) ((U)[0x10/4])
#define UxSTACLR(U) ((U)[0x14/4])
#define UxSTASET(U) ((U)[0x18/4])
#define UxTXREG(U) ((U)[0x20/4])
#define UxRXREG(U) ((U)[0x30/4])
#define UxBRG(U) ((U)[0x40/4])
/* PERIPHERAL_CLOCK must be defined in board file */
/**
* @brief Allocate memory to store the callback functions.
*/
static uart_isr_ctx_t uart_ctx[UART_NUMOF];
typedef struct PIC32_UART_tag {
volatile uint32_t *regs;
uint32_t clock;
} PIC32_UART_T;
static void irq_handler(uart_t uart)
{
uint32_t status = UxSTA(uart_config[uart].base);
/* pic uarts are numbered 1 to 6 */
static PIC32_UART_T pic_uart[UART_NUMOF + 1];
if (status & _U1STA_URXDA_MASK) {
uart_ctx[uart].rx_cb(uart_ctx[uart].arg, UxRXREG(uart_config[uart].base));
}
if (status & _U1STA_OERR_MASK) {
UxSTA(uart_config[uart].base) &= ~_U1STA_OERR_MASK;
}
#ifdef CPU_FAM_PIC32MX
eic_clear_flag(uart_config[uart].irq);
#else
eic_clear_flag(uart_config[uart].vector);
#endif
mips32r2_isr_end();
}
#ifdef UART_0_ISR
void UART_0_ISR(void)
{
irq_handler(UART_DEV(0));
}
#endif
#ifdef UART_1_ISR
void UART_1_ISR(void)
{
irq_handler(UART_DEV(1));
}
#endif
#ifdef UART_2_ISR
void UART_2_ISR(void)
{
irq_handler(UART_DEV(2));
}
#endif
#ifdef UART_3_ISR
void UART_3_ISR(void)
{
irq_handler(UART_DEV(3));
}
#endif
#ifdef UART_4_ISR
void UART_4_ISR(void)
{
irq_handler(UART_DEV(4));
}
#endif
#ifdef UART_5_ISR
void UART_5_ISR(void)
{
irq_handler(UART_DEV(5));
}
#endif
static void uart_init_pins(uart_t uart, uart_rx_cb_t rx_cb)
{
/* configure TX pin */
gpio_init(uart_config[uart].tx_pin, GPIO_OUT);
/* set TX pin high to avoid garbage during further initialization */
gpio_set(uart_config[uart].tx_pin);
*(uart_config[uart].tx_mux_reg) = uart_config[uart].tx_af;
/* configure RX pin */
if (rx_cb) {
gpio_init(uart_config[uart].rx_pin, GPIO_IN_PU);
*(uart_config[uart].rx_mux_reg) = uart_config[uart].rx_af;
}
}
int uart_init(uart_t uart, uint32_t baudrate, uart_rx_cb_t rx_cb, void *arg)
{
(void)rx_cb;
(void)arg;
assert(uart < UART_NUMOF);
assert(uart <= UART_NUMOF && uart != 0); /*No uart 0 on pic32*/
uart_init_pins(uart, rx_cb);
/* Pin Mux should be setup in board file */
UxBRG(uart_config[uart].base) = (uart_config[uart].clock / (16 * baudrate)) - 1;
UxSTA(uart_config[uart].base) = 0;
if (rx_cb) {
/* register callbacks */
uart_ctx[uart].rx_cb = rx_cb;
uart_ctx[uart].arg = arg;
UxSTASET(uart_config[uart].base) = _U1STA_URXEN_MASK;
pic_uart[uart].regs =
(volatile uint32_t *)(_UART1_BASE_ADDRESS + (uart - 1) * REGS_SPACING);
pic_uart[uart].clock = PERIPHERAL_CLOCK;
switch (uart) {
#ifdef UART_0_ISR
case UART_DEV(0): set_external_isr_cb(uart_config[uart].vector, UART_0_ISR); break;
#endif
#ifdef UART_1_ISR
case UART_DEV(1): set_external_isr_cb(uart_config[uart].vector, UART_1_ISR); break;
#endif
#ifdef UART_2_ISR
case UART_DEV(2): set_external_isr_cb(uart_config[uart].vector, UART_2_ISR); break;
#endif
#ifdef UART_3_ISR
case UART_DEV(3): set_external_isr_cb(uart_config[uart].vector, UART_3_ISR); break;
#endif
#ifdef UART_4_ISR
case UART_DEV(4): set_external_isr_cb(uart_config[uart].vector, UART_4_ISR); break;
#endif
#ifdef UART_5_ISR
case UART_DEV(5): set_external_isr_cb(uart_config[uart].vector, UART_5_ISR); break;
#endif
}
eic_configure_priority(uart_config[uart].vector, 1, 0);
UxBRG(pic_uart[uart])= (pic_uart[uart].clock / (16 * baudrate)) - 1;
UxSTA(pic_uart[uart])= 0;
UxMODE(pic_uart[uart])= _U1MODE_ON_MASK;
UxSTASET(pic_uart[uart])= _U1STA_URXEN_MASK;
UxSTASET(pic_uart[uart])= _U1STA_UTXEN_MASK;
#ifdef CPU_FAM_PIC32MX
eic_enable(uart_config[uart].irq);
#else
eic_enable(uart_config[uart].vector);
#endif
}
UxSTASET(uart_config[uart].base) = _U1STA_UTXEN_MASK;
UxMODE(uart_config[uart].base) = _U1MODE_ON_MASK;
return 0;
}
void uart_write(uart_t uart, const uint8_t *data, size_t len)
{
assert(uart <= UART_NUMOF && uart != 0);
assert(uart < UART_NUMOF);
while(len--) {
while(UxSTA(pic_uart[uart])& _U1STA_UTXBF_MASK) {}
UxTXREG(pic_uart[uart]) = *data++;
while(UxSTA(uart_config[uart].base)& _U1STA_UTXBF_MASK) {}
UxTXREG(uart_config[uart].base) = *data++;
}
}
void uart_poweron(uart_t uart)
{
assert(uart <= UART_NUMOF && uart != 0);
assert(uart < UART_NUMOF);
UxMODESET(pic_uart[uart])= _U1MODE_ON_MASK;
UxMODESET(uart_config[uart].base)= _U1MODE_ON_MASK;
}
void uart_poweroff(uart_t uart)
{
assert(uart <= UART_NUMOF && uart != 0);
assert(uart < UART_NUMOF);
UxMODECLR(pic_uart[uart])= _U1MODE_ON_MASK;
UxMODECLR(uart_config[uart].base)= _U1MODE_ON_MASK;
}

View File

@ -1 +1,4 @@
CPU_ARCH = m4k
CPU_FAM = pic32mx
-include $(RIOTCPU)/mips_pic32_common/Makefile.features

View File

@ -1,56 +0,0 @@
/*
* Copyright (C) 2016,2017, Imagination Technologies Limited and/or its
* affiliated group companies.
*
* This file is subject to the terms and conditions of the GNU Lesser
* General Public License v2.1. See the file LICENSE in the top level
* directory for more details.
*
*/
#include <assert.h>
#include "board.h"
#include "eic_irq.h"
void eic_irq_configure(int irq_num)
{
(void)irq_num;
/* Only timer interrupt supported currently */
assert(irq_num == EIC_IRQ_TIMER);
/* Enable IRQ0 CPU Timer Interrupt */
IEC0SET = _IEC0_CTIE_MASK;
/* Set IRQ 0 to priority 1.0 */
IPC0SET = 1 << _IPC0_CTIP_POSITION | 0 << _IPC0_CTIS_POSITION;
}
void eic_irq_enable(int irq_num)
{
(void)irq_num;
/* Only timer interrupt supported currently */
assert(irq_num == EIC_IRQ_TIMER);
/* Enable IRQ0 CPU Timer Interrupt */
IEC0SET = _IEC0_CTIE_MASK;
}
void eic_irq_disable(int irq_num)
{
(void)irq_num;
/* Only timer interrupt supported currently */
assert(irq_num == EIC_IRQ_TIMER);
/* Disable IRQ0 CPU Timer Interrupt */
IEC0CLR = _IEC0_CTIE_MASK;
}
void eic_irq_ack(int irq_num)
{
(void)irq_num;
/* Only timer interrupt supported currently */
assert(irq_num == EIC_IRQ_TIMER);
/* Ack the timer interrupt */
IFS0CLR =_IFS0_CTIF_MASK;
}

View File

@ -1,3 +1,6 @@
CPU_ARCH = m5101
CPU_FAM = pic32mz
FEATURES_PROVIDED += periph_hwrng
-include $(RIOTCPU)/mips_pic32_common/Makefile.features

View File

@ -1,56 +0,0 @@
/*
* Copyright(C) 2016,2017, Imagination Technologies Limited and/or its
* affiliated group companies.
*
* This file is subject to the terms and conditions of the GNU Lesser
* General Public License v2.1. See the file LICENSE in the top level
* directory for more details.
*
*/
#include <assert.h>
#include "board.h"
#include "eic_irq.h"
void eic_irq_configure(int irq_num)
{
(void)irq_num;
/* Only timer interrupt supported currently */
assert(irq_num == EIC_IRQ_TIMER);
/* Enable IRQ0 CPU Timer Interrupt */
IEC0SET = _IEC0_CTIE_MASK;
/* Set IRQ 0 to priority 1.0 */
IPC0SET = 1 << _IPC0_CTIP_POSITION | 0 << _IPC0_CTIS_POSITION;
}
void eic_irq_enable(int irq_num)
{
(void)irq_num;
/* Only timer interrupt supported currently */
assert(irq_num == EIC_IRQ_TIMER);
/* Enable IRQ0 CPU Timer Interrupt */
IEC0SET = _IEC0_CTIE_MASK;
}
void eic_irq_disable(int irq_num)
{
(void)irq_num;
/* Only timer interrupt supported currently */
assert(irq_num == EIC_IRQ_TIMER);
/* Disable IRQ0 CPU Timer Interrupt */
IEC0CLR = _IEC0_CTIE_MASK;
}
void eic_irq_ack(int irq_num)
{
(void)irq_num;
/* Only timer interrupt supported currently */
assert(irq_num == EIC_IRQ_TIMER);
/* Ack the timer interrupt */
IFS0CLR =_IFS0_CTIF_MASK;
}