# HG changeset patch # User Paul Boddie # Date 1494946165 -7200 # Node ID 20ec7f1e54f81033252e2ff7996802b0e9bec93f # Parent 5d521fefe5a69705e0e08d6324bf5fb0cdce6ca6 Switched to using PORTB instead of PMDIN for pixel data output. Added a second DMA channel to reset the output level after each line. diff -r 5d521fefe5a6 -r 20ec7f1e54f8 README.txt --- a/README.txt Mon May 15 14:52:17 2017 +0200 +++ b/README.txt Tue May 16 16:49:25 2017 +0200 @@ -2,19 +2,19 @@ -------------------------------------- MCLR# 1 \/ 28 - D7/PMD7 2 27 - D6/PMD6 3 26 (PMCS1) -PGED1/D0/PMD0 4 25 -PGEC1/D1/PMD1 5 24 (PMRD) - D2/PMD2 6 23 - (PMWR) 7 22 RB11/VSYNC - 8 21 RB10/STATUS - 9 20 - (PMA0) 10 19 - 11 18 PMD3/D3 - (PMA1) 12 17 PMD4/D4 - 13 16 PMD5/D5 - HSYNC/OC2 14 15 +VSYNC/OC1/RA0 2 27 +HSYNC/OC2/RA1 3 26 RB15 + D0/RB0 4 25 RB14 + D1/RB1 5 24 RB13 + D2/RB2 6 23 + D3/RB3 7 22 RB11/PGEC2 + 8 21 RB10/PGEC3 + RA2 9 20 + RA3 10 19 + D4/RB4 11 18 RB9 + 12 17 RB8 + 13 16 RB7/D7 + D5/RB5 14 15 RB6/D6 Data Signal Routing ------------------- diff -r 5d521fefe5a6 -r 20ec7f1e54f8 pic32.h --- a/pic32.h Mon May 15 14:52:17 2017 +0200 +++ b/pic32.h Tue May 16 16:49:25 2017 +0200 @@ -37,6 +37,15 @@ #define CFGCON 0xBF80F200 #define SYSKEY 0xBF80F230 +#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 diff -r 5d521fefe5a6 -r 20ec7f1e54f8 vga.S --- a/vga.S Mon May 15 14:52:17 2017 +0200 +++ b/vga.S Tue May 16 16:49:25 2017 +0200 @@ -119,6 +119,10 @@ jal init_pins nop + la $t0, PORTA + li $t1, (1 << 3) /* PORTA<3> = RA3 */ + sw $t1, CLR($t0) + jal init_oc_pins nop @@ -132,17 +136,12 @@ jal init_timer2 nop - /* Initialise PMP. */ - - jal init_pmp - nop - /* Initialise DMA. */ jal init_dma nop - /* Initialise OC3 and OC2. */ + /* Initialise OC1 and OC2. */ jal init_oc nop @@ -155,16 +154,6 @@ jal handle_error_level nop - /* Set initial sync conditions. */ - - la $t0, PORTB - li $t1, (1 << 5) /* PORTB<5> = RB5 */ - sw $t1, SET($t0) - - la $t0, PORTB - li $t1, (1 << 10) /* PORTB<10> = RB10 */ - sw $t1, SET($t0) - /* Main program. */ li $a1, 5000000 /* counter = 5000000 */ @@ -183,8 +172,8 @@ li $a1, 5000000 /* counter = 5000000 */ - la $t0, PORTB - li $t1, (1 << 11) /* PORTB<11> = RB11 */ + la $t0, PORTA + li $t1, (1 << 3) /* PORTA<3> = RA3 */ sw $t1, INV($t0) _next: @@ -272,7 +261,7 @@ /* Output compare initialisation. -Timer2 will be used to trigger two events using OC3: one initiating the hsync +Timer2 will be used to trigger two events using OC1: one initiating the hsync pulse, and one terminating the pulse. The pulse should appear after the line data has been transferred using DMA, but this is achieved by just choosing suitable start and end values. @@ -282,35 +271,35 @@ */ init_oc: - /* Disable OC3 interrupts. */ + /* Disable OC1 interrupts. */ la $v0, IEC0 - li $v1, (1 << 17) /* IEC0<17> = OC3IE = 0 */ + li $v1, (1 << 7) /* IEC0<7> = OC1IE = 0 */ sw $v1, CLR($v0) la $v0, IFS0 - li $v1, (1 << 17) /* IFS0<17> = OC3IF = 0 */ + li $v1, (1 << 7) /* IFS0<7> = OC1IF = 0 */ sw $v1, CLR($v0) - /* Initialise OC3. */ + /* Initialise OC1. */ - la $v0, OC3CON - li $v1, 0b101 /* OC3CON<2:0> = OCM<2:0> = 101 (dual compare, continuous pulse) */ + la $v0, OC1CON + li $v1, 0b101 /* OC1CON<2:0> = OCM<2:0> = 101 (dual compare, continuous pulse) */ sw $v1, 0($v0) /* Pulse start and end. */ - la $v0, OC3R + la $v0, OC1R li $v1, HSYNC_END /* HSYNC_START for positive polarity */ sw $v1, 0($v0) - la $v0, OC3RS + la $v0, OC1RS li $v1, HSYNC_START /* HSYNC_END for positive polarity */ sw $v1, 0($v0) - /* OC3 is enabled. */ + /* OC1 is enabled. */ - la $v0, OC3CON + la $v0, OC1CON li $v1, (1 << 15) sw $v1, SET($v0) @@ -356,16 +345,16 @@ li $v1, (1 << 13) /* IOLOCK = 0 */ sw $v1, CLR($v0) - /* Map OC3 to RPB10. */ + /* Map OC1 to RPA0. */ - la $v0, RPB10R - li $v1, 0b0101 /* RPB10R<3:0> = 0101 (OC3) */ + la $v0, RPA0R + li $v1, 0b0101 /* RPA0R<3:0> = 0101 (OC1) */ sw $v1, 0($v0) - /* Map OC2 to RPB5. */ + /* Map OC2 to RPA1. */ - la $v0, RPB5R - li $v1, 0b0101 /* RPB5R<3:0> = 0101 (OC2) */ + la $v0, RPA1R + li $v1, 0b0101 /* RPA1R<3:0> = 0101 (OC2) */ sw $v1, 0($v0) la $v0, CFGCON @@ -382,65 +371,10 @@ -/* Parallel Master Port initialisation. */ - -init_pmp: - /* Disable PMP interrupts. */ - - la $v0, IEC1 - li $v1, (1 << 16) /* IEC1<16> = PMPIE = 0 */ - sw $v1, CLR($v0) - - /* Initialise PMP. - - PMCON<12:11> = ADDRMUX<1:0> = 0; demultiplexed address and data - PMCON<9> = PTWREN<0> = 0; no write pin - PMCON<8> = PTRDEN<0> = 0; no read pin - PMCON<7:6> = CSF<1:0> = 0; no chip select pins - */ - - la $v0, PMCON - sw $zero, 0($v0) - - /* - PMMODE<14:13> = IRQM<1:0> = 1; interrupt after every read/write - PMMODE<12:11> = INCM<1:0> = 0; no increment on every read/write - PMMODE<10> = MODE16<0> = 0; 8-bit transfers - PMMODE<9:8> = MODE<1:0> = 10; master mode 2 - PMMODE<5:2> = WAITM<3:0> = 00; single cycle read/write, no chip select wait cycles - */ - - la $v0, PMMODE - li $v1, 0x2200 - sw $v1, 0($v0) - - /* Free non-essential pins for general I/O. */ - - la $v0, PMAEN - sw $zero, 0($v0) - - la $v0, PMADDR - sw $zero, 0($v0) - - la $v0, IFS1 - li $v1, (3 << 16) /* IFS1<17:16> = PMPEIF, PMPIF = 0 */ - sw $v1, CLR($v0) - - /* Start PMP mode. */ - - la $v0, PMCON - li $v1, (1 << 15) /* PMCON<15> = ON = 1 */ - sw $v1, SET($v0) - - jr $ra - nop - - - /* Direct Memory Access initialisation. -Write 160 pixels to the PMP for the line data. This is initiated by a timer +Write 160 pixels to PORTB for the line data. This is initiated by a timer interrupt. Upon completion of the transfer, a DMA interrupt initiates the address update routine, changing the source address of the DMA channel. */ @@ -449,13 +383,13 @@ /* Disable DMA interrupts. */ la $v0, IEC1 - li $v1, (1 << 28) /* IEC1<28> = DMA0IE = 0 */ + li $v1, (3 << 28) /* IEC1<29:28> = DMA1IE, DMA0IE = 0 */ sw $v1, CLR($v0) /* Clear DMA interrupt flags. */ la $v0, IFS1 - li $v1, (1 << 28) /* IFS1<28> = DMA0IF = 0 */ + li $v1, (3 << 28) /* IFS1<29:28> = DMA1IF, DMA0IF = 0 */ sw $v1, CLR($v0) /* Enable DMA. */ @@ -471,7 +405,7 @@ Specify a priority of 3: DCHxCON<1:0> = CHPRI<1:0> = 3 - Auto-enable the channels: + Auto-enable the channel: DCHxCON<4> = CHAEN = 1 */ @@ -480,6 +414,24 @@ sw $v1, 0($v0) /* + Initialise a level reset channel. + The reset channel will be channel 1 (x = 1). + + Specify a priority of 3: + DCHxCON<1:0> = CHPRI<1:0> = 3 + + Chain the channel to channel 0: + DCHxCON<5> = CHCHN = 1 + + Allow the channel to receive events when disabled: + DCHxCON<6> = CHAED = 1 + */ + + la $v0, DCH1CON + li $v1, 0b1100011 + sw $v1, 0($v0) + + /* Initiate channel transfers when the initiating interrupt condition occurs: DCHxECON<15:8> = CHSIRQ<7:0> = timer 2 interrupt @@ -491,7 +443,17 @@ sw $v1, 0($v0) /* - The line channel has a cell size as the number bytes in a line: + Initiate reset channel transfer when channel 0 is finished: + DCHxECON<15:8> = CHSIRQ<7:0> = channel 0 interrupt + DCHxECON<4> = SIRQEN = 1 + */ + + la $v0, DCH1ECON + li $v1, (60 << 8) | (1 << 4) + sw $v1, 0($v0) + + /* + The line channel has a cell size of the number bytes in a line: DCHxCSIZ<15:0> = CHCSIZ<15:0> = LINE_LENGTH */ @@ -500,6 +462,15 @@ sw $v1, 0($v0) /* + The reset channel has a cell size of a single zero byte: + DCHxCSIZ<15:0> = CHCSIZ<15:0> = LINE_LENGTH + */ + + la $v0, DCH1CSIZ + li $v1, 1 + sw $v1, 0($v0) + + /* The source has a size identical to the cell size: DCHxSSIZ<15:0> = CHSSIZ<15:0> = LINE_LENGTH */ @@ -508,6 +479,10 @@ li $v1, LINE_LENGTH sw $v1, 0($v0) + la $v0, DCH1SSIZ + li $v1, 1 + sw $v1, 0($v0) + /* The source address is the physical address of the line data: DCHxSSA = physical(line data address) @@ -517,6 +492,17 @@ sw $zero, 0($v0) /* + For the reset channel, a single byte of zero is transferred: + DCHxSSA = physical(zero data address) + */ + + la $v0, DCH1SSA + la $v1, zerodata + li $t8, KSEG0_BASE + subu $v1, $v1, $t8 + sw $v1, 0($v0) + + /* The destination has a size of 1 byte: DCHxDSIZ<15:0> = CHDSIZ<15:0> = 1 */ @@ -525,17 +511,23 @@ li $v1, 1 sw $v1, 0($v0) + la $v0, DCH1DSIZ + sw $v1, 0($v0) + /* - The destination address is the physical address of PMDIN: - DCHxDSA = physical(PMDIN) + The destination address is the physical address of PORTB: + DCHxDSA = physical(PORTB) */ la $v0, DCH0DSA - li $v1, PMDIN + li $v1, PORTB li $t8, KSEG1_BASE subu $v1, $v1, $t8 sw $v1, 0($v0) + la $v0, DCH1DSA + sw $v1, 0($v0) + /* Use the block transfer completion interrupt to indicate when the source address can be updated. @@ -559,7 +551,7 @@ li $v1, (1 << 28) /* IEC1<28> = DMA0IE = 1 */ sw $v1, SET($v0) - /* Enable channel. */ + /* Enable line channel. */ la $v0, DCH0CON li $v1, 0b10000000 @@ -568,6 +560,9 @@ jr $ra nop +zerodata: +.word 0 + /* Framebuffer initialisation. */ @@ -645,8 +640,8 @@ addiu $t8, $t8, -1 bnez $t8, exc_loop nop - la $v0, PORTB - li $v1, (1 << 11) /* PORTB<11> = RB11 */ + la $v0, PORTA + li $v1, (1 << 2) /* PORTA<2> = RA2 */ sw $v1, INV($v0) j exception_handler nop