# HG changeset patch # User Paul Boddie # Date 1540056274 -7200 # Node ID 200e6ac337906bbbada83ea2bd8e8b5b136508b2 # Parent ec8c42b2c07b2af60f0d1db4eb95cbfc40049d59 Introduced separate example directories containing the demonstration program and an initial demonstration of VGA output based on the VGAPIC32 project. Introduced common Makefile definitions and rules to be used by specific example Makefiles. Enhanced the debugging output functions, introducing a separate newline-writing function instead of generating newlines immediately after values. Made sure that mutable data members are explicitly initialised in the examples, since static initialisation will not work without the use of a routine to take care of such initialisation when a program is started. diff -r ec8c42b2c07b -r 200e6ac33790 Makefile --- a/Makefile Sat Oct 20 19:19:30 2018 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,75 +0,0 @@ -# Makefile - Build the PIC32 deployment payload -# -# Copyright (C) 2015, 2017, 2018 Paul Boddie -# Copyright (C) Xiangfu Liu -# -# 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 . - -ARCH = mipsel-linux-gnu -CC = $(ARCH)-gcc -LD = $(ARCH)-ld -NM = $(ARCH)-nm -OBJCOPY=$(ARCH)-objcopy -OBJDUMP=$(ARCH)-objdump - -# 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 - -CFLAGS = -O2 -Wall \ - -fno-unit-at-a-time -fno-zero-initialized-in-bss \ - -ffreestanding -fno-hosted -fno-builtin \ - -march=mips32 -LDFLAGS = -nostdlib -EL - -TARGET = payload.elf -DUMP = $(TARGET:.elf=.dump) -MAP = $(TARGET:.elf=.map) -SCRIPT = $(TARGET:.elf=.ld) - -HEX = $(TARGET:.elf=.hex) -SREC = $(TARGET:.elf=.srec) - -# Ordering of objects is important and cannot be left to replacement rules. - -SRC = start.S main.c init.c debug.c cpu.S -OBJ = start.o main.o init.o debug.o cpu.o - -.PHONY: all clean distclean - -all: $(HEX) $(SREC) - -clean: - rm -f $(OBJ) $(TARGET) $(HEX) $(SREC) $(DUMP) *.map - -distclean: clean - echo "Nothing else to clean." - -$(HEX): $(TARGET) - $(OBJCOPY) -O ihex $(TARGET) $(HEX) - -$(SREC): $(TARGET) - $(OBJCOPY) -O srec $(TARGET) $(SREC) - -$(TARGET): $(OBJ) - $(LD) $(LDFLAGS) -T $(SCRIPT) $(OBJ) -o $@ - $(OBJDUMP) -D $(TARGET) > $(DUMP) - $(OBJDUMP) -h $(TARGET) > $(MAP) - $(NM) -n $(TARGET) > System.map - -.c.o: - $(CC) -c $(CFLAGS) $< -o $@ - -.S.o: - $(CC) -c $(CFLAGS) $< -o $@ diff -r ec8c42b2c07b -r 200e6ac33790 debug.c --- a/debug.c Sat Oct 20 19:19:30 2018 +0200 +++ b/debug.c Sat Oct 20 19:24:34 2018 +0200 @@ -20,14 +20,21 @@ #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 reg) -{ - vbits(REG(reg)); -} - -void vbits(uint32_t val) +void bits(uint32_t val, int bytes) { uint32_t mask; @@ -36,17 +43,14 @@ uart_write('1'); else uart_write('0'); - - uart_write('\r'); - uart_write('\n'); } -void vhex(uint32_t val) +void hex(uint32_t val, int bytes) { uint32_t mask; - uint8_t digit, shift; + uint8_t digit, shift, start = bytes * 8 - 4; - for (mask = (0b1111 << 28), shift = 28; mask; mask >>= 4, shift -= 4) + for (mask = (0b1111 << start), shift = start; mask; mask >>= 4, shift -= 4) { digit = (val & mask) >> shift; if (digit > 9) @@ -54,9 +58,6 @@ else uart_write('0' + digit); } - - uart_write('\r'); - uart_write('\n'); } @@ -94,6 +95,12 @@ 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) diff -r ec8c42b2c07b -r 200e6ac33790 debug.h --- a/debug.h Sat Oct 20 19:19:30 2018 +0200 +++ b/debug.h Sat Oct 20 19:24:34 2018 +0200 @@ -20,11 +20,15 @@ #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 reg); -void vbits(uint32_t val); -void vhex(uint32_t val); +void bits(uint32_t val, int bytes); +void hex(uint32_t val, int bytes); /* General input/output functions. */ @@ -36,6 +40,7 @@ /* 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 ec8c42b2c07b -r 200e6ac33790 examples/demo/Makefile --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/examples/demo/Makefile Sat Oct 20 19:24:34 2018 +0200 @@ -0,0 +1,33 @@ +# Makefile - Build the PIC32 deployment payload +# +# Copyright (C) 2015, 2017, 2018 Paul Boddie +# Copyright (C) Xiangfu Liu +# +# 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 ../../mk/common.mk + +TARGET = demo.elf +DUMP = $(TARGET:.elf=.dump) +MAP = $(TARGET:.elf=.map) + +HEX = $(TARGET:.elf=.hex) +SREC = $(TARGET:.elf=.srec) + +# Ordering of objects is important and cannot be left to replacement rules. + +SRC = $(START_SRC) main.c $(COMMON_SRC) +OBJ = $(START_OBJ) main.o $(COMMON_OBJ) + +include ../../mk/rules.mk diff -r ec8c42b2c07b -r 200e6ac33790 examples/demo/main.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/examples/demo/main.c Sat Oct 20 19:24:34 2018 +0200 @@ -0,0 +1,197 @@ +/* + * A demonstration of various PIC32 peripherals. + * + * 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 "pic32_c.h" +#include "init.h" +#include "debug.h" +#include "main.h" + +static const char message1[] = "Hello!\r\n"; +static const char message2[] = "Again!\r\n"; +static int uart_echo; + + + +/* Blink an attached LED with delays implemented using a loop. */ + +static void blink(uint32_t delay, uint32_t port, uint32_t pins) +{ + uint32_t counter; + + /* Clear outputs (LED). */ + + CLR_REG(port, pins); + + while (1) + { + counter = delay; + + while (counter--) __asm__(""); /* retain loop */ + + /* Invert outputs (LED). */ + + INV_REG(port, pins); + } +} + + + +/* Main program. */ + +void main(void) +{ + uart_echo = 0; + + init_memory(); + init_pins(); + init_outputs(); + + unlock_config(); + config_uart(); + lock_config(); + + init_dma(); + + /* Initiate DMA on the Timer2 interrupt. Since the channel is not + auto-enabled, it must be explicitly enabled elsewhere (when a UART + interrupt is handled). */ + + dma_init(0, 3); + dma_set_interrupt(0, T2, 1); + dma_set_transfer(0, PHYSICAL((uint32_t) message1), sizeof(message1) - 1, + HW_PHYSICAL(UART_REG(1, UxTXREG)), 1, + 1); + + /* Enable DMA on the preceding channel's completion, with OC1 initiating + transfers, raising a transfer completion interrupt to be handled. */ + + dma_init(1, 3); + dma_set_chaining(1, dma_chain_previous); + dma_set_interrupt(1, OC1, 1); + dma_set_transfer(1, PHYSICAL((uint32_t) message2), sizeof(message2) - 1, + HW_PHYSICAL(UART_REG(1, UxTXREG)), 1, + 1); + dma_init_interrupt(1, 0b00001000, 7, 3); + + /* Configure a timer for the first DMA channel whose interrupt condition + drives the transfer but is not handled (having a lower priority than the + CPU. */ + + timer_init(2, 0b111, 60000); + timer_init_interrupt(2, 1, 3); + timer_on(2); + + /* Configure a timer for the output compare unit below. */ + + timer_init(3, 0b111, 20000); + timer_on(3); + + /* Configure output compare in dual compare (continuous output) mode using + Timer3 as time base. The interrupt condition drives the second DMA + channel but is not handled (having a lower priority than the CPU). */ + + oc_init(1, 0b101, 3); + oc_set_pulse(1, 10000); + oc_set_pulse_end(1, 20000); + oc_init_interrupt(1, 1, 3); + oc_on(1); + + /* Set UART interrupt priority above CPU priority to process events and to + enable the first DMA channel. */ + + uart_init(1, 115200); + uart_init_interrupt(1, UxRIF, 7, 3); + uart_on(1); + + interrupts_on(); + + blink(3 << 24, PORTA, 1 << 3); +} + + + +/* Exception and interrupt handlers. */ + +void exception_handler(void) +{ + blink(3 << 12, PORTA, 1 << 3); +} + +void interrupt_handler(void) +{ + uint32_t ifs; + char val; + + /* Check for a UART receive interrupt condition (UxRIF). */ + + ifs = REG(UARTIFS) & UART_INT_FLAGS(1, UxRIF); + + if (ifs) + { + /* Clear the UART interrupt condition. */ + + CLR_REG(UARTIFS, ifs); + + /* Write the received data back. */ + + while (uart_can_read(1)) + { + val = uart_read_char(1); + if (uart_echo) + uart_write_char(1, val); + + /* Initiate transfer upon receiving a particular character. */ + + if (val == '0') + dma_on(0); + } + } + + /* Check for a DMA interrupt condition (CHBCIF). */ + + ifs = REG(DMAIFS) & DMA_INT_FLAGS(1, DCHxIF); + + if (ifs) + { + uart_write_string("CHBCIF\r\n"); + INV_REG(PORTA, 1 << 2); + CLR_REG(DMA_REG(1, DCHxINT), 0b11111111); + CLR_REG(DMAIFS, ifs); + } +} + + + +/* Peripheral pin configuration. */ + +void config_uart(void) +{ + /* Map U1RX to RPB13. */ + + REG(U1RXR) = 0b0011; /* U1RXR<3:0> = 0011 (RPB13) */ + + /* Map U1TX to RPB15. */ + + REG(RPB15R) = 0b0001; /* RPB15R<3:0> = 0001 (U1TX) */ + + /* Set RPB13 to input. */ + + SET_REG(TRISB, 1 << 13); +} diff -r ec8c42b2c07b -r 200e6ac33790 examples/demo/main.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/examples/demo/main.h Sat Oct 20 19:24:34 2018 +0200 @@ -0,0 +1,27 @@ +/* + * A demonstration of various PIC32 peripherals. + * + * 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 __MAIN_H__ +#define __MAIN_H__ + +/* Peripheral pin configuration. */ + +void config_uart(void); + +#endif /* __MAIN_H__ */ diff -r ec8c42b2c07b -r 200e6ac33790 examples/vga/Makefile --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/examples/vga/Makefile Sat Oct 20 19:24:34 2018 +0200 @@ -0,0 +1,33 @@ +# Makefile - Build the PIC32 deployment payload +# +# Copyright (C) 2015, 2017, 2018 Paul Boddie +# Copyright (C) Xiangfu Liu +# +# 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 ../../mk/common.mk + +TARGET = vga.elf +DUMP = $(TARGET:.elf=.dump) +MAP = $(TARGET:.elf=.map) + +HEX = $(TARGET:.elf=.hex) +SREC = $(TARGET:.elf=.srec) + +# Ordering of objects is important and cannot be left to replacement rules. + +SRC = $(START_SRC) main.c $(COMMON_SRC) +OBJ = $(START_OBJ) main.o $(COMMON_OBJ) + +include ../../mk/rules.mk diff -r ec8c42b2c07b -r 200e6ac33790 examples/vga/main.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/examples/vga/main.c Sat Oct 20 19:24:34 2018 +0200 @@ -0,0 +1,297 @@ +/* + * Generate a VGA signal using a PIC32 microcontroller. + * + * 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 "pic32_c.h" +#include "init.h" +#include "debug.h" +#include "main.h" +#include "vga.h" + + + +/* Display state. */ + +static void (*state_handler)(void); +static uint32_t line; + +/* Pixel data. */ + +static uint8_t linedata[LINE_LENGTH]; +static const uint8_t zerodata[ZERO_LENGTH] = {0}; + + + +static void test_linedata(void) +{ + int i; + + for (i = 0; i < LINE_LENGTH; i++) + linedata[i] = (i % 2) ? 0xff : 0x00; +} + +/* Blink an attached LED with delays implemented using a loop. */ + +static void blink(uint32_t delay, uint32_t port, uint32_t pins) +{ + uint32_t counter; + int i; + + /* Clear outputs (LED). */ + + CLR_REG(port, pins); + + while (1) + { + counter = delay; + + while (counter--) __asm__(""); /* retain loop */ + + /* Invert outputs (LED). */ + + INV_REG(port, pins); + for (i = 0; i < LINE_LENGTH; i++) + hex(linedata[i], 1); + uart_write_nl(); + } +} + + + +/* Main program. */ + +void main(void) +{ + line = 0; + state_handler = vbp_active; + test_linedata(); + + init_memory(); + init_pins(); + init_outputs(); + + unlock_config(); + config_oc(); + config_uart(); + lock_config(); + + init_dma(); + + /* Initiate DMA on the Timer2 interrupt transferring line data to the first + byte of PORTB. Do not enable the channel for initiation until the visible + region is about to start. */ + + dma_init(0, 3); + dma_set_auto_enable(0, 1); + dma_set_interrupt(0, T2, 1); + dma_set_transfer(0, PHYSICAL((uint32_t) linedata), LINE_LENGTH, + HW_PHYSICAL(PORTB), 1, + LINE_LENGTH); + dma_init_interrupt(0, 0b00001000, 1, 3); + + /* Enable DMA on the preceding channel's completion, with this also + initiating transfers. */ + + dma_init(1, 3); + dma_set_chaining(1, dma_chain_previous); + dma_set_interrupt(1, DMA0, 1); + dma_set_transfer(1, PHYSICAL((uint32_t) zerodata), ZERO_LENGTH, + HW_PHYSICAL(PORTB), 1, + ZERO_LENGTH); + dma_set_receive_events(1, 1); + + /* Configure a timer for the horizontal sync. The timer has no prescaling + (0). */ + + timer_init(2, 0, HFREQ_LIMIT); + timer_on(2); + + /* Horizontal sync. */ + + /* Configure output compare in dual compare (continuous output) mode using + Timer2 as time base. The interrupt condition drives the first DMA channel + but is not handled (having a lower priority than the CPU). */ + + oc_init(1, 0b101, 2); + oc_set_pulse(1, HSYNC_END); + oc_set_pulse_end(1, HSYNC_START); + oc_init_interrupt(1, 7, 3); + oc_on(1); + + /* Vertical sync. */ + + /* Configure output compare in single compare (output driven low) mode using + Timer2 as time base. The unit is enabled later. It is only really used to + achieve precisely-timed level transitions in hardware. */ + + oc_init(2, 0b010, 2); + oc_set_pulse(2, 0); + + uart_init(1, 115200); + uart_on(1); + + interrupts_on(); + + blink(3 << 24, PORTA, 1 << 3); +} + + + +/* Exception and interrupt handlers. */ + +void exception_handler(void) +{ + blink(3 << 12, PORTA, 1 << 3); +} + +void interrupt_handler(void) +{ + uint32_t ifs; + + /* Check for a OC1 interrupt condition. */ + + ifs = REG(OCIFS) & OC_INT_FLAGS(1, OCxIF); + + if (ifs) + { + line += 1; + state_handler(); + CLR_REG(OCIFS, ifs); + } +} + + + +/* Vertical back porch region. */ + +void vbp_active(void) +{ + if (line < VISIBLE_START) + return; + + /* Enter the visible region. */ + + state_handler = visible_active; + + /* NOTE: Set the line address. */ + + /* Enable the channel for the next line. */ + + dma_on(0); +} + +/* Visible region. */ + +void visible_active(void) +{ + uint32_t ifs; + + /* Remove any DMA interrupt condition (CHBCIF). */ + + ifs = REG(DMAIFS) & DMA_INT_FLAGS(0, DCHxIF); + + if (ifs) + { + CLR_REG(DMA_REG(0, DCHxINT), 0b11111111); + CLR_REG(DMAIFS, ifs); + INV_REG(PORTA, 1 << 2); + } + + if (line < VFP_START) + { + /* NOTE: Update the line address and handle wraparound. */ + + return; + } + + /* End the visible region. */ + + state_handler = vfp_active; + + /* Disable the channel for the next line. */ + + dma_off(0); +} + +/* Vertical front porch region. */ + +void vfp_active(void) +{ + if (line < VSYNC_START) + return; + + /* Enter the vertical sync region. */ + + state_handler = vsync_active; + + /* Bring vsync low (single compare, output driven low) when the next line + starts. */ + + oc_init(2, 0b010, 2); + oc_on(2); +} + +/* Vertical sync region. */ + +void vsync_active(void) +{ + if (line < VSYNC_END) + return; + + /* Start again at the top of the display. */ + + line = 0; + state_handler = vbp_active; + + /* Bring vsync high (single compare, output driven high) when the next line + starts. */ + + oc_init(2, 0b001, 2); + oc_on(2); +} + + + +/* Peripheral pin configuration. */ + +void config_oc(void) +{ + /* Map OC1 to RPA0. */ + + REG(RPA0R) = 0b0101; /* RPA0R<3:0> = 0101 (OC1) */ + + /* Map OC2 to RPA1. */ + + REG(RPA1R) = 0b0101; /* RPA1R<3:0> = 0101 (OC2) */ +} + +void config_uart(void) +{ + /* Map U1RX to RPB13. */ + + REG(U1RXR) = 0b0011; /* U1RXR<3:0> = 0011 (RPB13) */ + + /* Map U1TX to RPB15. */ + + REG(RPB15R) = 0b0001; /* RPB15R<3:0> = 0001 (U1TX) */ + + /* Set RPB13 to input. */ + + SET_REG(TRISB, 1 << 13); +} diff -r ec8c42b2c07b -r 200e6ac33790 examples/vga/main.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/examples/vga/main.h Sat Oct 20 19:24:34 2018 +0200 @@ -0,0 +1,35 @@ +/* + * Generate a VGA signal using a PIC32 microcontroller. + * + * 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 __MAIN_H__ +#define __MAIN_H__ + +/* Peripheral pin configuration. */ + +void config_oc(void); +void config_uart(void); + +/* Display state handlers. */ + +void vbp_active(void); +void visible_active(void); +void vfp_active(void); +void vsync_active(void); + +#endif /* __MAIN_H__ */ diff -r ec8c42b2c07b -r 200e6ac33790 examples/vga/vga.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/examples/vga/vga.h Sat Oct 20 19:24:34 2018 +0200 @@ -0,0 +1,55 @@ +/* + * Generate a VGA signal using a PIC32 microcontroller. + * + * 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 __VGA_H__ +#define __VGA_H__ + +#define LINE_LENGTH 160 /* pixels */ +#define LINE_COUNT 256 /* distinct display lines */ + +#define ZERO_LENGTH 1 /* pixels */ + +/* 24MHz cycle measurements. */ + +#define HFREQ_LIMIT 643 +#define HSYNC_START 460 +#define HSYNC_LIMIT 64 +#define HSYNC_END (HSYNC_START + HSYNC_LIMIT) + +/* Horizontal lines, back porch end. */ + +#define VISIBLE_START 70 +#define VFP_START (VISIBLE_START + 2 * LINE_COUNT) + +/* Horizontal lines, front porch end. */ + +#define VSYNC_START 620 + +/* Horizontal lines, back porch start. */ + +#define VSYNC_END 622 + +#define SCREEN_BASE 256 +#define SCREEN_SIZE (40 * 1024) +#define SCREEN_LIMIT (SCREEN_BASE + SCREEN_SIZE) + +#define SCREEN_BASE_KSEG0 (KSEG0_BASE + SCREEN_BASE) +#define SCREEN_LIMIT_KSEG0 (KSEG0_BASE + SCREEN_LIMIT) + +#endif /* __VGA_H__ */ diff -r ec8c42b2c07b -r 200e6ac33790 main.c --- a/main.c Sat Oct 20 19:19:30 2018 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,195 +0,0 @@ -/* - * A demonstration of various PIC32 peripherals. - * - * 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 "pic32_c.h" -#include "init.h" -#include "debug.h" -#include "main.h" - -static const char message1[] = "Hello!\r\n"; -static const char message2[] = "Again!\r\n"; -static int uart_echo = 0; - - - -/* Blink an attached LED with delays implemented using a loop. */ - -static void blink(uint32_t delay, uint32_t port, uint32_t pins) -{ - uint32_t counter; - - /* Clear outputs (LED). */ - - CLR_REG(port, pins); - - while (1) - { - counter = delay; - - while (counter--) __asm__(""); /* retain loop */ - - /* Invert outputs (LED). */ - - INV_REG(port, pins); - } -} - - - -/* Main program. */ - -void main(void) -{ - init_memory(); - init_pins(); - init_outputs(); - - unlock_config(); - config_uart(); - lock_config(); - - init_dma(); - - /* Initiate DMA on the Timer2 interrupt. Since the channel is not - auto-enabled, it must be explicitly enabled elsewhere (when a UART - interrupt is handled). */ - - dma_init(0, 3); - dma_set_interrupt(0, T2, 1); - dma_set_transfer(0, PHYSICAL((uint32_t) message1), sizeof(message1) - 1, - HW_PHYSICAL(UART_REG(1, UxTXREG)), 1, - 1); - - /* Enable DMA on the preceding channel's completion, with OC1 initiating - transfers, raising a transfer completion interrupt to be handled. */ - - dma_init(1, 3); - dma_set_chaining(1, dma_chain_previous); - dma_set_interrupt(1, OC1, 1); - dma_set_transfer(1, PHYSICAL((uint32_t) message2), sizeof(message2) - 1, - HW_PHYSICAL(UART_REG(1, UxTXREG)), 1, - 1); - dma_init_interrupt(1, 0b00001000, 7, 3); - - /* Configure a timer for the first DMA channel whose interrupt condition - drives the transfer but is not handled (having a lower priority than the - CPU. */ - - timer_init(2, 0b111, 60000); - timer_init_interrupt(2, 1, 3); - timer_on(2); - - /* Configure a timer for the output compare unit below. */ - - timer_init(3, 0b111, 20000); - timer_on(3); - - /* Configure output compare in dual compare (continuous output) mode using - Timer3 as time base. The interrupt condition drives the second DMA - channel but is not handled (having a lower priority than the CPU). */ - - oc_init(1, 0b101, 3); - oc_set_pulse(1, 10000); - oc_set_pulse_end(1, 20000); - oc_init_interrupt(1, 1, 3); - oc_on(1); - - /* Set UART interrupt priority above CPU priority to process events and to - enable the first DMA channel. */ - - uart_init(1, 115200); - uart_init_interrupt(1, UxRIF, 7, 3); - uart_on(1); - - interrupts_on(); - - blink(3 << 24, PORTA, 1 << 3); -} - - - -/* Exception and interrupt handlers. */ - -void exception_handler(void) -{ - blink(3 << 12, PORTA, 1 << 3); -} - -void interrupt_handler(void) -{ - uint32_t ifs; - char val; - - /* Check for a UART receive interrupt condition (UxRIF). */ - - ifs = REG(UARTIFS) & UART_INT_FLAGS(1, UxRIF); - - if (ifs) - { - /* Clear the UART interrupt condition. */ - - CLR_REG(UARTIFS, ifs); - - /* Write the received data back. */ - - while (uart_can_read(1)) - { - val = uart_read_char(1); - if (uart_echo) - uart_write_char(1, val); - - /* Initiate transfer upon receiving a particular character. */ - - if (val == '0') - dma_on(0); - } - } - - /* Check for a DMA interrupt condition (CHBCIF). */ - - ifs = REG(DMAIFS) & DMA_INT_FLAGS(1, 1); - - if (ifs) - { - uart_write_string("CHBCIF\r\n"); - INV_REG(PORTA, 1 << 2); - CLR_REG(DMA_REG(1, DCHxINT), 0b11111111); - CLR_REG(DMAIFS, ifs); - } -} - - - -/* Peripheral pin configuration. */ - -void config_uart(void) -{ - /* Map U1RX to RPB13. */ - - REG(U1RXR) = 0b0011; /* U1RXR<3:0> = 0011 (RPB13) */ - - /* Map U1TX to RPB15. */ - - REG(RPB15R) = 0b0001; /* RPB15R<3:0> = 0001 (U1TX) */ - - /* Set RPB13 to input. */ - - SET_REG(TRISB, 1 << 13); -} diff -r ec8c42b2c07b -r 200e6ac33790 main.h --- a/main.h Sat Oct 20 19:19:30 2018 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,27 +0,0 @@ -/* - * A demonstration of various PIC32 peripherals. - * - * 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 __MAIN_H__ -#define __MAIN_H__ - -/* Peripheral pin configuration. */ - -void config_uart(void); - -#endif /* __MAIN_H__ */ diff -r ec8c42b2c07b -r 200e6ac33790 mk/common.mk --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/mk/common.mk Sat Oct 20 19:24:34 2018 +0200 @@ -0,0 +1,51 @@ +# Makefile - Common definitions for building PIC32 deployment payloads +# +# Copyright (C) 2015, 2017, 2018 Paul Boddie +# Copyright (C) Xiangfu Liu +# +# 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 . + +ARCH = mipsel-linux-gnu +CC = $(ARCH)-gcc +LD = $(ARCH)-ld +NM = $(ARCH)-nm +OBJCOPY=$(ARCH)-objcopy +OBJDUMP=$(ARCH)-objdump + +# 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 + +CFLAGS = -O2 -Wall \ + -fno-unit-at-a-time -fno-zero-initialized-in-bss \ + -ffreestanding -fno-hosted -fno-builtin \ + -march=mips32 \ + -I../.. +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 + +# 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 linker script. + +SCRIPT = ../../payload.ld diff -r ec8c42b2c07b -r 200e6ac33790 mk/rules.mk --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/mk/rules.mk Sat Oct 20 19:24:34 2018 +0200 @@ -0,0 +1,45 @@ +# Makefile - Rules for building PIC32 deployment payloads +# +# Copyright (C) 2015, 2017, 2018 Paul Boddie +# Copyright (C) Xiangfu Liu +# +# 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 . + +.PHONY: all clean distclean + +all: $(HEX) $(SREC) + +clean: + rm -f $(OBJ) $(TARGET) $(HEX) $(SREC) $(DUMP) *.map + +distclean: clean + echo "Nothing else to clean." + +$(HEX): $(TARGET) + $(OBJCOPY) -O ihex $(TARGET) $(HEX) + +$(SREC): $(TARGET) + $(OBJCOPY) -O srec $(TARGET) $(SREC) + +$(TARGET): $(OBJ) + $(LD) $(LDFLAGS) -T $(SCRIPT) $(OBJ) -o $@ + $(OBJDUMP) -D $(TARGET) > $(DUMP) + $(OBJDUMP) -h $(TARGET) > $(MAP) + $(NM) -n $(TARGET) > System.map + +.c.o: + $(CC) -c $(CFLAGS) $< -o $@ + +.S.o: + $(CC) -c $(CFLAGS) $< -o $@