Last active
February 19, 2019 03:24
-
-
Save chrisgward/6af26dafa5bf6ed7313116e5ec11a2d3 to your computer and use it in GitHub Desktop.
LCD library for STM32L476VG Discovery
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/* | |
* ---------------------------------------------------------------------------- | |
* "THE BEER-WARE LICENSE" (Revision 42): | |
* Chris Ward <[email protected]> wrote this file. As long as you retain | |
* this notice you can do whatever you want with this stuff. If we meet some | |
* day, and you think this stuff is worth it, you can buy me a beer in return. | |
* ---------------------------------------------------------------------------- | |
*/ | |
.syntax unified | |
.section .rodata | |
// CCSSSSSS (CC = com bits, 0-3, SSSSSS = seg number (0-63)) | |
.macro segment com seg | |
.byte \com << 6 | \seg | |
.endm | |
.global lcd_segmap | |
.global lcd_seg0 | |
.global lcd_seg1 | |
.global lcd_seg2 | |
.global lcd_seg3 | |
.global lcd_seg4 | |
.global lcd_seg5 | |
.global lcd_bars | |
lcd_segmap: | |
.align 4 | |
lcd_seg0: | |
segment 1 22 // a | |
segment 0 22 // b | |
segment 1 23 // c | |
segment 1 4 // d | |
segment 0 4 // e | |
segment 1 3 // f | |
segment 0 3 // g1 | |
segment 0 23 // g2 | |
segment 3 3 // h | |
segment 3 22 // i | |
segment 2 22 // j | |
segment 2 3 // k | |
segment 2 4 // l | |
segment 3 4 // m | |
segment 2 23 // colon | |
segment 3 23 // dp | |
lcd_seg1: | |
segment 1 12 // a | |
segment 0 12 // b | |
segment 1 13 // c | |
segment 1 6 // d | |
segment 0 6 // e | |
segment 1 5 // f | |
segment 0 5 // g1 | |
segment 0 13 // g2 | |
segment 3 5 // h | |
segment 3 12 // i | |
segment 2 12 // j | |
segment 2 5 // k | |
segment 2 6 // l | |
segment 3 6 // m | |
segment 2 13 // colon | |
segment 3 13 // dp | |
lcd_seg2: | |
segment 1 28 // a | |
segment 0 28 // b | |
segment 1 29 // c | |
segment 1 15 // d | |
segment 0 15 // e | |
segment 1 14 // f | |
segment 0 14 // g1 | |
segment 0 29// g2 | |
segment 3 14 // h | |
segment 3 28 // i | |
segment 2 28 // j | |
segment 2 14 // k | |
segment 2 15 // l | |
segment 3 15 // m | |
segment 2 29 // colon | |
segment 3 29 // dp | |
lcd_seg3: | |
segment 1 32 // a | |
segment 0 32 // b | |
segment 1 33 // c | |
segment 1 31 // d | |
segment 0 31 // e | |
segment 1 30 // f | |
segment 0 30 // g1 | |
segment 0 33 // g2 | |
segment 3 30 // h | |
segment 3 32 // i | |
segment 2 32 // j | |
segment 2 30 // k | |
segment 2 31 // l | |
segment 3 31 // m | |
segment 2 33 // colon | |
segment 3 33 // dp | |
lcd_seg4: | |
segment 1 24 // a | |
segment 0 24 // b | |
segment 1 25 // c | |
segment 1 35 // d | |
segment 0 35 // e | |
segment 1 34 // f | |
segment 0 34 // g1 | |
segment 0 25 // g2 | |
segment 3 34// h | |
segment 3 24 // i | |
segment 2 24 // j | |
segment 2 34 // k | |
segment 2 35 // l | |
segment 3 35 // m | |
segment 0 0 // colon | |
segment 0 0 // dp | |
lcd_seg5: | |
segment 1 9 // a | |
segment 0 9 // b | |
segment 1 8 // c | |
segment 1 17 // d | |
segment 0 17 // e | |
segment 1 26 // f | |
segment 0 26 // g1 | |
segment 0 8 // g2 | |
segment 3 26 // h | |
segment 3 9 // i | |
segment 2 9 // j | |
segment 2 26 // k | |
segment 2 17 // l | |
segment 3 17 // m | |
segment 0 0 // colon | |
segment 0 0 // dp | |
lcd_bars: | |
segment 2 25 | |
segment 3 25 | |
segment 2 8 | |
segment 3 8 | |
lcd_font: | |
// ABCDEFGGHIJKLMCD | |
.hword 0b0000000000000000 // 20 (space) | |
.hword 0b1111111111111100 // 21 ! (light em up) | |
.hword 0b0100000001000000 // 22 " | |
.hword 0b0111001101001000 // 23 # | |
.hword 0b1011011101001000 // 24 $ | |
// ABCDEFGGHIJKLMCD | |
.hword 0b0010011111111100 // 25 % | |
.hword 0b1001101011000100 // 26 & | |
.hword 0b0000000001000000 // 27 ' | |
.hword 0b0000000000100100 // 28 ( | |
.hword 0b0000000010010000 // 29 ) | |
// ABCDEFGGHIJKLMCD | |
.hword 0b0000001111111100 // 2A * | |
.hword 0b0000001101001000 // 2B + | |
.hword 0b0000000000010000 // 2C , | |
.hword 0b0000001100000000 // 2D - | |
// ABCDEFGGHIJKLMCD | |
.hword 0b0000000000000001 // 2E . | |
.hword 0b0000000000110000 // 2F / | |
.hword 0b1111110000000000 // 30 0 | |
.hword 0b0110000000100000 // 31 1 | |
.hword 0b1101101100000000 // 32 2 | |
// ABCDEFGGHIJKLMCD | |
.hword 0b1111001100000000 // 33 3 | |
.hword 0b0110011100000000 // 34 4 | |
.hword 0b1011011100000000 // 35 5 | |
.hword 0b1011111100000000 // 36 6 | |
.hword 0b1110000000000000 // 37 7 | |
// ABCDEFGGHIJKLMCD | |
.hword 0b1111111100000000 // 38 8 | |
.hword 0b1111011100000000 // 39 9 | |
.hword 0b0000000000000010 // 3A : | |
.hword 0b0000000001010000 // 3B ; | |
.hword 0b0000001000100100 // 3C < | |
// ABCDEFGGHIJKLMCD | |
.hword 0b0001001100000000 // 3D = | |
.hword 0b0000000110010000 // 3E > | |
.hword 0b1100010100001000 // 3F ? | |
.hword 0b1101110101000000 // 40 @ | |
.hword 0b1110111100000000 // 41 A | |
// ABCDEFGGHIJKLMCD | |
.hword 0b1111000101001000 // 42 B | |
.hword 0b1001110000000000 // 43 C | |
.hword 0b1111000001001000 // 44 D | |
.hword 0b1001111000000000 // 45 E | |
.hword 0b1000111000000000 // 46 F | |
// ABCDEFGGHIJKLMCD | |
.hword 0b1011110100000000 // 47 G | |
.hword 0b0110111100000000 // 48 H | |
.hword 0b1001000001001000 // 49 I | |
.hword 0b0111100000000000 // 4A J | |
.hword 0b0000111000100100 // 4B K | |
// ABCDEFGGHIJKLMCD | |
.hword 0b0001110000000000 // 4C L | |
.hword 0b0110110010100000 // 4D M | |
.hword 0b0110110010000100 // 4E N | |
.hword 0b1111110000000000 // 4F O | |
.hword 0b1100111100000000 // 50 P | |
// ABCDEFGGHIJKLMCD | |
.hword 0b1111110000000100 // 51 Q | |
.hword 0b1100111100000100 // 52 R | |
.hword 0b1011011100000000 // 53 S | |
.hword 0b1000000001001000 // 54 T | |
.hword 0b0111110000000000 // 55 U | |
// ABCDEFGGHIJKLMCD | |
.hword 0b0000110000110000 // 56 V | |
.hword 0b0110110000010100 // 57 W | |
.hword 0b0000000010110100 // 58 X | |
.hword 0b0111011100000000 // 59 Y | |
.hword 0b1001000000110000 // 5A Z | |
// ABCDEFGGHIJKLMCD | |
.hword 0b1001110000000000 // 5B [ | |
.hword 0b0000000010000100 // 5C backslash | |
.hword 0b1111000000000000 // 5D ] | |
.hword 0b0000000000010100 // 5E ^ | |
.hword 0b0001000000000000 // 5F _ | |
// ABCDEFGGHIJKLMCD | |
.hword 0b0000000010000000 // 60 ` | |
.hword 0b0001101000001000 // 61 a | |
.hword 0b0011111100000000 // 62 b | |
.hword 0b0001101100000000 // 63 c | |
.hword 0b0111101100000000 // 64 d | |
// ABCDEFGGHIJKLMCD | |
.hword 0b0001101000010000 // 65 e | |
.hword 0b0000001100101000 // 66 f | |
.hword 0b0111000100100000 // 67 g | |
.hword 0b0010111100000000 // 68 h | |
.hword 0b0000000000001000 // 69 i | |
// ABCDEFGGHIJKLMCD | |
.hword 0b0000100001010000 // 6A j | |
.hword 0b0000111000100100 // 6B k | |
.hword 0b0000110000000000 // 6C l | |
.hword 0b0010101100001000 // 6D m | |
.hword 0b0010101100000000 // 6E n | |
// ABCDEFGGHIJKLMCD | |
.hword 0b0011101100000000 // 6F o | |
.hword 0b1100111100000000 // 70 p | |
.hword 0b1110011100000000 // 71 q | |
.hword 0b0000101100000000 // 72 r | |
.hword 0b1011011100000000 // 73 s | |
// ABCDEFGGHIJKLMCD | |
.hword 0b0001111000000000 // 74 t | |
.hword 0b0011100000000000 // 75 u | |
.hword 0b0000110000110000 // 76 v | |
.hword 0b0010100000010100 // 77 w | |
.hword 0b0000000010110100 // 78 x | |
// ABCDEFGGHIJKLMCD | |
.hword 0b0111000101000000 // 79 y | |
.hword 0b1001000000110000 // 7A z | |
.hword 0b1001001010010000 // 7B { | |
.hword 0b0000000001001000 // 7C | | |
.hword 0b1001000100100100 // 7D } | |
.hword 0b0010101000000100 // 7E - | |
// 7F DEL | |
.text | |
.macro lcd_gpio pin | |
ldr r1, [r0] // set alternate flag on pins | |
orr r1, 1<<(\pin*2+1) | |
bic r1, 1<<(\pin*2) | |
str r1, [r0] | |
.if \pin < 8 // afrh/l | |
ldr r1, [r0, 0x20] | |
.else | |
ldr r1, [r0, 0x24] | |
.endif | |
mov r2, 0xF << ((\pin % 8) * 4) | |
bic r1, r2 // clear all relevant bits | |
mov r2, 11 << ((\pin % 8) * 4)// set the bits for LCD | |
orr r1,r2 | |
.if \pin < 8 | |
str r1, [r0, 0x20] // store | |
.else | |
str r1, [r0, 0x24] | |
.endif | |
.endm | |
.global lcd_setup | |
.type lcd_setup,%function | |
lcd_setup: | |
push {r0-r2,lr} | |
ldr r0, =0x40021000 // RCC | |
ldr r1, [r0, 0x4C] // enable GPIO port clocks | |
orr r1, 0b1111 // ports A-D | |
str r1, [r0, 0x4C] | |
ldr r1, [r0, 0x58] // enable LCD (9) and PWR (28) clocks | |
orr r1, 1<<9 | |
orr r1, 1<<28 | |
str r1, [r0, 0x58] | |
ldr r1, [r0, 0x94] // enable LSI clock | |
orr r1, 1<<0 | |
str r1, [r0, 0x94] | |
ldr r0, =#0x40007000 // PWR controller base | |
ldr r1, [r0] | |
orr r1, 1<<8 // unlock RTC/Backup registers | |
str r1, [r0] | |
ldr r0, =0x40021000 // RCC | |
ldr r1, [r0, 0x90] | |
orr r1, 1<<9 | |
bic r1, 1<<8 // select LSI clock for LCD/RTC clock source | |
str r1, [r0, 0x90] | |
ldr r0, =#0x40007000 // PWR controller base | |
ldr r1, [r0] | |
bic r1, 1<<8 // lock RTC registers | |
str r1, [r0] | |
ldr r0,=0x48000000 // port a | |
lcd_gpio 6 // SEG23 SEG3 | |
lcd_gpio 7 // SEG0 SEG4 | |
lcd_gpio 8 // COM0 COM0 | |
lcd_gpio 9 // COM1 COM1 | |
lcd_gpio 10 // COM2 COM2 | |
lcd_gpio 15 // SEG10 SEG17 | |
ldr r0,=0x48000400 // pb | |
lcd_gpio 0 // SEG21 SEG5 | |
lcd_gpio 1 // SEG2 SEG6 | |
lcd_gpio 4 // SEG11 SEG8 | |
lcd_gpio 5 // SEG12 SEG9 | |
lcd_gpio 9 // COM3 COM3 | |
lcd_gpio 12 // SEG20 SEG12 | |
lcd_gpio 13 // SEG3 SEG13 | |
lcd_gpio 14 // SEG19 SEG14 | |
lcd_gpio 15 // SEG4 SEG15 | |
ldr r0,=0x48000800 // pc | |
lcd_gpio 3 // VLCD VLCD | |
lcd_gpio 4 // SEG22 SEG22 | |
lcd_gpio 5 // SEG1 SEG23 | |
lcd_gpio 6 // SEG14 SEG24 | |
lcd_gpio 7 // SEG9 SEG25 | |
lcd_gpio 8 // SEG13 SEG26 | |
ldr r0,=0x48000C00 // pd | |
lcd_gpio 8 // SEG18 SEG28 | |
lcd_gpio 9 // SEG5 SEG29 | |
lcd_gpio 10 // SEG17 SEG30 | |
lcd_gpio 11 // SEG6 SEG31 | |
lcd_gpio 12 // SEG16 SEG32 | |
lcd_gpio 13 // SEG7 SEG33 | |
lcd_gpio 14 // SEG15 SEG34 | |
lcd_gpio 15 // SEG8 SEG35 | |
ldr r1, =#0x40002400 // LCD base | |
ldr r2, [r1] @LCD Control reg | |
orr r2, #(0b011<<2) @ duty cycle bits | |
orr r2, #(0b01<<5) @Bias bits | |
str r2, [r1] | |
@frame rate & contrast setup | |
ldr r2, [r1,0x04] @Frame control reg | |
orr r2, #(0b0011<<22) @Framerate Prescaler (PS) | |
orr r2, #(0b0100<<18) @Framrate Divisor (DIV) | |
orr r2, #(0b000<<10) @constrast (CON) | |
orr r2, #(0b100<<4) @Pulse ON duration (PON) | |
str r2, [r1,0x04] | |
ldr r2, [r1] @LCD Control reg | |
orr r2, #0x01 @Enable the LCD Controller (LCDEN) | |
str r2, [r1] | |
bl lcd_wait_for_ready | |
bl lcd_clear | |
pop {r0-r2,lr} | |
bx lr | |
.size lcd_setup,.-lcd_setup | |
.global lcd_update | |
.type lcd_update,%function | |
lcd_update: | |
push {r0-r1,lr} | |
bl lcd_wait_for_ready | |
ldr r0, =0x40002400 | |
ldr r1, [r0,0x08] @LCD status reg | |
orr r1, #(1<<2) @Update screen request (UDR) bit | |
str r1, [r0,0x08] | |
pop {r0-r1,lr} | |
bx lr | |
.size lcd_update,.-lcd_update | |
.global lcd_clear | |
.type lcd_clear,%function | |
lcd_clear: | |
push {r0,r1,lr} | |
ldr r0, =#0x40002400 // LCD base | |
ldr r1, =0 | |
str r1, [r0,0x14] @com0 segment ram | |
str r1, [r0,0x18] @com0 segment ram | |
str r1, [r0,0x1c] @com1 segment ram | |
str r1, [r0,0x20] @com1 segment ram | |
str r1, [r0,0x24] @com2 segment ram | |
str r1, [r0,0x28] @com2 segment ram | |
str r1, [r0,0x2c] @com3 segment ram | |
str r1, [r0,0x30] @com3 segment ram | |
//bl lcd_update | |
pop {r0,r1,lr} | |
bx lr | |
.size lcd_clear,.-lcd_clear | |
.global lcd_wait_for_ready | |
.type lcd_wait_for_ready,%function | |
lcd_wait_for_ready: | |
push {r0,r1,r2} | |
lcd_wait_for_ready_loop: | |
ldr r0, =0x40002400 | |
ldr r1, [r0, 0x8] | |
ands r1, 1<<2 | |
bne lcd_wait_for_ready_loop | |
pop {r0,r1,r2} | |
bx lr | |
.size lcd_wait_for_ready,.-lcd_wait_for_ready | |
// r0 -> [CCSSSSSS] | |
.macro lcd_segment_op name op | |
.global lcd_\name\()_segment | |
.type lcd_\name\()_segment,%function | |
lcd_\name\()_segment: | |
push {r0-r5,lr} | |
ldr r0,[r0] | |
and r2,r0,0b111111 // seg | |
and r1,r0,3<<6 | |
lsr r1,6 // com | |
ldr r3,=#0x40002414 | |
cmp r2,32 | |
blt lcd_set_segment_seg_lt_32\name\() | |
lcd_set_segment_seg_ge_32\name\(): | |
sub r2,32 | |
add r3,4 | |
lcd_set_segment_seg_lt_32\name\(): | |
mov r4,1 // seg | |
lsl r4,r2 | |
mov r5,8 | |
mul r1,r5 | |
add r3,r1 | |
ldr r5,[r3] | |
\op r5,r4 | |
str r5,[r3] | |
//bl lcd_update | |
pop {r0-r5,lr} | |
bx lr | |
.size lcd_\name\()_segment,.-lcd_\name\()_segment | |
.endm | |
lcd_segment_op set orr | |
lcd_segment_op clear bic | |
lcd_segment_op toggle eor | |
.global lcd_set_character | |
// r0 -> seg number (0-5) | |
// r1 -> char (0-255) | |
lcd_set_character: | |
cmp r1,0x1F | |
it le | |
bxle lr // do nothing | |
push {r0-r6,lr} | |
sub r1,0x20 | |
add r1,r1 | |
ldr r2, =lcd_font | |
add r2,r1 | |
ldrh r2,[r2] // font in r2 | |
ldr r3, =lcd_segmap // segmap + 16 * r0 = start address of segments | |
mov r4, 16 | |
mul r4, r0 | |
add r3, r4 // address of segment map | |
mov r0,r3 // r0 = address of segment map | |
mov r5, 1<<15 // leftmost bit in font | |
loop: | |
ands r6,r5,r2 | |
it ne | |
blne lcd_set_segment | |
add r0,1 | |
lsrs r5, 1 | |
beq done | |
b loop | |
done: | |
pop {r0-r6,lr} | |
bx lr | |
.size lcd_set_character,.-lcd_set_character | |
// r0 -> address of string | |
// r1 -> first segment | |
.global lcd_set_string_at | |
.type lcd_set_string_at,%function | |
lcd_set_string_at: | |
push {r0-r2,lr} | |
b lcd_set_string_loop | |
.size lcd_set_string_at,.-lcd_set_string | |
// r0 -> address of string | |
.global lcd_set_string | |
.type lcd_set_string,%function | |
lcd_set_string: | |
push {r0-r2,lr} | |
mov r1,0 | |
lcd_set_string_loop: | |
ldrb r2,[r0] // r2 = character | |
cmp r2,0 | |
beq lcd_set_string_done // if nul, end | |
cmp r1,6 // if end of screen, end | |
beq lcd_set_string_done | |
push {r0,r1} | |
mov r0,r1 | |
mov r1,r2 | |
bl lcd_set_character | |
pop {r0,r1} | |
add r0,1 | |
add r1,1 | |
b lcd_set_string_loop | |
lcd_set_string_done: | |
pop {r0-r2,lr} | |
bx lr | |
.size lcd_set_string,.-lcd_set_string | |
.data | |
lcd_itoa_buf: | |
.word 0,0 | |
.text | |
// r0 -> integer to display | |
.global lcd_set_integer | |
.type lcd_set_integer,%function | |
lcd_set_integer: | |
push {r1-r2,lr} | |
ldr r1,=lcd_itoa_buf | |
mov r2,10 | |
bl itoa // sneaky c | |
pop {r1-r2,lr} | |
b lcd_set_string | |
.size lcd_set_integer,.-lcd_set_integer |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment