# HG changeset patch # User Paul Boddie # Date 1540237442 -7200 # Node ID a8a72e8935620f2a76e10f822af6e98b34f9b3cc # Parent 2500eefe10f979838fb85b1838bdb1aa312c84ca Organised header and common payload files into include and lib directories. diff -r 2500eefe10f9 -r a8a72e893562 cpu.S --- a/cpu.S Mon Oct 22 19:12:33 2018 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,174 +0,0 @@ -/* - * PIC32 microcontroller interrupt handling code. - * - * Copyright (C) 2017, 2018 Paul Boddie - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -#include "mips.h" -#include "pic32.h" -#include "cpu.h" - -.globl enable_interrupts -.globl handle_error_level -.globl init_interrupts -.extern exception_handler -.extern interrupt_handler - -/* Put general routines in the text section. */ - -.text - -/* -Clear the error and exception status flags, making interrupts and exceptions -possible. -*/ - -handle_error_level: - mfc0 $t3, CP0_STATUS - - /* Clear error level and exception level. */ - - li $t4, ~(STATUS_ERL | STATUS_EXL) - and $t3, $t3, $t4 - mtc0 $t3, CP0_STATUS - - jr $ra - nop - -/* Enable interrupts and direct interrupt requests to non-bootloader vectors. */ - -enable_interrupts: - mfc0 $t3, CP0_STATUS - - /* Clear interrupt priority bits. */ - - li $t4, ~STATUS_IRQ - and $t3, $t3, $t4 - - /* Set interrupt priority. */ - - ori $t3, $t3, (CPU_INT_PRIORITY << STATUS_IRQ_SHIFT) - - /* CP0_STATUS &= ~STATUS_BEV (use non-bootloader vectors) */ - - li $t4, ~STATUS_BEV - and $t3, $t3, $t4 - - /* Enable interrupts. */ - - ori $t3, $t3, STATUS_IE - mtc0 $t3, CP0_STATUS - - jr $ra - nop - -/* Initialise the interrupt system parameters. */ - -init_interrupts: - /* Clear debug mode. */ - - mfc0 $t3, CP0_DEBUG - li $t4, ~DEBUG_DM - and $t3, $t3, $t4 - mtc0 $t3, CP0_DEBUG - - /* Update the exception base. */ - - mfc0 $t3, CP0_STATUS - li $t4, STATUS_BEV /* BEV = 1 or EBASE cannot be set */ - or $t3, $t3, $t4 - mtc0 $t3, CP0_STATUS - - la $t3, ebase - mtc0 $t3, CP0_EBASE - - /* Set vector spacing. */ - - li $t3, 0x20 /* Must be non-zero or the CPU gets upset */ - mtc0 $t3, CP0_INTCTL - - li $t3, CAUSE_IV /* IV = 1 (use EBASE+0x200 for interrupts) */ - mtc0 $t3, CP0_CAUSE - - jr $ra - nop - - - -/* Exception servicing, positioned at EBASE at the start of program memory. */ - -.section .vectors, "a" - -/* TLB error servicing. */ - -ebase: -tlb_handler: - j exception_handler - nop - - - -/* General exception servicing. */ - -.org 0x180 - -exc_handler: - j exception_handler - nop - - - -/* Interrupt servicing. */ - -.org 0x200 -.set noat - -#define IRQ_STACK_LIMIT (KSEG0_BASE + IRQ_STACK_SIZE) -#define IRQ_STACK_TOP (IRQ_STACK_LIMIT - 32 * 4) - -int_handler: - - /* Store affected registers from IRQ_STACK_LIMIT - 4 downwards. */ - - lui $k0, %hi(IRQ_STACK_LIMIT) - ori $k0, $k0, %lo(IRQ_STACK_LIMIT) - - .irp reg, \ - 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15 \ - 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, \ - 28, 29, 30, 31 - sw $\reg, -(\reg * 4)($k0) - .endr - - /* Switch to the IRQ stack. */ - - lui $sp, %hi(IRQ_STACK_TOP) - ori $sp, $sp, %lo(IRQ_STACK_TOP) - - jal interrupt_handler - nop - - /* Restore affected registers. */ - - .irp reg, \ - 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15 \ - 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, \ - 28, 29, 30, 31 - lw $\reg, -(\reg * 4)($k0) - .endr - - eret - nop diff -r 2500eefe10f9 -r a8a72e893562 cpu.h --- a/cpu.h Mon Oct 22 19:12:33 2018 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,35 +0,0 @@ -/* - * PIC32 microcontroller interrupt handling code. - * - * Copyright (C) 2017, 2018 Paul Boddie - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -#ifndef __CPU_H__ -#define __CPU_H__ - -#define CPU_INT_PRIORITY 3 - -#ifndef __ASSEMBLER__ - -/* Specific operations. */ - -void enable_interrupts(void); -void handle_error_level(void); -void init_interrupts(void); - -#endif /* __ASSEMBLER__ */ - -#endif /* __CPU_H__ */ diff -r 2500eefe10f9 -r a8a72e893562 debug.c --- a/debug.c Mon Oct 22 19:12:33 2018 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,108 +0,0 @@ -/* - * Some simple debugging functions. - * - * Copyright (C) 2018 Paul Boddie - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -#include "pic32_c.h" -#include "debug.h" - -/* Register output functions using UART1. */ - -void rbits(uint32_t reg) -{ - bits(REG(reg), 4); -} - -void rhex(uint32_t reg) -{ - hex(REG(reg), 4); -} - -/* Value output functions using UART1. */ - -void bits(uint32_t val, int bytes) -{ - uint32_t mask; - - for (mask = (1 << 31); mask; mask >>= 1) - if (val & mask) - uart_write('1'); - else - uart_write('0'); -} - -void hex(uint32_t val, int bytes) -{ - uint32_t mask; - uint8_t digit, shift, start = bytes * 8 - 4; - - for (mask = (0b1111 << start), shift = start; mask; mask >>= 4, shift -= 4) - { - digit = (val & mask) >> shift; - if (digit > 9) - uart_write('A' + digit - 10); - else - uart_write('0' + digit); - } -} - - - -/* General input/output functions. */ - -int uart_can_read(int uart) -{ - return REG(UART_REG(uart, UxSTA)) & 1; -} - -char uart_read_char(int uart) -{ - return (char) REG(UART_REG(uart, UxRXREG)); -} - -int uart_can_write(int uart) -{ - return !(REG(UART_REG(uart, UxSTA)) & (1 << 9)); /* UTXBF (buffer full) */ -} - -void uart_write_char(int uart, char c) -{ - while (!uart_can_write(uart)); /* busy loop */ - - REG(UART_REG(uart, UxTXREG)) = c; -} - - - -/* Functions using UART1. */ - -void uart_write(char c) -{ - uart_write_char(1, c); -} - -void uart_write_nl(void) -{ - uart_write('\r'); - uart_write('\n'); -} - -void uart_write_string(const char *s) -{ - while (*s) - uart_write(*s++); -} diff -r 2500eefe10f9 -r a8a72e893562 debug.h --- a/debug.h Mon Oct 22 19:12:33 2018 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,46 +0,0 @@ -/* - * Some simple debugging functions. - * - * Copyright (C) 2018 Paul Boddie - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -#ifndef __DEBUG_H__ -#define __DEBUG_H__ - -/* Register output functions using UART1. */ - -void rbits(uint32_t reg); -void rhex(uint32_t reg); - -/* Value output functions using UART1. */ - -void bits(uint32_t val, int bytes); -void hex(uint32_t val, int bytes); - -/* General input/output functions. */ - -int uart_can_read(int uart); -char uart_read_char(int uart); -int uart_can_write(int uart); -void uart_write_char(int uart, char c); - -/* Functions using UART1. */ - -void uart_write(char c); -void uart_write_nl(void); -void uart_write_string(const char *s); - -#endif /* __DEBUG_H__ */ diff -r 2500eefe10f9 -r a8a72e893562 include/cpu.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/include/cpu.h Mon Oct 22 21:44:02 2018 +0200 @@ -0,0 +1,35 @@ +/* + * PIC32 microcontroller interrupt handling code. + * + * Copyright (C) 2017, 2018 Paul Boddie + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#ifndef __CPU_H__ +#define __CPU_H__ + +#define CPU_INT_PRIORITY 3 + +#ifndef __ASSEMBLER__ + +/* Specific operations. */ + +void enable_interrupts(void); +void handle_error_level(void); +void init_interrupts(void); + +#endif /* __ASSEMBLER__ */ + +#endif /* __CPU_H__ */ diff -r 2500eefe10f9 -r a8a72e893562 include/debug.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/include/debug.h Mon Oct 22 21:44:02 2018 +0200 @@ -0,0 +1,46 @@ +/* + * Some simple debugging functions. + * + * Copyright (C) 2018 Paul Boddie + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#ifndef __DEBUG_H__ +#define __DEBUG_H__ + +/* Register output functions using UART1. */ + +void rbits(uint32_t reg); +void rhex(uint32_t reg); + +/* Value output functions using UART1. */ + +void bits(uint32_t val, int bytes); +void hex(uint32_t val, int bytes); + +/* General input/output functions. */ + +int uart_can_read(int uart); +char uart_read_char(int uart); +int uart_can_write(int uart); +void uart_write_char(int uart, char c); + +/* Functions using UART1. */ + +void uart_write(char c); +void uart_write_nl(void); +void uart_write_string(const char *s); + +#endif /* __DEBUG_H__ */ diff -r 2500eefe10f9 -r a8a72e893562 include/init.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/include/init.h Mon Oct 22 21:44:02 2018 +0200 @@ -0,0 +1,164 @@ +/* + * PIC32 peripheral configuration and initialisation. + * + * Copyright (C) 2017, 2018 Paul Boddie + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#ifndef __INIT_H__ +#define __INIT_H__ + +#include "pic32_c.h" + + + +/* Basic initialisation. */ + +void init_memory(void); +void init_pins(void); +void init_outputs(void); + + + +/* Peripheral pin configuration. */ + +void lock_config(void); +void unlock_config(void); + + + +/* Convenience operations. */ + +void interrupts_on(void); + + + +/* DMA configuration. */ + +void init_dma(void); + +void dma_init(int channel, uint8_t pri); + +void dma_init_interrupt(int channel, uint8_t conditions, + uint8_t pri, uint8_t sub); + +void dma_off(int channel); + +void dma_on(int channel); + +void dma_set_auto_enable(int channel, int enable); + +void dma_set_chaining(int channel, enum dma_chain chain); + +void dma_set_enable(int channel, int enable); + +void dma_set_interrupt(int channel, uint8_t int_num, int enable); + +void dma_set_interrupt_enable(int channel, int enable); + +void dma_set_receive_events(int channel, int enable); + +void dma_set_transfer(int channel, + uint32_t source_start_address, uint16_t source_size, + uint32_t destination_start_address, uint16_t destination_size, + uint16_t cell_size); + +int DMA_INT_FLAGS(int channel, uint8_t flags); + +uint32_t DMA_IPC_PRI(int channel, uint8_t pri, uint8_t sub); + + + +/* External interrupt configuration. */ + +void int_init_interrupt(int int_num, uint8_t pri, uint8_t sub); + +int INT_INT_FLAGS(int int_num, uint8_t flags); + +uint32_t INT_IPC_PRI(int int_num, uint8_t pri, uint8_t sub); +uint32_t INT_IPC_REG(int int_num); + + + +/* Output compare configuration. */ + +void oc_init(int unit, uint8_t mode, int timer); + +void oc_init_interrupt(int unit, uint8_t pri, uint8_t sub); + +void oc_on(int unit); + +void oc_set_pulse(int unit, uint32_t start); + +void oc_set_pulse_end(int unit, uint32_t end); + +int OC_INT_FLAGS(int unit, uint8_t flags); + +uint32_t OC_IPC_PRI(int unit, uint8_t pri, uint8_t sub); +uint32_t OC_IPC_REG(int unit); + + + +/* Parallel mode configuration. */ + +void init_pm(void); + +void pm_init(int port, uint8_t mode); + +void pm_init_interrupt(int port, uint8_t pri, uint8_t sub); + +void pm_off(int port); + +void pm_on(int port); + +void pm_set_output(int port, int write_enable, int read_enable); + +int PM_INT_FLAGS(int port, uint8_t flags); + +uint32_t PM_IPC_PRI(int port, uint8_t pri, uint8_t sub); +uint32_t PM_IPC_REG(int port); + + + +/* Timer configuration. */ + +void timer_init(int timer, uint8_t prescale, uint16_t limit); + +void timer_init_interrupt(int timer, uint8_t pri, uint8_t sub); + +void timer_on(int timer); + +int TIMER_INT_FLAGS(int timer, uint8_t flags); + +uint32_t TIMER_IPC_PRI(int timer, uint8_t pri, uint8_t sub); +uint32_t TIMER_IPC_REG(int timer); + + + +/* UART configuration. */ + +void uart_init(int uart, uint32_t baudrate); + +void uart_init_interrupt(int uart, uint8_t conditions, + uint8_t pri, uint8_t sub); + +void uart_on(int uart); + +int UART_INT_FLAGS(int uart, uint8_t flags); + +uint32_t UART_IPC_PRI(int uart, uint8_t pri, uint8_t sub); +uint32_t UART_IPC_REG(int uart); + +#endif /* __INIT_H__ */ diff -r 2500eefe10f9 -r a8a72e893562 include/mips.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/include/mips.h Mon Oct 22 21:44:02 2018 +0200 @@ -0,0 +1,63 @@ +#ifndef __MIPS_H__ +#define __MIPS_H__ + +#define KSEG0_BASE 0x80000000 +#define KSEG1_BASE 0xA0000000 + +#define CP0_INDEX $0 +#define CP0_ENTRYLO0 $2 +#define CP0_ENTRYLO1 $3 +#define CP0_CONTEXT $4 +#define CP0_PAGEMASK $5 +#define CP0_WIRED $6 +#define CP0_BADVADDR $8 +#define CP0_COUNT $9 +#define CP0_ENTRYHI $10 +#define CP0_COMPARE $11 +#define CP0_STATUS $12 +#define CP0_INTCTL $12, 1 +#define CP0_CAUSE $13 +#define CP0_EPC $14 +#define CP0_EBASE $15, 1 +#define CP0_CONFIG $16 +#define CP0_WATCHLO $18 +#define CP0_DEBUG $23 +#define CP0_TAGLO $28 +#define CP0_TAGHI $29 +#define CP0_ERROREPC $30, 0 + +#define STATUS_CP0 0x10000000 +#define STATUS_BEV 0x00400000 + +#define STATUS_IRQ 0x0000fc00 +#define STATUS_IRQ_SHIFT 10 + +#define STATUS_UM 0x00000010 +#define STATUS_ERL 0x00000004 +#define STATUS_EXL 0x00000002 +#define STATUS_IE 0x00000001 + +#define CAUSE_IV 0x00800000 + +#define EBASE_MASK 0x3ffff000 + +#define INTCTL_MASK 0x000003e0 + +#define DEBUG_DM 0x40000000 + +#define TLB_CACHED 0x00000018 +#define TLB_UNCACHED 0x00000010 +#define TLB_DIRTY 0x00000004 +#define TLB_VALID 0x00000002 +#define TLB_GLOBAL 0x00000001 + +#define TLB_READ (TLB_CACHED | TLB_VALID) +#define TLB_WRITE (TLB_CACHED | TLB_DIRTY | TLB_VALID) +#define TLB_ALL_READ (TLB_CACHED | TLB_VALID | TLB_GLOBAL) +#define TLB_ALL_WRITE (TLB_CACHED | TLB_DIRTY | TLB_VALID | TLB_GLOBAL) + +#define CONFIG_K0 0x00000007 +#define CONFIG_K0_UNCACHED 2 +#define CONFIG_K0_CACHABLE_NONCOHERENT 3 + +#endif /* __MIPS_H__ */ diff -r 2500eefe10f9 -r a8a72e893562 include/pic32.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/include/pic32.h Mon Oct 22 21:44:02 2018 +0200 @@ -0,0 +1,382 @@ +/* + * PIC32 peripheral descriptions. + * + * Copyright (C) 2017, 2018 Paul Boddie + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#ifndef __PIC32_H__ +#define __PIC32_H__ + +/* Peripheral addresses. + * See... + * TABLE 4-1: SFR MEMORYMAP + * TABLE 11-3: PORTA REGISTER MAP + * PIC32MX1XX/2XX 28/36/44-pin Family Data Sheet + */ + +#define OSCCON 0xBF80F000 +#define REFOCON 0xBF80F020 +#define REFOTRIM 0xBF80F030 +#define CFGCON 0xBF80F200 +#define SYSKEY 0xBF80F230 + +#define INT2R 0xBF80FA08 +#define U1RXR 0xBF80FA50 + +#define RPA0R 0xBF80FB00 +#define RPA1R 0xBF80FB04 +#define RPA2R 0xBF80FB08 +#define RPA3R 0xBF80FB0C +#define RPA4R 0xBF80FB10 +#define RPB0R 0xBF80FB2C +#define RPB1R 0xBF80FB30 +#define RPB2R 0xBF80FB34 +#define RPB3R 0xBF80FB38 +#define RPB4R 0xBF80FB3C +#define RPB5R 0xBF80FB40 +#define RPB10R 0xBF80FB54 +#define RPB15R 0xBF80FB68 + +#define INTCON 0xBF881000 +#define IFS0 0xBF881030 +#define IFS1 0xBF881040 +#define IEC0 0xBF881060 +#define IEC1 0xBF881070 +#define IPC0 0xBF881090 +#define IPC1 0xBF8810A0 +#define IPC2 0xBF8810B0 +#define IPC3 0xBF8810C0 +#define IPC4 0xBF8810D0 +#define IPC5 0xBF8810E0 +#define IPC6 0xBF8810F0 +#define IPC7 0xBF881100 +#define IPC8 0xBF881110 +#define IPC9 0xBF881120 +#define IPC10 0xBF881130 + +#define BMXCON 0xBF882000 +#define BMXDKPBA 0xBF882010 +#define BMXDUDBA 0xBF882020 +#define BMXDUPBA 0xBF882030 +#define BMXDRMSZ 0xBF882040 + +#define ANSELA 0xBF886000 +#define TRISA 0xBF886010 +#define PORTA 0xBF886020 +#define LATA 0xBF886030 +#define ODCA 0xBF886040 +#define ANSELB 0xBF886100 +#define TRISB 0xBF886110 +#define PORTB 0xBF886120 +#define LATB 0xBF886130 +#define ODCB 0xBF886140 + +/* DEVCFG conveniences. */ + +#define DEVCFG1_UNUSED 0xff7fcbd8 /* exclude FWDTWINSZ, WINDIS, WDTPS, FCKSM, POSCMOD, IESO */ + +#define DEVCFG1_FWDTEN_OFF (0 << 23) +#define DEVCFG1_FWDTEN_ON (1 << 23) + +#define DEVCFG1_FPBDIV_1 (0b00 << 12) +#define DEVCFG1_FPBDIV_2 (0b01 << 12) +#define DEVCFG1_FPBDIV_4 (0b10 << 12) +#define DEVCFG1_FPBDIV_8 (0b11 << 12) + +#define DEVCFG1_OSCIOFNC_ON (0 << 10) +#define DEVCFG1_OSCIOFNC_OFF (1 << 10) + +#define DEVCFG1_FSOSCEN_OFF (0 << 5) +#define DEVCFG1_FSOSCEN_ON (1 << 5) + +#define DEVCFG1_FNOSC_FRC (0b000) +#define DEVCFG1_FNOSC_FRCDIV_PLL (0b001) +#define DEVCFG1_FNOSC_FRCDIV (0b111) + +#define DEVCFG2_UNUSED 0xfff8ff88 /* exclude UPLLEN, UPLLIDIV */ + +#define DEVCFG2_FPLLODIV_1 (0b000 << 16) +#define DEVCFG2_FPLLODIV_2 (0b001 << 16) +#define DEVCFG2_FPLLODIV_4 (0b010 << 16) +#define DEVCFG2_FPLLODIV_8 (0b011 << 16) +#define DEVCFG2_FPLLODIV_16 (0b100 << 16) +#define DEVCFG2_FPLLODIV_32 (0b101 << 16) +#define DEVCFG2_FPLLODIV_64 (0b110 << 16) +#define DEVCFG2_FPLLODIV_128 (0b111 << 16) + +#define DEVCFG2_FPLLMUL_15 (0b000 << 4) +#define DEVCFG2_FPLLMUL_16 (0b001 << 4) +#define DEVCFG2_FPLLMUL_17 (0b010 << 4) +#define DEVCFG2_FPLLMUL_18 (0b011 << 4) +#define DEVCFG2_FPLLMUL_19 (0b100 << 4) +#define DEVCFG2_FPLLMUL_20 (0b101 << 4) +#define DEVCFG2_FPLLMUL_21 (0b110 << 4) +#define DEVCFG2_FPLLMUL_24 (0b111 << 4) + +#define DEVCFG2_FPLLIDIV_1 (0b000) +#define DEVCFG2_FPLLIDIV_2 (0b001) +#define DEVCFG2_FPLLIDIV_3 (0b010) +#define DEVCFG2_FPLLIDIV_4 (0b011) +#define DEVCFG2_FPLLIDIV_5 (0b100) +#define DEVCFG2_FPLLIDIV_6 (0b101) +#define DEVCFG2_FPLLIDIV_10 (0b110) +#define DEVCFG2_FPLLIDIV_12 (0b111) + +/* DMA conveniences. */ + +#define DMACON 0xBF883000 +#define DCH0CON 0xBF883060 +#define DCH1CON 0xBF883120 +#define DCH2CON 0xBF8831E0 +#define DCH3CON 0xBF8832A0 + +#define DCHMIN 0 +#define DCHMAX 3 +#define DCHBASE DCH0CON +#define DCHSTEP (DCH1CON - DCH0CON) + +#define DCHxCON 0x00 +#define DCHxECON 0x10 +#define DCHxINT 0x20 +#define DCHxSSA 0x30 +#define DCHxDSA 0x40 +#define DCHxSSIZ 0x50 +#define DCHxDSIZ 0x60 +#define DCHxSPTR 0x70 +#define DCHxDPTR 0x80 +#define DCHxCSIZ 0x90 +#define DCHxCPTR 0xA0 +#define DCHxDAT 0xB0 + +#define DMAIEC IEC1 + +#define DCHxIE 1 + +#define DMAIFS IFS1 + +#define DCHxIF 1 + +#define DMAINTBASE 28 + +#define DMAIPC IPC10 +#define DCHIPCBASE 0 +#define DCHIPCSTEP 8 + +/* External interrupt conveniences. */ + +#define INTMIN 0 +#define INTMAX 4 + +#define INTIEC IEC0 + +#define INTxIE 1 + +#define INTIFS IFS0 + +#define INTxIF 1 + +#define INTINTBASE 3 +#define INTINTSTEP 5 + +#define INT0IPC IPC0 +#define INT1IPC IPC1 +#define INT2IPC IPC2 +#define INT3IPC IPC3 +#define INT4IPC IPC4 +#define INTIPCBASE 24 + +/* Output compare conveniences. */ + +#define OC1CON 0xBF803000 +#define OC2CON 0xBF803200 +#define OC3CON 0xBF803400 +#define OC4CON 0xBF803600 +#define OC5CON 0xBF803800 + +#define OCMIN 1 +#define OCMAX 5 +#define OCBASE OC1CON +#define OCSTEP (OC2CON - OC1CON) + +#define OCxCON 0x00 +#define OCxR 0x10 +#define OCxRS 0x20 + +#define OCIEC IEC0 + +#define OCxIE 1 + +#define OCIFS IFS0 + +#define OCxIF 1 + +#define OCINTBASE 7 +#define OCINTSTEP 5 + +#define OC1IPC IPC1 +#define OC2IPC IPC2 +#define OC3IPC IPC3 +#define OC4IPC IPC4 +#define OC5IPC IPC5 +#define OCIPCBASE 16 + +/* Parallel mode conveniences. */ + +#define PMCON 0xBF807000 + +#define PMxCON 0x00 +#define PMxMODE 0x10 +#define PMxADDR 0x20 +#define PMxDOUT 0x30 +#define PMxDIN 0x40 +#define PMxAEN 0x50 +#define PMxSTAT 0x60 + +#define PMMIN 0 +#define PMMAX 0 +#define PMBASE PMCON +#define PMSTEP 0 + +#define PMIEC IEC1 + +#define PMxIE 1 +#define PMxEIE 2 + +#define PMIFS IFS1 + +#define PMxIF 1 +#define PMxEIF 2 + +#define PMINTBASE 16 +#define PMINTSTEP 0 + +#define PMIPC IPC8 +#define PMIPCBASE 24 + +/* Timer conveniences. */ + +#define T1CON 0xBF800600 +#define T2CON 0xBF800800 +#define T3CON 0xBF800A00 +#define T4CON 0xBF800C00 +#define T5CON 0xBF800E00 + +#define TIMERMIN 1 +#define TIMERMAX 5 +#define TIMERBASE T1CON +#define TIMERSTEP (T2CON - T1CON) + +#define TxCON 0x00 +#define TMRx 0x10 +#define PRx 0x20 + +#define TIMERIEC IEC0 + +#define TxIE 1 + +#define TIMERIFS IEC0 + +#define TxIF 1 + +#define TIMERINTBASE 4 +#define TIMERINTSTEP 5 + +#define TIMER1IPC IPC1 +#define TIMER2IPC IPC2 +#define TIMER3IPC IPC3 +#define TIMER4IPC IPC4 +#define TIMER5IPC IPC5 +#define TIMERIPCBASE 0 + +/* UART conveniences. */ + +#define U1MODE 0xBF806000 +#define U2MODE 0xBF806200 + +#define UARTMIN 1 +#define UARTMAX 2 +#define UARTBASE U1MODE +#define UARTSTEP (U2MODE - U1MODE) + +#define UxMODE 0x00 +#define UxSTA 0x10 +#define UxTXREG 0x20 +#define UxRXREG 0x30 +#define UxBRG 0x40 + +#define UARTIEC IEC1 + +#define UxEIE 1 +#define UxRIE 2 +#define UxTIE 4 + +#define UARTIFS IFS1 + +#define UxEIF 1 +#define UxRIF 2 +#define UxTIF 4 + +#define UARTINTBASE 7 +#define UARTINTSTEP 14 + +#define UART1IPC IPC8 +#define UART1IPCBASE 0 +#define UART2IPC IPC9 +#define UART2IPCBASE 8 + +/* Interrupt numbers. + * See... + * TABLE 7-1: INTERRUPT IRQ, VECTOR AND BIT LOCATION + * PIC32MX1XX/2XX 28/36/44-pin Family Data Sheet + */ + +#define DMA0 60 +#define DMA1 61 +#define DMA2 62 +#define DMA3 63 +#define INT0 3 +#define INT1 8 +#define INT2 13 +#define INT3 18 +#define INT4 23 +#define OC1 7 +#define OC2 12 +#define OC3 17 +#define OC4 22 +#define OC5 27 +#define PMP 48 +#define PMPE 49 +#define T1 4 +#define T2 9 +#define T3 14 +#define T4 19 +#define T5 24 +#define U1RX 40 +#define U1TX 41 +#define U2RX 54 +#define U2TX 55 + +/* Address modifiers. + * See... + * 11.2 CLR, SET and INV Registers + * PIC32MX1XX/2XX 28/36/44-pin Family Data Sheet + */ + +#define CLR 0x4 +#define SET 0x8 +#define INV 0xC + +#endif /* __PIC32_H__ */ diff -r 2500eefe10f9 -r a8a72e893562 include/pic32_c.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/include/pic32_c.h Mon Oct 22 21:44:02 2018 +0200 @@ -0,0 +1,110 @@ +/* + * PIC32 peripheral access utilities. + * + * Copyright (C) 2018 Paul Boddie + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#ifndef __ASSEMBLER__ + +#ifndef __PIC32_C_H__ +#define __PIC32_C_H__ + +#include +#include "mips.h" +#include "pic32.h" + + + +/* Access. */ + +#define REG(mem) *((volatile uint32_t *) (mem)) + + + +/* Bit clearing, setting and inverting. */ + +static inline void CLR_REG(uint32_t mem, uint32_t val) +{ + REG(mem + CLR) = val; +} + +static inline void SET_REG(uint32_t mem, uint32_t val) +{ + REG(mem + SET) = val; +} + +static inline void INV_REG(uint32_t mem, uint32_t val) +{ + REG(mem + INV) = val; +} + + + +/* Address translation. */ + +static inline uint32_t PHYSICAL(uint32_t addr) +{ + return ((uint32_t) addr) - KSEG0_BASE; +} + +static inline uint32_t HW_PHYSICAL(uint32_t addr) +{ + return ((uint32_t) addr) - KSEG1_BASE; +} + + + +/* Register collection access. */ + +static inline uint32_t DMA_REG(int channel, uint32_t reg) +{ + return DCHBASE + reg + (channel - DCHMIN) * DCHSTEP; +} + +static inline uint32_t OC_REG(int unit, uint32_t reg) +{ + return OCBASE + reg + (unit - OCMIN) * OCSTEP; +} + +static inline uint32_t PM_REG(int port, uint32_t reg) +{ + return PMBASE + reg + (port - PMMIN) * PMSTEP; +} + +static inline uint32_t TIMER_REG(int timer, uint32_t reg) +{ + return TIMERBASE + reg + (timer - TIMERMIN) * TIMERSTEP; +} + +static inline uint32_t UART_REG(int uart, uint32_t reg) +{ + return UARTBASE + reg + (uart - UARTMIN) * UARTSTEP; +} + + + +/* Convenience types. */ + +enum dma_chain +{ + dma_chain_none, + dma_chain_next, + dma_chain_previous, +}; + +#endif /* __PIC32_C_H__ */ + +#endif /* __ASSEMBLER__ */ diff -r 2500eefe10f9 -r a8a72e893562 init.c --- a/init.c Mon Oct 22 19:12:33 2018 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,715 +0,0 @@ -/* - * PIC32 peripheral configuration and initialisation. - * - * Copyright (C) 2017, 2018 Paul Boddie - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -#include "cpu.h" -#include "pic32_c.h" -#include "init.h" - -/* Application-specific configuration. */ - -#include "devconfig.h" - - - -/* Basic memory and pin initialisation. */ - -void init_memory(void) -{ - /* - Configure RAM. - See: http://microchipdeveloper.com/32bit:mx-arch-exceptions-processor-initialization - */ - - uint32_t config = REG(BMXCON); - - /* Set zero wait states for address setup. */ - - config &= ~(1 << 6); /* BMXCON<6> = BMXWSDRM = 0 */ - - /* Set bus arbitration mode. */ - - config &= ~0b111; - config |= 0b010; /* BMXCON<2:0> = BMXARB<2:0> = 2 */ - - REG(BMXCON) = config; -} - -void init_pins(void) -{ - /* DEVCFG0<2> also needs setting to 0 before the program is run. */ - - CLR_REG(CFGCON, 1 << 3); /* CFGCON<3> = JTAGEN = 0 */ -} - -void init_outputs(void) -{ - /* Remove analogue features from pins. */ - - REG(ANSELA) = 0; - REG(ANSELB) = 0; - - /* Set pins as outputs. */ - - REG(TRISA) = 0; - REG(TRISB) = 0; - - /* Clear outputs. */ - - REG(PORTA) = 0; - REG(PORTB) = 0; -} - - - -/* Peripheral pin configuration. */ - -void lock_config(void) -{ - SET_REG(CFGCON, 1 << 13); /* IOLOCK = 1 */ - - /* Lock the configuration again. */ - - REG(SYSKEY) = 0x33333333; -} - -void unlock_config(void) -{ - /* Unlock the configuration register bits. */ - - REG(SYSKEY) = 0; - REG(SYSKEY) = 0xAA996655; - REG(SYSKEY) = 0x556699AA; - - CLR_REG(CFGCON, 1 << 13); /* IOLOCK = 0 */ -} - - - -/* Convenience operations. */ - -void interrupts_on(void) -{ - init_interrupts(); - enable_interrupts(); - handle_error_level(); -} - - - -/* DMA configuration. */ - -void init_dma(void) -{ - /* Disable DMA interrupts (DMAxIE). */ - - CLR_REG(DMAIEC, 0b1111 << DMAINTBASE); - - /* Clear DMA interrupt flags (DMAxIF). */ - - CLR_REG(DMAIFS, 0b1111 << DMAINTBASE); - - /* Enable DMA. */ - - SET_REG(DMACON, 1 << 15); -} - -/* Initialise the given channel. */ - -void dma_init(int channel, uint8_t pri) -{ - if ((channel < DCHMIN) || (channel > DCHMAX)) - return; - - /* Initialise a channel. */ - - REG(DMA_REG(channel, DCHxCON)) = pri & 0b11; - REG(DMA_REG(channel, DCHxECON)) = 0; - REG(DMA_REG(channel, DCHxINT)) = 0; -} - -/* Set the channel repeated enable mode, enabling it again when a block transfer - completes. The documentation describes this as auto-enable. */ - -void dma_set_auto_enable(int channel, int enable) -{ - (enable ? SET_REG : CLR_REG)(DMA_REG(channel, DCHxCON), 1 << 4); -} - -/* Set the channel chaining mode. */ - -void dma_set_chaining(int channel, enum dma_chain chain) -{ - (chain != dma_chain_none ? - SET_REG : CLR_REG)(DMA_REG(channel, DCHxCON), 1 << 5); - - (chain == dma_chain_next ? - SET_REG : CLR_REG)(DMA_REG(channel, DCHxCON), 1 << 8); -} - -/* Configure a channel's initiation interrupt. */ - -void dma_set_interrupt(int channel, uint8_t int_num, int enable) -{ - if ((channel < DCHMIN) || (channel > DCHMAX)) - return; - - /* Allow an interrupt to trigger the transfer. */ - - REG(DMA_REG(channel, DCHxECON)) = (int_num << 8) | - ((enable ? 1 : 0) << 4); -} - -/* Configure only the channel's initiation interrupt status. */ - -void dma_set_interrupt_enable(int channel, int enable) -{ - if ((channel < DCHMIN) || (channel > DCHMAX)) - return; - - (enable ? SET_REG : CLR_REG)(DMA_REG(channel, DCHxECON), 1 << 4); -} - -/* Permit the channel to register events while disabled or suspended. A - suspended channel is one that is enabled but where the DMA peripheral - has been suspended. */ - -void dma_set_receive_events(int channel, int enable) -{ - (enable ? SET_REG : CLR_REG)(DMA_REG(channel, DCHxCON), 1 << 6); -} - -/* Set a channel's transfer parameters. */ - -void dma_set_transfer(int channel, - uint32_t source_start_address, uint16_t source_size, - uint32_t destination_start_address, uint16_t destination_size, - uint16_t cell_size) -{ - if ((channel < DCHMIN) || (channel > DCHMAX)) - return; - - REG(DMA_REG(channel, DCHxSSIZ)) = source_size; - REG(DMA_REG(channel, DCHxSSA)) = source_start_address; - REG(DMA_REG(channel, DCHxDSIZ)) = destination_size; - REG(DMA_REG(channel, DCHxDSA)) = destination_start_address; - REG(DMA_REG(channel, DCHxCSIZ)) = cell_size; -} - -/* Configure interrupts caused by the channel. */ - -void dma_init_interrupt(int channel, uint8_t conditions, - uint8_t pri, uint8_t sub) -{ - if ((channel < DCHMIN) || (channel > DCHMAX)) - return; - - /* Disable channel interrupt and clear interrupt flag. */ - - CLR_REG(DMAIEC, DMA_INT_FLAGS(channel, 1)); - CLR_REG(DMAIFS, DMA_INT_FLAGS(channel, 1)); - - /* Produce an interrupt for the provided conditions. */ - - REG(DMA_REG(channel, DCHxINT)) = conditions << 16; - - /* Set interrupt priorities. */ - - REG(DMAIPC) = (REG(DMAIPC) & - ~(DMA_IPC_PRI(channel, 7, 3))) | - DMA_IPC_PRI(channel, pri, sub); - - /* Enable interrupt. */ - - SET_REG(DMAIEC, DMA_INT_FLAGS(channel, 1)); -} - -/* Enable or disable the channel. */ - -void dma_set_enable(int channel, int enable) -{ - if ((channel < DCHMIN) || (channel > DCHMAX)) - return; - - (enable ? SET_REG : CLR_REG)(DMA_REG(channel, DCHxCON), 1 << 7); -} - -/* Disable a DMA channel. */ - -void dma_off(int channel) -{ - dma_set_enable(channel, 0); -} - -/* Enable a DMA channel. */ - -void dma_on(int channel) -{ - dma_set_enable(channel, 1); -} - - - -/* External interrupt initialisation. */ - -void int_init_interrupt(int int_num, uint8_t pri, uint8_t sub) -{ - if ((int_num < INTMIN) || (int_num > INTMAX)) - return; - - /* Disable interrupt and clear interrupt flag. */ - - CLR_REG(INTIEC, INT_INT_FLAGS(int_num, INTxIE)); - CLR_REG(INTIFS, INT_INT_FLAGS(int_num, INTxIF)); - - /* Set interrupt priorities. */ - - REG(INT_IPC_REG(int_num)) = (REG(INT_IPC_REG(int_num)) & - ~(INT_IPC_PRI(int_num, 7, 3))) | - INT_IPC_PRI(int_num, pri, sub); - - /* Enable interrupt. */ - - SET_REG(INTIEC, INT_INT_FLAGS(int_num, INTxIE)); -} - - - -/* Output compare configuration. */ - -void oc_init(int unit, uint8_t mode, int timer) -{ - if ((unit < OCMIN) || (unit > OCMAX)) - return; - - REG(OC_REG(unit, OCxCON)) = (timer == 3 ? (1 << 3) : 0) | (mode & 0b111); -} - -/* Set the start value for the pulse. */ - -void oc_set_pulse(int unit, uint32_t start) -{ - if ((unit < OCMIN) || (unit > OCMAX)) - return; - - REG(OC_REG(unit, OCxR)) = start; -} - -/* Set the end value for the pulse. */ - -void oc_set_pulse_end(int unit, uint32_t end) -{ - if ((unit < OCMIN) || (unit > OCMAX)) - return; - - REG(OC_REG(unit, OCxRS)) = end; -} - -/* Configure interrupts caused by the unit. */ - -void oc_init_interrupt(int unit, uint8_t pri, uint8_t sub) -{ - if ((unit < OCMIN) || (unit > OCMAX)) - return; - - /* Disable interrupt and clear interrupt flag. */ - - CLR_REG(OCIEC, OC_INT_FLAGS(unit, OCxIE)); - CLR_REG(OCIFS, OC_INT_FLAGS(unit, OCxIF)); - - /* Set interrupt priorities. */ - - REG(OC_IPC_REG(unit)) = (REG(OC_IPC_REG(unit)) & - ~(OC_IPC_PRI(unit, 7, 3))) | - OC_IPC_PRI(unit, pri, sub); - - /* Enable interrupt. */ - - SET_REG(OCIEC, OC_INT_FLAGS(unit, OCxIE)); -} - -/* Enable a unit. */ - -void oc_on(int unit) -{ - if ((unit < OCMIN) || (unit > OCMAX)) - return; - - SET_REG(OC_REG(unit, OCxCON), 1 << 15); -} - - - -/* Parallel mode configuration. */ - -void init_pm(void) -{ - int i; - - /* Disable PM interrupts (PMxIE). */ - - CLR_REG(PMIEC, 0b11 << PMINTBASE); - - /* Clear PM interrupt flags (PMxIF). */ - - CLR_REG(PMIFS, 0b11 << PMINTBASE); - - /* Disable PM for configuration. */ - - for (i = PMMIN; i <= PMMAX; i++) - REG(PM_REG(i, PMxCON)) = 0; -} - -/* Configure the parallel mode. */ - -void pm_init(int port, uint8_t mode) -{ - if ((port < PMMIN) || (port > PMMAX)) - return; - - REG(PM_REG(port, PMxMODE)) = (mode & 0b11) << 8; - REG(PM_REG(port, PMxAEN)) = 0; - REG(PM_REG(port, PMxADDR)) = 0; -} - -/* Configure output signals. */ - -void pm_set_output(int port, int write_enable, int read_enable) -{ - if ((port < PMMIN) || (port > PMMAX)) - return; - - REG(PM_REG(port, PMxCON)) = (write_enable ? (1 << 9) : 0) | - (read_enable ? (1 << 8) : 0) | - (1 << 1); /* WRSP: PMENB active high */ -} - -/* Configure interrupts caused by parallel mode. */ - -void pm_init_interrupt(int port, uint8_t pri, uint8_t sub) -{ - if ((port < PMMIN) || (port > PMMAX)) - return; - - /* Disable interrupt and clear interrupt flag. */ - - CLR_REG(PMIEC, PM_INT_FLAGS(port, PMxIE)); - CLR_REG(PMIFS, PM_INT_FLAGS(port, PMxIF)); - - /* Set interrupt priorities. */ - - REG(PM_IPC_REG(port)) = (REG(PM_IPC_REG(port)) & - ~(PM_IPC_PRI(port, 7, 3))) | - PM_IPC_PRI(port, pri, sub); - - /* Enable interrupt. */ - - SET_REG(PMIEC, PM_INT_FLAGS(port, PMxIE)); -} - -/* Enable parallel mode. */ - -void pm_on(int port) -{ - if ((port < PMMIN) || (port > PMMAX)) - return; - - SET_REG(PM_REG(port, PMxCON), 1 << 15); -} - -/* Disable parallel mode. */ - -void pm_off(int port) -{ - if ((port < PMMIN) || (port > PMMAX)) - return; - - CLR_REG(PM_REG(port, PMxCON), 1 << 15); -} - - - - -/* Timer configuration. */ - -void timer_init(int timer, uint8_t prescale, uint16_t limit) -{ - /* NOTE: Should convert from the real prescale value. */ - - REG(TIMER_REG(timer, TxCON)) = (prescale & 0b111) << 4; - REG(TIMER_REG(timer, TMRx)) = 0; - REG(TIMER_REG(timer, PRx)) = limit; -} - -/* Configure interrupts caused by the timer. */ - -void timer_init_interrupt(int timer, uint8_t pri, uint8_t sub) -{ - if ((timer < TIMERMIN) || (timer > TIMERMAX)) - return; - - /* Disable interrupt and clear interrupt flag. */ - - CLR_REG(TIMERIEC, TIMER_INT_FLAGS(timer, TxIE)); - CLR_REG(TIMERIFS, TIMER_INT_FLAGS(timer, TxIF)); - - /* Set interrupt priorities. */ - - REG(TIMER_IPC_REG(timer)) = (REG(TIMER_IPC_REG(timer)) & - ~(TIMER_IPC_PRI(timer, 7, 3))) | - TIMER_IPC_PRI(timer, pri, sub); - - /* Enable interrupt. */ - - SET_REG(TIMERIEC, TIMER_INT_FLAGS(timer, TxIE)); -} - -/* Enable a timer. */ - -void timer_on(int timer) -{ - if ((timer < TIMERMIN) || (timer > TIMERMAX)) - return; - - SET_REG(TIMER_REG(timer, TxCON), 1 << 15); -} - - - -/* UART configuration. */ - -void uart_init(int uart, uint32_t baudrate) -{ - /* FPB is configured in the devconfig.h file and set in the start.S file. */ - - if ((uart < UARTMIN) || (uart > UARTMAX)) - return; - - /* Disable the UART (ON). */ - - CLR_REG(UART_REG(uart, UxMODE), 1 << 15); - - /* Set the baud rate. For example: - - UxBRG<15:0> = BRG - = (FPB / (16 * baudrate)) - 1 - = (24000000 / (16 * 115200)) - 1 - = 12 - */ - - REG(UART_REG(uart, UxBRG)) = (FPB / (16 * baudrate)) - 1; -} - -/* Configure interrupts caused by the UART. */ - -void uart_init_interrupt(int uart, uint8_t conditions, - uint8_t pri, uint8_t sub) -{ - if ((uart < UARTMIN) || (uart > UARTMAX)) - return; - - /* Disable interrupts and clear interrupt flags. */ - - CLR_REG(UARTIEC, UART_INT_FLAGS(uart, UxTIE | UxRIE | UxEIE)); - CLR_REG(UARTIFS, UART_INT_FLAGS(uart, UxTIF | UxRIF | UxEIF)); - - /* Set priorities: UxIP = pri; UxIS = sub */ - - REG(UART_IPC_REG(uart)) = (REG(UART_IPC_REG(uart)) & - ~UART_IPC_PRI(uart, 7, 3)) | - UART_IPC_PRI(uart, pri, sub); - - /* Enable interrupts. */ - - SET_REG(UARTIEC, UART_INT_FLAGS(uart, conditions)); -} - -/* Enable a UART. */ - -void uart_on(int uart) -{ - if ((uart < UARTMIN) || (uart > UARTMAX)) - return; - - /* Enable receive (URXEN) and transmit (UTXEN). */ - - SET_REG(UART_REG(uart, UxSTA), (1 << 12) | (1 << 10)); - - /* Start UART. */ - - SET_REG(UART_REG(uart, UxMODE), 1 << 15); -} - - - -/* Utility functions. */ - -/* Return encoded interrupt priorities. */ - -static uint8_t PRI(uint8_t pri, uint8_t sub) -{ - return ((pri & 0b111) << 2) | (sub & 0b11); -} - -/* Return the DMA interrupt flags for combining with a register. */ - -int DMA_INT_FLAGS(int channel, uint8_t flags) -{ - return (flags & 0b1) << (DMAINTBASE + (channel - DCHMIN)); -} - -/* Return encoded DMA interrupt priorities for combining with a register. */ - -uint32_t DMA_IPC_PRI(int channel, uint8_t pri, uint8_t sub) -{ - return PRI(pri, sub) << (DCHIPCBASE + (channel - DCHMIN) * DCHIPCSTEP); -} - -/* Return encoded external interrupt priorities for combining with a register. */ - -uint32_t INT_IPC_PRI(int int_num, uint8_t pri, uint8_t sub) -{ - (void) int_num; - return PRI(pri, sub) << INTIPCBASE; -} - -/* Return the external interrupt priorities register. */ - -uint32_t INT_IPC_REG(int int_num) -{ - switch (int_num) - { - case 0: return INT0IPC; - case 1: return INT1IPC; - case 2: return INT2IPC; - case 3: return INT3IPC; - case 4: return INT4IPC; - default: return 0; /* should not occur */ - } -} - -/* Return the external interrupt flags for combining with a register. */ - -int INT_INT_FLAGS(int int_num, uint8_t flags) -{ - return (flags & 0b1) << (INTINTBASE + (int_num - INTMIN) * INTINTSTEP); -} - -/* Return encoded output compare interrupt priorities for combining with a register. */ - -uint32_t OC_IPC_PRI(int unit, uint8_t pri, uint8_t sub) -{ - (void) unit; - return PRI(pri, sub) << OCIPCBASE; -} - -/* Return the output compare interrupt priorities register. */ - -uint32_t OC_IPC_REG(int unit) -{ - switch (unit) - { - case 1: return OC1IPC; - case 2: return OC2IPC; - case 3: return OC3IPC; - case 4: return OC4IPC; - case 5: return OC5IPC; - default: return 0; /* should not occur */ - } -} - -/* Return the output compare interrupt flags for combining with a register. */ - -int OC_INT_FLAGS(int unit, uint8_t flags) -{ - return (flags & 0b1) << (OCINTBASE + (unit - OCMIN) * OCINTSTEP); -} - -/* Return encoded parallel mode interrupt priorities for combining with a register. */ - -uint32_t PM_IPC_PRI(int port, uint8_t pri, uint8_t sub) -{ - (void) port; - return PRI(pri, sub) << PMIPCBASE; -} - -/* Return the parallel mode interrupt priorities register. */ - -uint32_t PM_IPC_REG(int port) -{ - (void) port; - return PMIPC; -} - -/* Return the parallel mode interrupt flags for combining with a register. */ - -int PM_INT_FLAGS(int port, uint8_t flags) -{ - return (flags & 0b11) << (PMINTBASE + (port - PMMIN) * PMINTSTEP); -} - -/* Return encoded timer interrupt priorities for combining with a register. */ - -uint32_t TIMER_IPC_PRI(int timer, uint8_t pri, uint8_t sub) -{ - (void) timer; - return PRI(pri, sub) << TIMERIPCBASE; -} - -/* Return the timer interrupt priorities register. */ - -uint32_t TIMER_IPC_REG(int timer) -{ - switch (timer) - { - case 1: return TIMER1IPC; - case 2: return TIMER2IPC; - case 3: return TIMER3IPC; - case 4: return TIMER4IPC; - case 5: return TIMER5IPC; - default: return 0; /* should not occur */ - } -} - -/* Return the timer interrupt flags for combining with a register. */ - -int TIMER_INT_FLAGS(int timer, uint8_t flags) -{ - return (flags & 0b1) << (TIMERINTBASE + (timer - TIMERMIN) * TIMERINTSTEP); -} - -/* Return encoded UART interrupt priorities for combining with a register. */ - -uint32_t UART_IPC_PRI(int uart, uint8_t pri, uint8_t sub) -{ - return PRI(pri, sub) << (uart == 1 ? UART1IPCBASE : UART2IPCBASE); -} - -/* Return the UART interrupt priorities register. */ - -uint32_t UART_IPC_REG(int uart) -{ - return uart == 1 ? UART1IPC : UART2IPC; -} - -/* Return the UART interrupt flags for combining with a register. */ - -int UART_INT_FLAGS(int uart, uint8_t flags) -{ - return (flags & 0b111) << (UARTINTBASE + (uart - UARTMIN) * UARTINTSTEP); -} diff -r 2500eefe10f9 -r a8a72e893562 init.h --- a/init.h Mon Oct 22 19:12:33 2018 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,164 +0,0 @@ -/* - * PIC32 peripheral configuration and initialisation. - * - * Copyright (C) 2017, 2018 Paul Boddie - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -#ifndef __INIT_H__ -#define __INIT_H__ - -#include "pic32_c.h" - - - -/* Basic initialisation. */ - -void init_memory(void); -void init_pins(void); -void init_outputs(void); - - - -/* Peripheral pin configuration. */ - -void lock_config(void); -void unlock_config(void); - - - -/* Convenience operations. */ - -void interrupts_on(void); - - - -/* DMA configuration. */ - -void init_dma(void); - -void dma_init(int channel, uint8_t pri); - -void dma_init_interrupt(int channel, uint8_t conditions, - uint8_t pri, uint8_t sub); - -void dma_off(int channel); - -void dma_on(int channel); - -void dma_set_auto_enable(int channel, int enable); - -void dma_set_chaining(int channel, enum dma_chain chain); - -void dma_set_enable(int channel, int enable); - -void dma_set_interrupt(int channel, uint8_t int_num, int enable); - -void dma_set_interrupt_enable(int channel, int enable); - -void dma_set_receive_events(int channel, int enable); - -void dma_set_transfer(int channel, - uint32_t source_start_address, uint16_t source_size, - uint32_t destination_start_address, uint16_t destination_size, - uint16_t cell_size); - -int DMA_INT_FLAGS(int channel, uint8_t flags); - -uint32_t DMA_IPC_PRI(int channel, uint8_t pri, uint8_t sub); - - - -/* External interrupt configuration. */ - -void int_init_interrupt(int int_num, uint8_t pri, uint8_t sub); - -int INT_INT_FLAGS(int int_num, uint8_t flags); - -uint32_t INT_IPC_PRI(int int_num, uint8_t pri, uint8_t sub); -uint32_t INT_IPC_REG(int int_num); - - - -/* Output compare configuration. */ - -void oc_init(int unit, uint8_t mode, int timer); - -void oc_init_interrupt(int unit, uint8_t pri, uint8_t sub); - -void oc_on(int unit); - -void oc_set_pulse(int unit, uint32_t start); - -void oc_set_pulse_end(int unit, uint32_t end); - -int OC_INT_FLAGS(int unit, uint8_t flags); - -uint32_t OC_IPC_PRI(int unit, uint8_t pri, uint8_t sub); -uint32_t OC_IPC_REG(int unit); - - - -/* Parallel mode configuration. */ - -void init_pm(void); - -void pm_init(int port, uint8_t mode); - -void pm_init_interrupt(int port, uint8_t pri, uint8_t sub); - -void pm_off(int port); - -void pm_on(int port); - -void pm_set_output(int port, int write_enable, int read_enable); - -int PM_INT_FLAGS(int port, uint8_t flags); - -uint32_t PM_IPC_PRI(int port, uint8_t pri, uint8_t sub); -uint32_t PM_IPC_REG(int port); - - - -/* Timer configuration. */ - -void timer_init(int timer, uint8_t prescale, uint16_t limit); - -void timer_init_interrupt(int timer, uint8_t pri, uint8_t sub); - -void timer_on(int timer); - -int TIMER_INT_FLAGS(int timer, uint8_t flags); - -uint32_t TIMER_IPC_PRI(int timer, uint8_t pri, uint8_t sub); -uint32_t TIMER_IPC_REG(int timer); - - - -/* UART configuration. */ - -void uart_init(int uart, uint32_t baudrate); - -void uart_init_interrupt(int uart, uint8_t conditions, - uint8_t pri, uint8_t sub); - -void uart_on(int uart); - -int UART_INT_FLAGS(int uart, uint8_t flags); - -uint32_t UART_IPC_PRI(int uart, uint8_t pri, uint8_t sub); -uint32_t UART_IPC_REG(int uart); - -#endif /* __INIT_H__ */ diff -r 2500eefe10f9 -r a8a72e893562 lib/cpu.S --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/lib/cpu.S Mon Oct 22 21:44:02 2018 +0200 @@ -0,0 +1,174 @@ +/* + * PIC32 microcontroller interrupt handling code. + * + * Copyright (C) 2017, 2018 Paul Boddie + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#include "mips.h" +#include "pic32.h" +#include "cpu.h" + +.globl enable_interrupts +.globl handle_error_level +.globl init_interrupts +.extern exception_handler +.extern interrupt_handler + +/* Put general routines in the text section. */ + +.text + +/* +Clear the error and exception status flags, making interrupts and exceptions +possible. +*/ + +handle_error_level: + mfc0 $t3, CP0_STATUS + + /* Clear error level and exception level. */ + + li $t4, ~(STATUS_ERL | STATUS_EXL) + and $t3, $t3, $t4 + mtc0 $t3, CP0_STATUS + + jr $ra + nop + +/* Enable interrupts and direct interrupt requests to non-bootloader vectors. */ + +enable_interrupts: + mfc0 $t3, CP0_STATUS + + /* Clear interrupt priority bits. */ + + li $t4, ~STATUS_IRQ + and $t3, $t3, $t4 + + /* Set interrupt priority. */ + + ori $t3, $t3, (CPU_INT_PRIORITY << STATUS_IRQ_SHIFT) + + /* CP0_STATUS &= ~STATUS_BEV (use non-bootloader vectors) */ + + li $t4, ~STATUS_BEV + and $t3, $t3, $t4 + + /* Enable interrupts. */ + + ori $t3, $t3, STATUS_IE + mtc0 $t3, CP0_STATUS + + jr $ra + nop + +/* Initialise the interrupt system parameters. */ + +init_interrupts: + /* Clear debug mode. */ + + mfc0 $t3, CP0_DEBUG + li $t4, ~DEBUG_DM + and $t3, $t3, $t4 + mtc0 $t3, CP0_DEBUG + + /* Update the exception base. */ + + mfc0 $t3, CP0_STATUS + li $t4, STATUS_BEV /* BEV = 1 or EBASE cannot be set */ + or $t3, $t3, $t4 + mtc0 $t3, CP0_STATUS + + la $t3, ebase + mtc0 $t3, CP0_EBASE + + /* Set vector spacing. */ + + li $t3, 0x20 /* Must be non-zero or the CPU gets upset */ + mtc0 $t3, CP0_INTCTL + + li $t3, CAUSE_IV /* IV = 1 (use EBASE+0x200 for interrupts) */ + mtc0 $t3, CP0_CAUSE + + jr $ra + nop + + + +/* Exception servicing, positioned at EBASE at the start of program memory. */ + +.section .vectors, "a" + +/* TLB error servicing. */ + +ebase: +tlb_handler: + j exception_handler + nop + + + +/* General exception servicing. */ + +.org 0x180 + +exc_handler: + j exception_handler + nop + + + +/* Interrupt servicing. */ + +.org 0x200 +.set noat + +#define IRQ_STACK_LIMIT (KSEG0_BASE + IRQ_STACK_SIZE) +#define IRQ_STACK_TOP (IRQ_STACK_LIMIT - 32 * 4) + +int_handler: + + /* Store affected registers from IRQ_STACK_LIMIT - 4 downwards. */ + + lui $k0, %hi(IRQ_STACK_LIMIT) + ori $k0, $k0, %lo(IRQ_STACK_LIMIT) + + .irp reg, \ + 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15 \ + 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, \ + 28, 29, 30, 31 + sw $\reg, -(\reg * 4)($k0) + .endr + + /* Switch to the IRQ stack. */ + + lui $sp, %hi(IRQ_STACK_TOP) + ori $sp, $sp, %lo(IRQ_STACK_TOP) + + jal interrupt_handler + nop + + /* Restore affected registers. */ + + .irp reg, \ + 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15 \ + 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, \ + 28, 29, 30, 31 + lw $\reg, -(\reg * 4)($k0) + .endr + + eret + nop diff -r 2500eefe10f9 -r a8a72e893562 lib/debug.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/lib/debug.c Mon Oct 22 21:44:02 2018 +0200 @@ -0,0 +1,108 @@ +/* + * Some simple debugging functions. + * + * Copyright (C) 2018 Paul Boddie + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#include "pic32_c.h" +#include "debug.h" + +/* Register output functions using UART1. */ + +void rbits(uint32_t reg) +{ + bits(REG(reg), 4); +} + +void rhex(uint32_t reg) +{ + hex(REG(reg), 4); +} + +/* Value output functions using UART1. */ + +void bits(uint32_t val, int bytes) +{ + uint32_t mask; + + for (mask = (1 << 31); mask; mask >>= 1) + if (val & mask) + uart_write('1'); + else + uart_write('0'); +} + +void hex(uint32_t val, int bytes) +{ + uint32_t mask; + uint8_t digit, shift, start = bytes * 8 - 4; + + for (mask = (0b1111 << start), shift = start; mask; mask >>= 4, shift -= 4) + { + digit = (val & mask) >> shift; + if (digit > 9) + uart_write('A' + digit - 10); + else + uart_write('0' + digit); + } +} + + + +/* General input/output functions. */ + +int uart_can_read(int uart) +{ + return REG(UART_REG(uart, UxSTA)) & 1; +} + +char uart_read_char(int uart) +{ + return (char) REG(UART_REG(uart, UxRXREG)); +} + +int uart_can_write(int uart) +{ + return !(REG(UART_REG(uart, UxSTA)) & (1 << 9)); /* UTXBF (buffer full) */ +} + +void uart_write_char(int uart, char c) +{ + while (!uart_can_write(uart)); /* busy loop */ + + REG(UART_REG(uart, UxTXREG)) = c; +} + + + +/* Functions using UART1. */ + +void uart_write(char c) +{ + uart_write_char(1, c); +} + +void uart_write_nl(void) +{ + uart_write('\r'); + uart_write('\n'); +} + +void uart_write_string(const char *s) +{ + while (*s) + uart_write(*s++); +} diff -r 2500eefe10f9 -r a8a72e893562 lib/init.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/lib/init.c Mon Oct 22 21:44:02 2018 +0200 @@ -0,0 +1,715 @@ +/* + * PIC32 peripheral configuration and initialisation. + * + * Copyright (C) 2017, 2018 Paul Boddie + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#include "cpu.h" +#include "pic32_c.h" +#include "init.h" + +/* Application-specific configuration. */ + +#include "devconfig.h" + + + +/* Basic memory and pin initialisation. */ + +void init_memory(void) +{ + /* + Configure RAM. + See: http://microchipdeveloper.com/32bit:mx-arch-exceptions-processor-initialization + */ + + uint32_t config = REG(BMXCON); + + /* Set zero wait states for address setup. */ + + config &= ~(1 << 6); /* BMXCON<6> = BMXWSDRM = 0 */ + + /* Set bus arbitration mode. */ + + config &= ~0b111; + config |= 0b010; /* BMXCON<2:0> = BMXARB<2:0> = 2 */ + + REG(BMXCON) = config; +} + +void init_pins(void) +{ + /* DEVCFG0<2> also needs setting to 0 before the program is run. */ + + CLR_REG(CFGCON, 1 << 3); /* CFGCON<3> = JTAGEN = 0 */ +} + +void init_outputs(void) +{ + /* Remove analogue features from pins. */ + + REG(ANSELA) = 0; + REG(ANSELB) = 0; + + /* Set pins as outputs. */ + + REG(TRISA) = 0; + REG(TRISB) = 0; + + /* Clear outputs. */ + + REG(PORTA) = 0; + REG(PORTB) = 0; +} + + + +/* Peripheral pin configuration. */ + +void lock_config(void) +{ + SET_REG(CFGCON, 1 << 13); /* IOLOCK = 1 */ + + /* Lock the configuration again. */ + + REG(SYSKEY) = 0x33333333; +} + +void unlock_config(void) +{ + /* Unlock the configuration register bits. */ + + REG(SYSKEY) = 0; + REG(SYSKEY) = 0xAA996655; + REG(SYSKEY) = 0x556699AA; + + CLR_REG(CFGCON, 1 << 13); /* IOLOCK = 0 */ +} + + + +/* Convenience operations. */ + +void interrupts_on(void) +{ + init_interrupts(); + enable_interrupts(); + handle_error_level(); +} + + + +/* DMA configuration. */ + +void init_dma(void) +{ + /* Disable DMA interrupts (DMAxIE). */ + + CLR_REG(DMAIEC, 0b1111 << DMAINTBASE); + + /* Clear DMA interrupt flags (DMAxIF). */ + + CLR_REG(DMAIFS, 0b1111 << DMAINTBASE); + + /* Enable DMA. */ + + SET_REG(DMACON, 1 << 15); +} + +/* Initialise the given channel. */ + +void dma_init(int channel, uint8_t pri) +{ + if ((channel < DCHMIN) || (channel > DCHMAX)) + return; + + /* Initialise a channel. */ + + REG(DMA_REG(channel, DCHxCON)) = pri & 0b11; + REG(DMA_REG(channel, DCHxECON)) = 0; + REG(DMA_REG(channel, DCHxINT)) = 0; +} + +/* Set the channel repeated enable mode, enabling it again when a block transfer + completes. The documentation describes this as auto-enable. */ + +void dma_set_auto_enable(int channel, int enable) +{ + (enable ? SET_REG : CLR_REG)(DMA_REG(channel, DCHxCON), 1 << 4); +} + +/* Set the channel chaining mode. */ + +void dma_set_chaining(int channel, enum dma_chain chain) +{ + (chain != dma_chain_none ? + SET_REG : CLR_REG)(DMA_REG(channel, DCHxCON), 1 << 5); + + (chain == dma_chain_next ? + SET_REG : CLR_REG)(DMA_REG(channel, DCHxCON), 1 << 8); +} + +/* Configure a channel's initiation interrupt. */ + +void dma_set_interrupt(int channel, uint8_t int_num, int enable) +{ + if ((channel < DCHMIN) || (channel > DCHMAX)) + return; + + /* Allow an interrupt to trigger the transfer. */ + + REG(DMA_REG(channel, DCHxECON)) = (int_num << 8) | + ((enable ? 1 : 0) << 4); +} + +/* Configure only the channel's initiation interrupt status. */ + +void dma_set_interrupt_enable(int channel, int enable) +{ + if ((channel < DCHMIN) || (channel > DCHMAX)) + return; + + (enable ? SET_REG : CLR_REG)(DMA_REG(channel, DCHxECON), 1 << 4); +} + +/* Permit the channel to register events while disabled or suspended. A + suspended channel is one that is enabled but where the DMA peripheral + has been suspended. */ + +void dma_set_receive_events(int channel, int enable) +{ + (enable ? SET_REG : CLR_REG)(DMA_REG(channel, DCHxCON), 1 << 6); +} + +/* Set a channel's transfer parameters. */ + +void dma_set_transfer(int channel, + uint32_t source_start_address, uint16_t source_size, + uint32_t destination_start_address, uint16_t destination_size, + uint16_t cell_size) +{ + if ((channel < DCHMIN) || (channel > DCHMAX)) + return; + + REG(DMA_REG(channel, DCHxSSIZ)) = source_size; + REG(DMA_REG(channel, DCHxSSA)) = source_start_address; + REG(DMA_REG(channel, DCHxDSIZ)) = destination_size; + REG(DMA_REG(channel, DCHxDSA)) = destination_start_address; + REG(DMA_REG(channel, DCHxCSIZ)) = cell_size; +} + +/* Configure interrupts caused by the channel. */ + +void dma_init_interrupt(int channel, uint8_t conditions, + uint8_t pri, uint8_t sub) +{ + if ((channel < DCHMIN) || (channel > DCHMAX)) + return; + + /* Disable channel interrupt and clear interrupt flag. */ + + CLR_REG(DMAIEC, DMA_INT_FLAGS(channel, 1)); + CLR_REG(DMAIFS, DMA_INT_FLAGS(channel, 1)); + + /* Produce an interrupt for the provided conditions. */ + + REG(DMA_REG(channel, DCHxINT)) = conditions << 16; + + /* Set interrupt priorities. */ + + REG(DMAIPC) = (REG(DMAIPC) & + ~(DMA_IPC_PRI(channel, 7, 3))) | + DMA_IPC_PRI(channel, pri, sub); + + /* Enable interrupt. */ + + SET_REG(DMAIEC, DMA_INT_FLAGS(channel, 1)); +} + +/* Enable or disable the channel. */ + +void dma_set_enable(int channel, int enable) +{ + if ((channel < DCHMIN) || (channel > DCHMAX)) + return; + + (enable ? SET_REG : CLR_REG)(DMA_REG(channel, DCHxCON), 1 << 7); +} + +/* Disable a DMA channel. */ + +void dma_off(int channel) +{ + dma_set_enable(channel, 0); +} + +/* Enable a DMA channel. */ + +void dma_on(int channel) +{ + dma_set_enable(channel, 1); +} + + + +/* External interrupt initialisation. */ + +void int_init_interrupt(int int_num, uint8_t pri, uint8_t sub) +{ + if ((int_num < INTMIN) || (int_num > INTMAX)) + return; + + /* Disable interrupt and clear interrupt flag. */ + + CLR_REG(INTIEC, INT_INT_FLAGS(int_num, INTxIE)); + CLR_REG(INTIFS, INT_INT_FLAGS(int_num, INTxIF)); + + /* Set interrupt priorities. */ + + REG(INT_IPC_REG(int_num)) = (REG(INT_IPC_REG(int_num)) & + ~(INT_IPC_PRI(int_num, 7, 3))) | + INT_IPC_PRI(int_num, pri, sub); + + /* Enable interrupt. */ + + SET_REG(INTIEC, INT_INT_FLAGS(int_num, INTxIE)); +} + + + +/* Output compare configuration. */ + +void oc_init(int unit, uint8_t mode, int timer) +{ + if ((unit < OCMIN) || (unit > OCMAX)) + return; + + REG(OC_REG(unit, OCxCON)) = (timer == 3 ? (1 << 3) : 0) | (mode & 0b111); +} + +/* Set the start value for the pulse. */ + +void oc_set_pulse(int unit, uint32_t start) +{ + if ((unit < OCMIN) || (unit > OCMAX)) + return; + + REG(OC_REG(unit, OCxR)) = start; +} + +/* Set the end value for the pulse. */ + +void oc_set_pulse_end(int unit, uint32_t end) +{ + if ((unit < OCMIN) || (unit > OCMAX)) + return; + + REG(OC_REG(unit, OCxRS)) = end; +} + +/* Configure interrupts caused by the unit. */ + +void oc_init_interrupt(int unit, uint8_t pri, uint8_t sub) +{ + if ((unit < OCMIN) || (unit > OCMAX)) + return; + + /* Disable interrupt and clear interrupt flag. */ + + CLR_REG(OCIEC, OC_INT_FLAGS(unit, OCxIE)); + CLR_REG(OCIFS, OC_INT_FLAGS(unit, OCxIF)); + + /* Set interrupt priorities. */ + + REG(OC_IPC_REG(unit)) = (REG(OC_IPC_REG(unit)) & + ~(OC_IPC_PRI(unit, 7, 3))) | + OC_IPC_PRI(unit, pri, sub); + + /* Enable interrupt. */ + + SET_REG(OCIEC, OC_INT_FLAGS(unit, OCxIE)); +} + +/* Enable a unit. */ + +void oc_on(int unit) +{ + if ((unit < OCMIN) || (unit > OCMAX)) + return; + + SET_REG(OC_REG(unit, OCxCON), 1 << 15); +} + + + +/* Parallel mode configuration. */ + +void init_pm(void) +{ + int i; + + /* Disable PM interrupts (PMxIE). */ + + CLR_REG(PMIEC, 0b11 << PMINTBASE); + + /* Clear PM interrupt flags (PMxIF). */ + + CLR_REG(PMIFS, 0b11 << PMINTBASE); + + /* Disable PM for configuration. */ + + for (i = PMMIN; i <= PMMAX; i++) + REG(PM_REG(i, PMxCON)) = 0; +} + +/* Configure the parallel mode. */ + +void pm_init(int port, uint8_t mode) +{ + if ((port < PMMIN) || (port > PMMAX)) + return; + + REG(PM_REG(port, PMxMODE)) = (mode & 0b11) << 8; + REG(PM_REG(port, PMxAEN)) = 0; + REG(PM_REG(port, PMxADDR)) = 0; +} + +/* Configure output signals. */ + +void pm_set_output(int port, int write_enable, int read_enable) +{ + if ((port < PMMIN) || (port > PMMAX)) + return; + + REG(PM_REG(port, PMxCON)) = (write_enable ? (1 << 9) : 0) | + (read_enable ? (1 << 8) : 0) | + (1 << 1); /* WRSP: PMENB active high */ +} + +/* Configure interrupts caused by parallel mode. */ + +void pm_init_interrupt(int port, uint8_t pri, uint8_t sub) +{ + if ((port < PMMIN) || (port > PMMAX)) + return; + + /* Disable interrupt and clear interrupt flag. */ + + CLR_REG(PMIEC, PM_INT_FLAGS(port, PMxIE)); + CLR_REG(PMIFS, PM_INT_FLAGS(port, PMxIF)); + + /* Set interrupt priorities. */ + + REG(PM_IPC_REG(port)) = (REG(PM_IPC_REG(port)) & + ~(PM_IPC_PRI(port, 7, 3))) | + PM_IPC_PRI(port, pri, sub); + + /* Enable interrupt. */ + + SET_REG(PMIEC, PM_INT_FLAGS(port, PMxIE)); +} + +/* Enable parallel mode. */ + +void pm_on(int port) +{ + if ((port < PMMIN) || (port > PMMAX)) + return; + + SET_REG(PM_REG(port, PMxCON), 1 << 15); +} + +/* Disable parallel mode. */ + +void pm_off(int port) +{ + if ((port < PMMIN) || (port > PMMAX)) + return; + + CLR_REG(PM_REG(port, PMxCON), 1 << 15); +} + + + + +/* Timer configuration. */ + +void timer_init(int timer, uint8_t prescale, uint16_t limit) +{ + /* NOTE: Should convert from the real prescale value. */ + + REG(TIMER_REG(timer, TxCON)) = (prescale & 0b111) << 4; + REG(TIMER_REG(timer, TMRx)) = 0; + REG(TIMER_REG(timer, PRx)) = limit; +} + +/* Configure interrupts caused by the timer. */ + +void timer_init_interrupt(int timer, uint8_t pri, uint8_t sub) +{ + if ((timer < TIMERMIN) || (timer > TIMERMAX)) + return; + + /* Disable interrupt and clear interrupt flag. */ + + CLR_REG(TIMERIEC, TIMER_INT_FLAGS(timer, TxIE)); + CLR_REG(TIMERIFS, TIMER_INT_FLAGS(timer, TxIF)); + + /* Set interrupt priorities. */ + + REG(TIMER_IPC_REG(timer)) = (REG(TIMER_IPC_REG(timer)) & + ~(TIMER_IPC_PRI(timer, 7, 3))) | + TIMER_IPC_PRI(timer, pri, sub); + + /* Enable interrupt. */ + + SET_REG(TIMERIEC, TIMER_INT_FLAGS(timer, TxIE)); +} + +/* Enable a timer. */ + +void timer_on(int timer) +{ + if ((timer < TIMERMIN) || (timer > TIMERMAX)) + return; + + SET_REG(TIMER_REG(timer, TxCON), 1 << 15); +} + + + +/* UART configuration. */ + +void uart_init(int uart, uint32_t baudrate) +{ + /* FPB is configured in the devconfig.h file and set in the start.S file. */ + + if ((uart < UARTMIN) || (uart > UARTMAX)) + return; + + /* Disable the UART (ON). */ + + CLR_REG(UART_REG(uart, UxMODE), 1 << 15); + + /* Set the baud rate. For example: + + UxBRG<15:0> = BRG + = (FPB / (16 * baudrate)) - 1 + = (24000000 / (16 * 115200)) - 1 + = 12 + */ + + REG(UART_REG(uart, UxBRG)) = (FPB / (16 * baudrate)) - 1; +} + +/* Configure interrupts caused by the UART. */ + +void uart_init_interrupt(int uart, uint8_t conditions, + uint8_t pri, uint8_t sub) +{ + if ((uart < UARTMIN) || (uart > UARTMAX)) + return; + + /* Disable interrupts and clear interrupt flags. */ + + CLR_REG(UARTIEC, UART_INT_FLAGS(uart, UxTIE | UxRIE | UxEIE)); + CLR_REG(UARTIFS, UART_INT_FLAGS(uart, UxTIF | UxRIF | UxEIF)); + + /* Set priorities: UxIP = pri; UxIS = sub */ + + REG(UART_IPC_REG(uart)) = (REG(UART_IPC_REG(uart)) & + ~UART_IPC_PRI(uart, 7, 3)) | + UART_IPC_PRI(uart, pri, sub); + + /* Enable interrupts. */ + + SET_REG(UARTIEC, UART_INT_FLAGS(uart, conditions)); +} + +/* Enable a UART. */ + +void uart_on(int uart) +{ + if ((uart < UARTMIN) || (uart > UARTMAX)) + return; + + /* Enable receive (URXEN) and transmit (UTXEN). */ + + SET_REG(UART_REG(uart, UxSTA), (1 << 12) | (1 << 10)); + + /* Start UART. */ + + SET_REG(UART_REG(uart, UxMODE), 1 << 15); +} + + + +/* Utility functions. */ + +/* Return encoded interrupt priorities. */ + +static uint8_t PRI(uint8_t pri, uint8_t sub) +{ + return ((pri & 0b111) << 2) | (sub & 0b11); +} + +/* Return the DMA interrupt flags for combining with a register. */ + +int DMA_INT_FLAGS(int channel, uint8_t flags) +{ + return (flags & 0b1) << (DMAINTBASE + (channel - DCHMIN)); +} + +/* Return encoded DMA interrupt priorities for combining with a register. */ + +uint32_t DMA_IPC_PRI(int channel, uint8_t pri, uint8_t sub) +{ + return PRI(pri, sub) << (DCHIPCBASE + (channel - DCHMIN) * DCHIPCSTEP); +} + +/* Return encoded external interrupt priorities for combining with a register. */ + +uint32_t INT_IPC_PRI(int int_num, uint8_t pri, uint8_t sub) +{ + (void) int_num; + return PRI(pri, sub) << INTIPCBASE; +} + +/* Return the external interrupt priorities register. */ + +uint32_t INT_IPC_REG(int int_num) +{ + switch (int_num) + { + case 0: return INT0IPC; + case 1: return INT1IPC; + case 2: return INT2IPC; + case 3: return INT3IPC; + case 4: return INT4IPC; + default: return 0; /* should not occur */ + } +} + +/* Return the external interrupt flags for combining with a register. */ + +int INT_INT_FLAGS(int int_num, uint8_t flags) +{ + return (flags & 0b1) << (INTINTBASE + (int_num - INTMIN) * INTINTSTEP); +} + +/* Return encoded output compare interrupt priorities for combining with a register. */ + +uint32_t OC_IPC_PRI(int unit, uint8_t pri, uint8_t sub) +{ + (void) unit; + return PRI(pri, sub) << OCIPCBASE; +} + +/* Return the output compare interrupt priorities register. */ + +uint32_t OC_IPC_REG(int unit) +{ + switch (unit) + { + case 1: return OC1IPC; + case 2: return OC2IPC; + case 3: return OC3IPC; + case 4: return OC4IPC; + case 5: return OC5IPC; + default: return 0; /* should not occur */ + } +} + +/* Return the output compare interrupt flags for combining with a register. */ + +int OC_INT_FLAGS(int unit, uint8_t flags) +{ + return (flags & 0b1) << (OCINTBASE + (unit - OCMIN) * OCINTSTEP); +} + +/* Return encoded parallel mode interrupt priorities for combining with a register. */ + +uint32_t PM_IPC_PRI(int port, uint8_t pri, uint8_t sub) +{ + (void) port; + return PRI(pri, sub) << PMIPCBASE; +} + +/* Return the parallel mode interrupt priorities register. */ + +uint32_t PM_IPC_REG(int port) +{ + (void) port; + return PMIPC; +} + +/* Return the parallel mode interrupt flags for combining with a register. */ + +int PM_INT_FLAGS(int port, uint8_t flags) +{ + return (flags & 0b11) << (PMINTBASE + (port - PMMIN) * PMINTSTEP); +} + +/* Return encoded timer interrupt priorities for combining with a register. */ + +uint32_t TIMER_IPC_PRI(int timer, uint8_t pri, uint8_t sub) +{ + (void) timer; + return PRI(pri, sub) << TIMERIPCBASE; +} + +/* Return the timer interrupt priorities register. */ + +uint32_t TIMER_IPC_REG(int timer) +{ + switch (timer) + { + case 1: return TIMER1IPC; + case 2: return TIMER2IPC; + case 3: return TIMER3IPC; + case 4: return TIMER4IPC; + case 5: return TIMER5IPC; + default: return 0; /* should not occur */ + } +} + +/* Return the timer interrupt flags for combining with a register. */ + +int TIMER_INT_FLAGS(int timer, uint8_t flags) +{ + return (flags & 0b1) << (TIMERINTBASE + (timer - TIMERMIN) * TIMERINTSTEP); +} + +/* Return encoded UART interrupt priorities for combining with a register. */ + +uint32_t UART_IPC_PRI(int uart, uint8_t pri, uint8_t sub) +{ + return PRI(pri, sub) << (uart == 1 ? UART1IPCBASE : UART2IPCBASE); +} + +/* Return the UART interrupt priorities register. */ + +uint32_t UART_IPC_REG(int uart) +{ + return uart == 1 ? UART1IPC : UART2IPC; +} + +/* Return the UART interrupt flags for combining with a register. */ + +int UART_INT_FLAGS(int uart, uint8_t flags) +{ + return (flags & 0b111) << (UARTINTBASE + (uart - UARTMIN) * UARTINTSTEP); +} diff -r 2500eefe10f9 -r a8a72e893562 lib/payload.ld --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/lib/payload.ld Mon Oct 22 21:44:02 2018 +0200 @@ -0,0 +1,70 @@ +OUTPUT_ARCH(mips) +ENTRY(_start) + +IRQ_STACK_SIZE = 256; + +/* See... + * FIGURE 4-5: MEMORY MAP ON RESET FOR PIC32MX170/270 DEVICES (64 KB RAM, 256 KB FLASH) + * PIC32MX1XX/2XX 28/36/44-pin Family Data Sheet + */ + +MEMORY +{ + kseg0_boot_mem (rx) : ORIGIN = 0x9FC00000, LENGTH = 0xBF0 + kseg0_program_mem (rx) : ORIGIN = 0x9D000000, LENGTH = 0x40000 + kseg0_data_mem (w!x) : ORIGIN = 0x80000000, LENGTH = 0x10000 + physical_boot_mem (rx) : ORIGIN = 0x1FC00000, LENGTH = 0xBF0 + physical_program_mem (rx) : ORIGIN = 0x1D000000, LENGTH = 0x40000 + physical_data_mem (w!x) : ORIGIN = 0x00000000, LENGTH = 0x10000 + sfrs : ORIGIN = 0xBF800000, LENGTH = 0x100000 + configsfrs : ORIGIN = 0xBFC00BF0, LENGTH = 0x10 + config3 : ORIGIN = 0xBFC00BF0, LENGTH = 0x4 + config2 : ORIGIN = 0xBFC00BF4, LENGTH = 0x4 + config1 : ORIGIN = 0xBFC00BF8, LENGTH = 0x4 + config0 : ORIGIN = 0xBFC00BFC, LENGTH = 0x4 + physical_config3 : ORIGIN = 0x3FC00BF0, LENGTH = 0x4 + physical_config2 : ORIGIN = 0x3FC00BF4, LENGTH = 0x4 + physical_config1 : ORIGIN = 0x3FC00BF8, LENGTH = 0x4 + physical_config0 : ORIGIN = 0x3FC00BFC, LENGTH = 0x4 +} + +SECTIONS +{ + /* Boot program. */ + + .boot : { *(.boot*) } > kseg0_boot_mem AT > physical_boot_mem + + /* Exception/interrupt vectors and general program code. */ + + .vectors : { *(.vectors*) } > kseg0_program_mem AT > physical_program_mem + .text : { *(.text*) } > kseg0_program_mem AT > physical_program_mem + + /* Reserve space at the bottom of RAM for the IRQ stack. */ + + .irqstack : { + . += IRQ_STACK_SIZE; + } > kseg0_data_mem AT > physical_data_mem + + /* Add other data after the IRQ stack. */ + + .bss : { *(.bss*) } > kseg0_data_mem AT > physical_data_mem + .data : { *(.data*) } > kseg0_data_mem AT > physical_data_mem + + /* Store constant data in program memory. */ + + .rodata : { *(.rodata*) } > kseg0_program_mem AT > physical_program_mem + .got : { + _gp = ALIGN(16); + *(.got*) + } > kseg0_program_mem AT > physical_program_mem + + /* Device configuration registers to be flashed. */ + + .devcfg0 : { *(.devcfg0) } > config0 AT > physical_config0 + .devcfg1 : { *(.devcfg1) } > config1 AT > physical_config1 + .devcfg2 : { *(.devcfg2) } > config2 AT > physical_config2 + + /* Discard things that might overwrite useful data. */ + + /DISCARD/ : { *(.reginfo) *(.MIPS.abiflags) *(.pdr) *(.gnu.attributes) *(.comment) } +} diff -r 2500eefe10f9 -r a8a72e893562 lib/start.S --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/lib/start.S Mon Oct 22 21:44:02 2018 +0200 @@ -0,0 +1,83 @@ +/* + * PIC32 microcontroller initialisation code. + * + * Copyright (C) 2017, 2018 Paul Boddie + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#include "mips.h" +#include "pic32.h" + +/* Application-specific configuration. */ + +#include "devconfig.h" + +/* Disable JTAG functionality on pins. */ + +.section .devcfg0, "a" +.word 0xfffffffb /* DEVCFG0<2> = JTAGEN = 0 */ + +/* Select oscillator, pin usage, watchdog timer and peripheral clock divider. */ + +.section .devcfg1, "a" +.word (DEVCFG1_UNUSED | DEVCFG1_CONFIG) + +/* Set clock dividers and multiplier. */ + +.section .devcfg2, "a" +.word (DEVCFG2_UNUSED | DEVCFG2_CONFIG) + +/* The start routine is placed at the boot location. */ + +.section .boot, "a" + +.globl _start +.extern main + +_start: + /* Enable caching. */ + + mfc0 $v1, CP0_CONFIG + li $t8, ~CONFIG_K0 + and $v1, $v1, $t8 + ori $v1, $v1, CONFIG_K0_CACHABLE_NONCOHERENT + mtc0 $v1, CP0_CONFIG + nop + + /* Get the RAM size. */ + + la $v1, BMXDRMSZ + lw $t0, 0($v1) + + /* Initialise the stack pointer. */ + + li $v1, KSEG0_BASE + addu $sp, $t0, $v1 /* sp = KSEG0_BASE + RAM size */ + + /* Initialise the globals pointer. */ + + lui $gp, %hi(_GLOBAL_OFFSET_TABLE_) + ori $gp, $gp, %lo(_GLOBAL_OFFSET_TABLE_) + + /* + Jump to the main program. Since the boot code is separate from the + other code, the address cannot be obtained via the GOT. + ("relocation truncated to fit: R_MIPS_PC16 against `main'") + */ + + lui $t9, %hi(main) + ori $t9, $t9, %lo(main) + jr $t9 + nop diff -r 2500eefe10f9 -r a8a72e893562 mips.h --- a/mips.h Mon Oct 22 19:12:33 2018 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,63 +0,0 @@ -#ifndef __MIPS_H__ -#define __MIPS_H__ - -#define KSEG0_BASE 0x80000000 -#define KSEG1_BASE 0xA0000000 - -#define CP0_INDEX $0 -#define CP0_ENTRYLO0 $2 -#define CP0_ENTRYLO1 $3 -#define CP0_CONTEXT $4 -#define CP0_PAGEMASK $5 -#define CP0_WIRED $6 -#define CP0_BADVADDR $8 -#define CP0_COUNT $9 -#define CP0_ENTRYHI $10 -#define CP0_COMPARE $11 -#define CP0_STATUS $12 -#define CP0_INTCTL $12, 1 -#define CP0_CAUSE $13 -#define CP0_EPC $14 -#define CP0_EBASE $15, 1 -#define CP0_CONFIG $16 -#define CP0_WATCHLO $18 -#define CP0_DEBUG $23 -#define CP0_TAGLO $28 -#define CP0_TAGHI $29 -#define CP0_ERROREPC $30, 0 - -#define STATUS_CP0 0x10000000 -#define STATUS_BEV 0x00400000 - -#define STATUS_IRQ 0x0000fc00 -#define STATUS_IRQ_SHIFT 10 - -#define STATUS_UM 0x00000010 -#define STATUS_ERL 0x00000004 -#define STATUS_EXL 0x00000002 -#define STATUS_IE 0x00000001 - -#define CAUSE_IV 0x00800000 - -#define EBASE_MASK 0x3ffff000 - -#define INTCTL_MASK 0x000003e0 - -#define DEBUG_DM 0x40000000 - -#define TLB_CACHED 0x00000018 -#define TLB_UNCACHED 0x00000010 -#define TLB_DIRTY 0x00000004 -#define TLB_VALID 0x00000002 -#define TLB_GLOBAL 0x00000001 - -#define TLB_READ (TLB_CACHED | TLB_VALID) -#define TLB_WRITE (TLB_CACHED | TLB_DIRTY | TLB_VALID) -#define TLB_ALL_READ (TLB_CACHED | TLB_VALID | TLB_GLOBAL) -#define TLB_ALL_WRITE (TLB_CACHED | TLB_DIRTY | TLB_VALID | TLB_GLOBAL) - -#define CONFIG_K0 0x00000007 -#define CONFIG_K0_UNCACHED 2 -#define CONFIG_K0_CACHABLE_NONCOHERENT 3 - -#endif /* __MIPS_H__ */ diff -r 2500eefe10f9 -r a8a72e893562 mk/common.mk --- a/mk/common.mk Mon Oct 22 19:12:33 2018 +0200 +++ b/mk/common.mk Mon Oct 22 21:44:02 2018 +0200 @@ -23,6 +23,11 @@ OBJCOPY=$(ARCH)-objcopy OBJDUMP=$(ARCH)-objdump +# These paths are relative to each example directory. + +INCDIR = ../../include +LIBDIR = ../../lib + # NOTE: -O2 is actually needed to prevent memcpy references, whereas probably # NOTE: one of the -f{freestanding, no-hosted, no-builtin} options should work. # NOTE: See: https://gcc.gnu.org/bugzilla/show_bug.cgi?id=56888 @@ -31,21 +36,21 @@ -fno-unit-at-a-time -fno-zero-initialized-in-bss \ -ffreestanding -fno-hosted -fno-builtin \ -march=mips32 \ - -I. -I../.. + -I. \ + -I$(INCDIR) LDFLAGS = -nostdlib -EL # Ordering of objects is important and cannot be left to replacement rules. -# These are relative to each example directory. -START_SRC = ../../start.S -START_OBJ = ../../start.o +START_SRC = $(LIBDIR)/start.S +START_OBJ = $(LIBDIR)/start.o # Application-specific files appear after the above but before those below in # the application Makefiles. -COMMON_SRC = ../../init.c ../../debug.c ../../cpu.S -COMMON_OBJ = ../../init.o ../../debug.o ../../cpu.o +COMMON_SRC = $(LIBDIR)/init.c $(LIBDIR)/debug.c $(LIBDIR)/cpu.S +COMMON_OBJ = $(LIBDIR)/init.o $(LIBDIR)/debug.o $(LIBDIR)/cpu.o # Common linker script. -SCRIPT = ../../payload.ld +SCRIPT = $(LIBDIR)/payload.ld diff -r 2500eefe10f9 -r a8a72e893562 payload.ld --- a/payload.ld Mon Oct 22 19:12:33 2018 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,70 +0,0 @@ -OUTPUT_ARCH(mips) -ENTRY(_start) - -IRQ_STACK_SIZE = 256; - -/* See... - * FIGURE 4-5: MEMORY MAP ON RESET FOR PIC32MX170/270 DEVICES (64 KB RAM, 256 KB FLASH) - * PIC32MX1XX/2XX 28/36/44-pin Family Data Sheet - */ - -MEMORY -{ - kseg0_boot_mem (rx) : ORIGIN = 0x9FC00000, LENGTH = 0xBF0 - kseg0_program_mem (rx) : ORIGIN = 0x9D000000, LENGTH = 0x40000 - kseg0_data_mem (w!x) : ORIGIN = 0x80000000, LENGTH = 0x10000 - physical_boot_mem (rx) : ORIGIN = 0x1FC00000, LENGTH = 0xBF0 - physical_program_mem (rx) : ORIGIN = 0x1D000000, LENGTH = 0x40000 - physical_data_mem (w!x) : ORIGIN = 0x00000000, LENGTH = 0x10000 - sfrs : ORIGIN = 0xBF800000, LENGTH = 0x100000 - configsfrs : ORIGIN = 0xBFC00BF0, LENGTH = 0x10 - config3 : ORIGIN = 0xBFC00BF0, LENGTH = 0x4 - config2 : ORIGIN = 0xBFC00BF4, LENGTH = 0x4 - config1 : ORIGIN = 0xBFC00BF8, LENGTH = 0x4 - config0 : ORIGIN = 0xBFC00BFC, LENGTH = 0x4 - physical_config3 : ORIGIN = 0x3FC00BF0, LENGTH = 0x4 - physical_config2 : ORIGIN = 0x3FC00BF4, LENGTH = 0x4 - physical_config1 : ORIGIN = 0x3FC00BF8, LENGTH = 0x4 - physical_config0 : ORIGIN = 0x3FC00BFC, LENGTH = 0x4 -} - -SECTIONS -{ - /* Boot program. */ - - .boot : { *(.boot*) } > kseg0_boot_mem AT > physical_boot_mem - - /* Exception/interrupt vectors and general program code. */ - - .vectors : { *(.vectors*) } > kseg0_program_mem AT > physical_program_mem - .text : { *(.text*) } > kseg0_program_mem AT > physical_program_mem - - /* Reserve space at the bottom of RAM for the IRQ stack. */ - - .irqstack : { - . += IRQ_STACK_SIZE; - } > kseg0_data_mem AT > physical_data_mem - - /* Add other data after the IRQ stack. */ - - .bss : { *(.bss*) } > kseg0_data_mem AT > physical_data_mem - .data : { *(.data*) } > kseg0_data_mem AT > physical_data_mem - - /* Store constant data in program memory. */ - - .rodata : { *(.rodata*) } > kseg0_program_mem AT > physical_program_mem - .got : { - _gp = ALIGN(16); - *(.got*) - } > kseg0_program_mem AT > physical_program_mem - - /* Device configuration registers to be flashed. */ - - .devcfg0 : { *(.devcfg0) } > config0 AT > physical_config0 - .devcfg1 : { *(.devcfg1) } > config1 AT > physical_config1 - .devcfg2 : { *(.devcfg2) } > config2 AT > physical_config2 - - /* Discard things that might overwrite useful data. */ - - /DISCARD/ : { *(.reginfo) *(.MIPS.abiflags) *(.pdr) *(.gnu.attributes) *(.comment) } -} diff -r 2500eefe10f9 -r a8a72e893562 pic32.h --- a/pic32.h Mon Oct 22 19:12:33 2018 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,382 +0,0 @@ -/* - * PIC32 peripheral descriptions. - * - * Copyright (C) 2017, 2018 Paul Boddie - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -#ifndef __PIC32_H__ -#define __PIC32_H__ - -/* Peripheral addresses. - * See... - * TABLE 4-1: SFR MEMORYMAP - * TABLE 11-3: PORTA REGISTER MAP - * PIC32MX1XX/2XX 28/36/44-pin Family Data Sheet - */ - -#define OSCCON 0xBF80F000 -#define REFOCON 0xBF80F020 -#define REFOTRIM 0xBF80F030 -#define CFGCON 0xBF80F200 -#define SYSKEY 0xBF80F230 - -#define INT2R 0xBF80FA08 -#define U1RXR 0xBF80FA50 - -#define RPA0R 0xBF80FB00 -#define RPA1R 0xBF80FB04 -#define RPA2R 0xBF80FB08 -#define RPA3R 0xBF80FB0C -#define RPA4R 0xBF80FB10 -#define RPB0R 0xBF80FB2C -#define RPB1R 0xBF80FB30 -#define RPB2R 0xBF80FB34 -#define RPB3R 0xBF80FB38 -#define RPB4R 0xBF80FB3C -#define RPB5R 0xBF80FB40 -#define RPB10R 0xBF80FB54 -#define RPB15R 0xBF80FB68 - -#define INTCON 0xBF881000 -#define IFS0 0xBF881030 -#define IFS1 0xBF881040 -#define IEC0 0xBF881060 -#define IEC1 0xBF881070 -#define IPC0 0xBF881090 -#define IPC1 0xBF8810A0 -#define IPC2 0xBF8810B0 -#define IPC3 0xBF8810C0 -#define IPC4 0xBF8810D0 -#define IPC5 0xBF8810E0 -#define IPC6 0xBF8810F0 -#define IPC7 0xBF881100 -#define IPC8 0xBF881110 -#define IPC9 0xBF881120 -#define IPC10 0xBF881130 - -#define BMXCON 0xBF882000 -#define BMXDKPBA 0xBF882010 -#define BMXDUDBA 0xBF882020 -#define BMXDUPBA 0xBF882030 -#define BMXDRMSZ 0xBF882040 - -#define ANSELA 0xBF886000 -#define TRISA 0xBF886010 -#define PORTA 0xBF886020 -#define LATA 0xBF886030 -#define ODCA 0xBF886040 -#define ANSELB 0xBF886100 -#define TRISB 0xBF886110 -#define PORTB 0xBF886120 -#define LATB 0xBF886130 -#define ODCB 0xBF886140 - -/* DEVCFG conveniences. */ - -#define DEVCFG1_UNUSED 0xff7fcbd8 /* exclude FWDTWINSZ, WINDIS, WDTPS, FCKSM, POSCMOD, IESO */ - -#define DEVCFG1_FWDTEN_OFF (0 << 23) -#define DEVCFG1_FWDTEN_ON (1 << 23) - -#define DEVCFG1_FPBDIV_1 (0b00 << 12) -#define DEVCFG1_FPBDIV_2 (0b01 << 12) -#define DEVCFG1_FPBDIV_4 (0b10 << 12) -#define DEVCFG1_FPBDIV_8 (0b11 << 12) - -#define DEVCFG1_OSCIOFNC_ON (0 << 10) -#define DEVCFG1_OSCIOFNC_OFF (1 << 10) - -#define DEVCFG1_FSOSCEN_OFF (0 << 5) -#define DEVCFG1_FSOSCEN_ON (1 << 5) - -#define DEVCFG1_FNOSC_FRC (0b000) -#define DEVCFG1_FNOSC_FRCDIV_PLL (0b001) -#define DEVCFG1_FNOSC_FRCDIV (0b111) - -#define DEVCFG2_UNUSED 0xfff8ff88 /* exclude UPLLEN, UPLLIDIV */ - -#define DEVCFG2_FPLLODIV_1 (0b000 << 16) -#define DEVCFG2_FPLLODIV_2 (0b001 << 16) -#define DEVCFG2_FPLLODIV_4 (0b010 << 16) -#define DEVCFG2_FPLLODIV_8 (0b011 << 16) -#define DEVCFG2_FPLLODIV_16 (0b100 << 16) -#define DEVCFG2_FPLLODIV_32 (0b101 << 16) -#define DEVCFG2_FPLLODIV_64 (0b110 << 16) -#define DEVCFG2_FPLLODIV_128 (0b111 << 16) - -#define DEVCFG2_FPLLMUL_15 (0b000 << 4) -#define DEVCFG2_FPLLMUL_16 (0b001 << 4) -#define DEVCFG2_FPLLMUL_17 (0b010 << 4) -#define DEVCFG2_FPLLMUL_18 (0b011 << 4) -#define DEVCFG2_FPLLMUL_19 (0b100 << 4) -#define DEVCFG2_FPLLMUL_20 (0b101 << 4) -#define DEVCFG2_FPLLMUL_21 (0b110 << 4) -#define DEVCFG2_FPLLMUL_24 (0b111 << 4) - -#define DEVCFG2_FPLLIDIV_1 (0b000) -#define DEVCFG2_FPLLIDIV_2 (0b001) -#define DEVCFG2_FPLLIDIV_3 (0b010) -#define DEVCFG2_FPLLIDIV_4 (0b011) -#define DEVCFG2_FPLLIDIV_5 (0b100) -#define DEVCFG2_FPLLIDIV_6 (0b101) -#define DEVCFG2_FPLLIDIV_10 (0b110) -#define DEVCFG2_FPLLIDIV_12 (0b111) - -/* DMA conveniences. */ - -#define DMACON 0xBF883000 -#define DCH0CON 0xBF883060 -#define DCH1CON 0xBF883120 -#define DCH2CON 0xBF8831E0 -#define DCH3CON 0xBF8832A0 - -#define DCHMIN 0 -#define DCHMAX 3 -#define DCHBASE DCH0CON -#define DCHSTEP (DCH1CON - DCH0CON) - -#define DCHxCON 0x00 -#define DCHxECON 0x10 -#define DCHxINT 0x20 -#define DCHxSSA 0x30 -#define DCHxDSA 0x40 -#define DCHxSSIZ 0x50 -#define DCHxDSIZ 0x60 -#define DCHxSPTR 0x70 -#define DCHxDPTR 0x80 -#define DCHxCSIZ 0x90 -#define DCHxCPTR 0xA0 -#define DCHxDAT 0xB0 - -#define DMAIEC IEC1 - -#define DCHxIE 1 - -#define DMAIFS IFS1 - -#define DCHxIF 1 - -#define DMAINTBASE 28 - -#define DMAIPC IPC10 -#define DCHIPCBASE 0 -#define DCHIPCSTEP 8 - -/* External interrupt conveniences. */ - -#define INTMIN 0 -#define INTMAX 4 - -#define INTIEC IEC0 - -#define INTxIE 1 - -#define INTIFS IFS0 - -#define INTxIF 1 - -#define INTINTBASE 3 -#define INTINTSTEP 5 - -#define INT0IPC IPC0 -#define INT1IPC IPC1 -#define INT2IPC IPC2 -#define INT3IPC IPC3 -#define INT4IPC IPC4 -#define INTIPCBASE 24 - -/* Output compare conveniences. */ - -#define OC1CON 0xBF803000 -#define OC2CON 0xBF803200 -#define OC3CON 0xBF803400 -#define OC4CON 0xBF803600 -#define OC5CON 0xBF803800 - -#define OCMIN 1 -#define OCMAX 5 -#define OCBASE OC1CON -#define OCSTEP (OC2CON - OC1CON) - -#define OCxCON 0x00 -#define OCxR 0x10 -#define OCxRS 0x20 - -#define OCIEC IEC0 - -#define OCxIE 1 - -#define OCIFS IFS0 - -#define OCxIF 1 - -#define OCINTBASE 7 -#define OCINTSTEP 5 - -#define OC1IPC IPC1 -#define OC2IPC IPC2 -#define OC3IPC IPC3 -#define OC4IPC IPC4 -#define OC5IPC IPC5 -#define OCIPCBASE 16 - -/* Parallel mode conveniences. */ - -#define PMCON 0xBF807000 - -#define PMxCON 0x00 -#define PMxMODE 0x10 -#define PMxADDR 0x20 -#define PMxDOUT 0x30 -#define PMxDIN 0x40 -#define PMxAEN 0x50 -#define PMxSTAT 0x60 - -#define PMMIN 0 -#define PMMAX 0 -#define PMBASE PMCON -#define PMSTEP 0 - -#define PMIEC IEC1 - -#define PMxIE 1 -#define PMxEIE 2 - -#define PMIFS IFS1 - -#define PMxIF 1 -#define PMxEIF 2 - -#define PMINTBASE 16 -#define PMINTSTEP 0 - -#define PMIPC IPC8 -#define PMIPCBASE 24 - -/* Timer conveniences. */ - -#define T1CON 0xBF800600 -#define T2CON 0xBF800800 -#define T3CON 0xBF800A00 -#define T4CON 0xBF800C00 -#define T5CON 0xBF800E00 - -#define TIMERMIN 1 -#define TIMERMAX 5 -#define TIMERBASE T1CON -#define TIMERSTEP (T2CON - T1CON) - -#define TxCON 0x00 -#define TMRx 0x10 -#define PRx 0x20 - -#define TIMERIEC IEC0 - -#define TxIE 1 - -#define TIMERIFS IEC0 - -#define TxIF 1 - -#define TIMERINTBASE 4 -#define TIMERINTSTEP 5 - -#define TIMER1IPC IPC1 -#define TIMER2IPC IPC2 -#define TIMER3IPC IPC3 -#define TIMER4IPC IPC4 -#define TIMER5IPC IPC5 -#define TIMERIPCBASE 0 - -/* UART conveniences. */ - -#define U1MODE 0xBF806000 -#define U2MODE 0xBF806200 - -#define UARTMIN 1 -#define UARTMAX 2 -#define UARTBASE U1MODE -#define UARTSTEP (U2MODE - U1MODE) - -#define UxMODE 0x00 -#define UxSTA 0x10 -#define UxTXREG 0x20 -#define UxRXREG 0x30 -#define UxBRG 0x40 - -#define UARTIEC IEC1 - -#define UxEIE 1 -#define UxRIE 2 -#define UxTIE 4 - -#define UARTIFS IFS1 - -#define UxEIF 1 -#define UxRIF 2 -#define UxTIF 4 - -#define UARTINTBASE 7 -#define UARTINTSTEP 14 - -#define UART1IPC IPC8 -#define UART1IPCBASE 0 -#define UART2IPC IPC9 -#define UART2IPCBASE 8 - -/* Interrupt numbers. - * See... - * TABLE 7-1: INTERRUPT IRQ, VECTOR AND BIT LOCATION - * PIC32MX1XX/2XX 28/36/44-pin Family Data Sheet - */ - -#define DMA0 60 -#define DMA1 61 -#define DMA2 62 -#define DMA3 63 -#define INT0 3 -#define INT1 8 -#define INT2 13 -#define INT3 18 -#define INT4 23 -#define OC1 7 -#define OC2 12 -#define OC3 17 -#define OC4 22 -#define OC5 27 -#define PMP 48 -#define PMPE 49 -#define T1 4 -#define T2 9 -#define T3 14 -#define T4 19 -#define T5 24 -#define U1RX 40 -#define U1TX 41 -#define U2RX 54 -#define U2TX 55 - -/* Address modifiers. - * See... - * 11.2 CLR, SET and INV Registers - * PIC32MX1XX/2XX 28/36/44-pin Family Data Sheet - */ - -#define CLR 0x4 -#define SET 0x8 -#define INV 0xC - -#endif /* __PIC32_H__ */ diff -r 2500eefe10f9 -r a8a72e893562 pic32_c.h --- a/pic32_c.h Mon Oct 22 19:12:33 2018 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,110 +0,0 @@ -/* - * PIC32 peripheral access utilities. - * - * Copyright (C) 2018 Paul Boddie - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -#ifndef __ASSEMBLER__ - -#ifndef __PIC32_C_H__ -#define __PIC32_C_H__ - -#include -#include "mips.h" -#include "pic32.h" - - - -/* Access. */ - -#define REG(mem) *((volatile uint32_t *) (mem)) - - - -/* Bit clearing, setting and inverting. */ - -static inline void CLR_REG(uint32_t mem, uint32_t val) -{ - REG(mem + CLR) = val; -} - -static inline void SET_REG(uint32_t mem, uint32_t val) -{ - REG(mem + SET) = val; -} - -static inline void INV_REG(uint32_t mem, uint32_t val) -{ - REG(mem + INV) = val; -} - - - -/* Address translation. */ - -static inline uint32_t PHYSICAL(uint32_t addr) -{ - return ((uint32_t) addr) - KSEG0_BASE; -} - -static inline uint32_t HW_PHYSICAL(uint32_t addr) -{ - return ((uint32_t) addr) - KSEG1_BASE; -} - - - -/* Register collection access. */ - -static inline uint32_t DMA_REG(int channel, uint32_t reg) -{ - return DCHBASE + reg + (channel - DCHMIN) * DCHSTEP; -} - -static inline uint32_t OC_REG(int unit, uint32_t reg) -{ - return OCBASE + reg + (unit - OCMIN) * OCSTEP; -} - -static inline uint32_t PM_REG(int port, uint32_t reg) -{ - return PMBASE + reg + (port - PMMIN) * PMSTEP; -} - -static inline uint32_t TIMER_REG(int timer, uint32_t reg) -{ - return TIMERBASE + reg + (timer - TIMERMIN) * TIMERSTEP; -} - -static inline uint32_t UART_REG(int uart, uint32_t reg) -{ - return UARTBASE + reg + (uart - UARTMIN) * UARTSTEP; -} - - - -/* Convenience types. */ - -enum dma_chain -{ - dma_chain_none, - dma_chain_next, - dma_chain_previous, -}; - -#endif /* __PIC32_C_H__ */ - -#endif /* __ASSEMBLER__ */ diff -r 2500eefe10f9 -r a8a72e893562 start.S --- a/start.S Mon Oct 22 19:12:33 2018 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,83 +0,0 @@ -/* - * PIC32 microcontroller initialisation code. - * - * Copyright (C) 2017, 2018 Paul Boddie - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -#include "mips.h" -#include "pic32.h" - -/* Application-specific configuration. */ - -#include "devconfig.h" - -/* Disable JTAG functionality on pins. */ - -.section .devcfg0, "a" -.word 0xfffffffb /* DEVCFG0<2> = JTAGEN = 0 */ - -/* Select oscillator, pin usage, watchdog timer and peripheral clock divider. */ - -.section .devcfg1, "a" -.word (DEVCFG1_UNUSED | DEVCFG1_CONFIG) - -/* Set clock dividers and multiplier. */ - -.section .devcfg2, "a" -.word (DEVCFG2_UNUSED | DEVCFG2_CONFIG) - -/* The start routine is placed at the boot location. */ - -.section .boot, "a" - -.globl _start -.extern main - -_start: - /* Enable caching. */ - - mfc0 $v1, CP0_CONFIG - li $t8, ~CONFIG_K0 - and $v1, $v1, $t8 - ori $v1, $v1, CONFIG_K0_CACHABLE_NONCOHERENT - mtc0 $v1, CP0_CONFIG - nop - - /* Get the RAM size. */ - - la $v1, BMXDRMSZ - lw $t0, 0($v1) - - /* Initialise the stack pointer. */ - - li $v1, KSEG0_BASE - addu $sp, $t0, $v1 /* sp = KSEG0_BASE + RAM size */ - - /* Initialise the globals pointer. */ - - lui $gp, %hi(_GLOBAL_OFFSET_TABLE_) - ori $gp, $gp, %lo(_GLOBAL_OFFSET_TABLE_) - - /* - Jump to the main program. Since the boot code is separate from the - other code, the address cannot be obtained via the GOT. - ("relocation truncated to fit: R_MIPS_PC16 against `main'") - */ - - lui $t9, %hi(main) - ori $t9, $t9, %lo(main) - jr $t9 - nop