Initial import

This commit is contained in:
Daniele Lacamera 2020-04-06 21:08:01 +02:00
commit 22ff79dcdf
43 changed files with 7123 additions and 0 deletions

4
.gdbinit Normal file
View file

@ -0,0 +1,4 @@
tar rem:3333
file image.elf
foc c

6
.gitignore vendored Normal file
View file

@ -0,0 +1,6 @@
*.o
*.bin
image.elf
image.map
tags
core

3
.gitmodules vendored Normal file
View file

@ -0,0 +1,3 @@
[submodule "lib/unicore-mx"]
path = lib/unicore-mx
url = https://gitlab.com/insane-adding-machines/unicore-mx.git

339
LICENSE Normal file
View file

@ -0,0 +1,339 @@
GNU GENERAL PUBLIC LICENSE
Version 2, June 1991
Copyright (C) 1989, 1991 Free Software Foundation, Inc.,
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
Everyone is permitted to copy and distribute verbatim copies
of this license document, but changing it is not allowed.
Preamble
The licenses for most software are designed to take away your
freedom to share and change it. By contrast, the GNU General Public
License is intended to guarantee your freedom to share and change free
software--to make sure the software is free for all its users. This
General Public License applies to most of the Free Software
Foundation's software and to any other program whose authors commit to
using it. (Some other Free Software Foundation software is covered by
the GNU Lesser General Public License instead.) You can apply it to
your programs, too.
When we speak of free software, we are referring to freedom, not
price. Our General Public Licenses are designed to make sure that you
have the freedom to distribute copies of free software (and charge for
this service if you wish), that you receive source code or can get it
if you want it, that you can change the software or use pieces of it
in new free programs; and that you know you can do these things.
To protect your rights, we need to make restrictions that forbid
anyone to deny you these rights or to ask you to surrender the rights.
These restrictions translate to certain responsibilities for you if you
distribute copies of the software, or if you modify it.
For example, if you distribute copies of such a program, whether
gratis or for a fee, you must give the recipients all the rights that
you have. You must make sure that they, too, receive or can get the
source code. And you must show them these terms so they know their
rights.
We protect your rights with two steps: (1) copyright the software, and
(2) offer you this license which gives you legal permission to copy,
distribute and/or modify the software.
Also, for each author's protection and ours, we want to make certain
that everyone understands that there is no warranty for this free
software. If the software is modified by someone else and passed on, we
want its recipients to know that what they have is not the original, so
that any problems introduced by others will not reflect on the original
authors' reputations.
Finally, any free program is threatened constantly by software
patents. We wish to avoid the danger that redistributors of a free
program will individually obtain patent licenses, in effect making the
program proprietary. To prevent this, we have made it clear that any
patent must be licensed for everyone's free use or not licensed at all.
The precise terms and conditions for copying, distribution and
modification follow.
GNU GENERAL PUBLIC LICENSE
TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
0. This License applies to any program or other work which contains
a notice placed by the copyright holder saying it may be distributed
under the terms of this General Public License. The "Program", below,
refers to any such program or work, and a "work based on the Program"
means either the Program or any derivative work under copyright law:
that is to say, a work containing the Program or a portion of it,
either verbatim or with modifications and/or translated into another
language. (Hereinafter, translation is included without limitation in
the term "modification".) Each licensee is addressed as "you".
Activities other than copying, distribution and modification are not
covered by this License; they are outside its scope. The act of
running the Program is not restricted, and the output from the Program
is covered only if its contents constitute a work based on the
Program (independent of having been made by running the Program).
Whether that is true depends on what the Program does.
1. You may copy and distribute verbatim copies of the Program's
source code as you receive it, in any medium, provided that you
conspicuously and appropriately publish on each copy an appropriate
copyright notice and disclaimer of warranty; keep intact all the
notices that refer to this License and to the absence of any warranty;
and give any other recipients of the Program a copy of this License
along with the Program.
You may charge a fee for the physical act of transferring a copy, and
you may at your option offer warranty protection in exchange for a fee.
2. You may modify your copy or copies of the Program or any portion
of it, thus forming a work based on the Program, and copy and
distribute such modifications or work under the terms of Section 1
above, provided that you also meet all of these conditions:
a) You must cause the modified files to carry prominent notices
stating that you changed the files and the date of any change.
b) You must cause any work that you distribute or publish, that in
whole or in part contains or is derived from the Program or any
part thereof, to be licensed as a whole at no charge to all third
parties under the terms of this License.
c) If the modified program normally reads commands interactively
when run, you must cause it, when started running for such
interactive use in the most ordinary way, to print or display an
announcement including an appropriate copyright notice and a
notice that there is no warranty (or else, saying that you provide
a warranty) and that users may redistribute the program under
these conditions, and telling the user how to view a copy of this
License. (Exception: if the Program itself is interactive but
does not normally print such an announcement, your work based on
the Program is not required to print an announcement.)
These requirements apply to the modified work as a whole. If
identifiable sections of that work are not derived from the Program,
and can be reasonably considered independent and separate works in
themselves, then this License, and its terms, do not apply to those
sections when you distribute them as separate works. But when you
distribute the same sections as part of a whole which is a work based
on the Program, the distribution of the whole must be on the terms of
this License, whose permissions for other licensees extend to the
entire whole, and thus to each and every part regardless of who wrote it.
Thus, it is not the intent of this section to claim rights or contest
your rights to work written entirely by you; rather, the intent is to
exercise the right to control the distribution of derivative or
collective works based on the Program.
In addition, mere aggregation of another work not based on the Program
with the Program (or with a work based on the Program) on a volume of
a storage or distribution medium does not bring the other work under
the scope of this License.
3. You may copy and distribute the Program (or a work based on it,
under Section 2) in object code or executable form under the terms of
Sections 1 and 2 above provided that you also do one of the following:
a) Accompany it with the complete corresponding machine-readable
source code, which must be distributed under the terms of Sections
1 and 2 above on a medium customarily used for software interchange; or,
b) Accompany it with a written offer, valid for at least three
years, to give any third party, for a charge no more than your
cost of physically performing source distribution, a complete
machine-readable copy of the corresponding source code, to be
distributed under the terms of Sections 1 and 2 above on a medium
customarily used for software interchange; or,
c) Accompany it with the information you received as to the offer
to distribute corresponding source code. (This alternative is
allowed only for noncommercial distribution and only if you
received the program in object code or executable form with such
an offer, in accord with Subsection b above.)
The source code for a work means the preferred form of the work for
making modifications to it. For an executable work, complete source
code means all the source code for all modules it contains, plus any
associated interface definition files, plus the scripts used to
control compilation and installation of the executable. However, as a
special exception, the source code distributed need not include
anything that is normally distributed (in either source or binary
form) with the major components (compiler, kernel, and so on) of the
operating system on which the executable runs, unless that component
itself accompanies the executable.
If distribution of executable or object code is made by offering
access to copy from a designated place, then offering equivalent
access to copy the source code from the same place counts as
distribution of the source code, even though third parties are not
compelled to copy the source along with the object code.
4. You may not copy, modify, sublicense, or distribute the Program
except as expressly provided under this License. Any attempt
otherwise to copy, modify, sublicense or distribute the Program is
void, and will automatically terminate your rights under this License.
However, parties who have received copies, or rights, from you under
this License will not have their licenses terminated so long as such
parties remain in full compliance.
5. You are not required to accept this License, since you have not
signed it. However, nothing else grants you permission to modify or
distribute the Program or its derivative works. These actions are
prohibited by law if you do not accept this License. Therefore, by
modifying or distributing the Program (or any work based on the
Program), you indicate your acceptance of this License to do so, and
all its terms and conditions for copying, distributing or modifying
the Program or works based on it.
6. Each time you redistribute the Program (or any work based on the
Program), the recipient automatically receives a license from the
original licensor to copy, distribute or modify the Program subject to
these terms and conditions. You may not impose any further
restrictions on the recipients' exercise of the rights granted herein.
You are not responsible for enforcing compliance by third parties to
this License.
7. If, as a consequence of a court judgment or allegation of patent
infringement or for any other reason (not limited to patent issues),
conditions are imposed on you (whether by court order, agreement or
otherwise) that contradict the conditions of this License, they do not
excuse you from the conditions of this License. If you cannot
distribute so as to satisfy simultaneously your obligations under this
License and any other pertinent obligations, then as a consequence you
may not distribute the Program at all. For example, if a patent
license would not permit royalty-free redistribution of the Program by
all those who receive copies directly or indirectly through you, then
the only way you could satisfy both it and this License would be to
refrain entirely from distribution of the Program.
If any portion of this section is held invalid or unenforceable under
any particular circumstance, the balance of the section is intended to
apply and the section as a whole is intended to apply in other
circumstances.
It is not the purpose of this section to induce you to infringe any
patents or other property right claims or to contest validity of any
such claims; this section has the sole purpose of protecting the
integrity of the free software distribution system, which is
implemented by public license practices. Many people have made
generous contributions to the wide range of software distributed
through that system in reliance on consistent application of that
system; it is up to the author/donor to decide if he or she is willing
to distribute software through any other system and a licensee cannot
impose that choice.
This section is intended to make thoroughly clear what is believed to
be a consequence of the rest of this License.
8. If the distribution and/or use of the Program is restricted in
certain countries either by patents or by copyrighted interfaces, the
original copyright holder who places the Program under this License
may add an explicit geographical distribution limitation excluding
those countries, so that distribution is permitted only in or among
countries not thus excluded. In such case, this License incorporates
the limitation as if written in the body of this License.
9. The Free Software Foundation may publish revised and/or new versions
of the General Public License from time to time. Such new versions will
be similar in spirit to the present version, but may differ in detail to
address new problems or concerns.
Each version is given a distinguishing version number. If the Program
specifies a version number of this License which applies to it and "any
later version", you have the option of following the terms and conditions
either of that version or of any later version published by the Free
Software Foundation. If the Program does not specify a version number of
this License, you may choose any version ever published by the Free Software
Foundation.
10. If you wish to incorporate parts of the Program into other free
programs whose distribution conditions are different, write to the author
to ask for permission. For software which is copyrighted by the Free
Software Foundation, write to the Free Software Foundation; we sometimes
make exceptions for this. Our decision will be guided by the two goals
of preserving the free status of all derivatives of our free software and
of promoting the sharing and reuse of software generally.
NO WARRANTY
11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN
OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS
TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE
PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
REPAIR OR CORRECTION.
12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
POSSIBILITY OF SUCH DAMAGES.
END OF TERMS AND CONDITIONS
How to Apply These Terms to Your New Programs
If you develop a new program, and you want it to be of the greatest
possible use to the public, the best way to achieve this is to make it
free software which everyone can redistribute and change under these terms.
To do so, attach the following notices to the program. It is safest
to attach them to the start of each source file to most effectively
convey the exclusion of warranty; and each file should have at least
the "copyright" line and a pointer to where the full notice is found.
<one line to give the program's name and a brief idea of what it does.>
Copyright (C) <year> <name of author>
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 2 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, write to the Free Software Foundation, Inc.,
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
Also add information on how to contact you by electronic and paper mail.
If the program is interactive, make it output a short notice like this
when it starts in an interactive mode:
Gnomovision version 69, Copyright (C) year name of author
Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
This is free software, and you are welcome to redistribute it
under certain conditions; type `show c' for details.
The hypothetical commands `show w' and `show c' should show the appropriate
parts of the General Public License. Of course, the commands you use may
be called something other than `show w' and `show c'; they could even be
mouse-clicks or menu items--whatever suits your program.
You should also get your employer (if you work as a programmer) or your
school, if any, to sign a "copyright disclaimer" for the program, if
necessary. Here is a sample; alter the names:
Yoyodyne, Inc., hereby disclaims all copyright interest in the program
`Gnomovision' (which makes passes at compilers) written by James Hacker.
<signature of Ty Coon>, 1 April 1989
Ty Coon, President of Vice
This General Public License does not permit incorporating your program into
proprietary programs. If your program is a subroutine library, you may
consider it more useful to permit linking proprietary applications with the
library. If this is what you want to do, use the GNU Lesser General
Public License instead of this License.

46
Makefile Normal file
View file

@ -0,0 +1,46 @@
CROSS_COMPILE:=arm-none-eabi-
CC:=$(CROSS_COMPILE)gcc
LD:=$(CROSS_COMPILE)gcc
VERSION?=1
OBJS:=startup.o main.o system.o mem.o led.o \
i2c.o display.o font_twisted.o button.o systick.o newlib.o uart.o ui.o timer.o\
mutex.o ui_drone.o adc.o spi.o pot.o dac.o sound.o
UMX:=lib/unicore-mx/lib/libucmx_stm32f4.a
UMXFLAGS:=-Ilib/unicore-mx/include/ -DSTM32F4
LIBS+=$(UMX)
LSCRIPT:=target.ld
OBJCOPY:=$(CROSS_COMPILE)objcopy
CFLAGS:=-mcpu=cortex-m3 -mthumb -Wall -Wno-main -Wstack-usage=320 \
-ffreestanding -Wno-unused -DBLOCK_SIZE=4096 -I. -Ilib/unicore-mx/include \
-ffunction-sections -fdata-sections
CFLAGS+=-specs=nano.specs -lc -lg
CFLAGS+=$(UMXFLAGS)
#CFLAGS+=-O3
CFLAGS+=-g -ggdb3
ASFLAGS:=$(CFLAGS)
LDFLAGS:=-T $(LSCRIPT) -Wl,-gc-sections -Wl,-Map=image.map -mcpu=cortex-m3 -mthumb -nostartfiles
#all: image.bin
image.bin: image.elf
$(OBJCOPY) -O binary $^ $@
image.elf: $(LIBS) $(OBJS) $(LSCRIPT)
$(LD) $(LDFLAGS) $(OBJS) $(LIBS) -o $@
$(UMX):
make -C lib/unicore-mx FP_FLAGS="-O3 -mfloat-abi=soft" TARGETS=stm32/f4
clean:
@rm -f image.bin image.elf *.o image.map $(USECFS)/src/*.o
make -C lib/unicore-mx clean

57
adc.c Normal file
View file

@ -0,0 +1,57 @@
/*
*
* Copyright (c) 2019
* Author: Daniele Lacamera <root@danielinux.net>
* GPL2.0
*/
#include <stdint.h>
#include "adc.h"
#include "system.h"
int adc_init(void)
{
int i;
uint32_t val;
/* Enable clock */
APB2_CLOCK_ER |= ADC1_APB2_CLOCK_ER_VAL;
/* Power off */
ADC1_CR2 &= ~(ADC_CR2_EN);
/* Set common clock prescaler */
ADC_COM_CCR &= ~(0x03 << 16);
/* Disable scan mode */
ADC1_CR1 &= ~(ADC_CR1_SCAN);
/* Set one-shot (disable continuous mode) */
ADC1_CR2 &= ~(ADC_CR2_CONT);
/* Set sample time for all channels */
val = ADC1_SMPR1;
for (i = 0; i < 10; i++) {
val |= ADC_SMPR_SMP_480CYC << (i * 3);
ADC1_SMPR1 = val;
val = ADC1_SMPR2;
for (i = 10; i < 18; i++)
val |= ADC_SMPR_SMP_480CYC << ((i-10) * 3);
}
ADC1_SMPR2 = val;
ADC1_CR2 &= ~(ADC_CR2_EN);
return 0;
}
void adc_pin_val(uint32_t ch, uint16_t *val)
{
ADC1_SQR3 = ch;
ADC1_CR2 |= ADC_CR2_EN;
ADC1_CR2 |= ADC_CR2_SWSTART;
while (ADC1_CR2 & ADC_CR2_SWSTART);;
while ((ADC1_SR & ADC_SR_EOC) == 0);;
*val= ADC1_DR;
printf("Channel %d val %hu\r\n", ch, *val);
ADC1_SQR3 = 0;
}

6
adc.h Normal file
View file

@ -0,0 +1,6 @@
#ifndef ADC_H_INCLUDED
#define ADC_H_INCLUDED
int adc_init(void);
int adc_read(void);
void adc_pin_val(uint32_t pin, uint16_t *val);
#endif

221
button.c Normal file
View file

@ -0,0 +1,221 @@
/*
* (c) danielinux 2019
* GPLv.2
*
* See LICENSE for details
*/
#include <stdio.h>
#include <stdint.h>
#include <stdlib.h>
#include <string.h>
#include "system.h"
#include "button.h"
#include "systick.h"
#include "unicore-mx/stm32/gpio.h"
#include "unicore-mx/stm32/exti.h"
#include "unicore-mx/stm32/rcc.h"
#include "unicore-mx/stm32/f4/rcc.h"
#include "unicore-mx/stm32/adc.h"
#include "unicore-mx/stm32/f4/adc.h"
#include "unicore-mx/stm32/f4/nvic.h"
// Uncomment to enable debug
//#define BUTTON_DEBUG
enum button_state {
IDLE = 0,
PRESSING,
PRESSED,
HOLD,
RELEASING,
};
#ifdef BUTTON_DEBUG
# define DBG printf
#else
# define DBG(...) do {} while (0)
#endif
#define BUTTON_DEBOUNCE_TIME 50
#define BUTTON_HOLD_TIME 1500
static volatile int button_press_pending = 0;
#define BUTTON_PLUS '+'
#define BUTTON_MINUS '-'
static void input_run(uint32_t ev, void *arg);
static void input_init(void);
const char button_task_name[] = "Input";
// PA8 + PA9 // ROTARY encoder
// PC0 // BUTTON
//
// TODO:
// C4 + C5 rotary
// B0 + B1 + C3 Buttons (- + RotSW)
//
void pin_exti_init(void)
{
}
void pin_exti_start_read(void)
{
exti_set_trigger(GPIO0|GPIO1|GPIO3|GPIO4|GPIO5, EXTI_TRIGGER_BOTH);
exti_enable_request(GPIO0);
exti_enable_request(GPIO1);
exti_enable_request(GPIO3);
exti_enable_request(GPIO4);
exti_enable_request(GPIO5);
}
static void button_setup(void)
{
rcc_periph_clock_enable(RCC_SYSCFG);
rcc_periph_clock_enable(RCC_GPIOB);
rcc_periph_clock_enable(RCC_GPIOC);
gpio_mode_setup(GPIOC, GPIO_MODE_INPUT, GPIO_PUPD_PULLDOWN, GPIO3 | GPIO4 | GPIO5);
gpio_mode_setup(GPIOB, GPIO_MODE_INPUT, GPIO_PUPD_PULLDOWN, GPIO0 | GPIO1);
nvic_enable_irq(NVIC_EXTI9_5_IRQ);
nvic_enable_irq(NVIC_EXTI0_IRQ);
nvic_enable_irq(NVIC_EXTI1_IRQ);
nvic_enable_irq(NVIC_EXTI3_IRQ);
nvic_enable_irq(NVIC_EXTI4_IRQ);
nvic_set_priority(NVIC_EXTI9_5_IRQ, 1);
nvic_set_priority(NVIC_EXTI0_IRQ, 1);
nvic_set_priority(NVIC_EXTI1_IRQ, 1);
nvic_set_priority(NVIC_EXTI3_IRQ, 1);
nvic_set_priority(NVIC_EXTI4_IRQ, 1);
exti_select_source(GPIO0, GPIOB);
exti_select_source(GPIO1, GPIOB);
exti_select_source(GPIO3, GPIOC);
exti_select_source(GPIO4, GPIOC);
exti_select_source(GPIO5, GPIOC);
}
static volatile uint32_t rot_up = 0;
static volatile uint32_t rot_down = 0;
static void button_start_read(void)
{
exti_set_trigger(GPIO0|GPIO1|GPIO3, EXTI_TRIGGER_RISING);
exti_set_trigger(GPIO4, EXTI_TRIGGER_FALLING);
exti_enable_request(GPIO0);
exti_enable_request(GPIO1);
exti_enable_request(GPIO3);
exti_enable_request(GPIO4);
}
static volatile uint32_t last_rot_ev = 0;
void isr_exti_rot0(void)
{
uint32_t rot_val = gpio_get(GPIOC, GPIO4 | GPIO5);
if ((jiffies - last_rot_ev) > 100) {
if ((rot_val & GPIO4) == 0) {
if ((rot_val & GPIO5) == 0)
rot_down++;
else
rot_up++;
}
}
exti_reset_request(GPIO4);
exti_reset_request(GPIO5);
}
void isr_exti_button(void)
{
uint32_t pending;
pending = (gpio_get(GPIOB, GPIO0|GPIO1));
if ((pending & GPIO0) != 0) {
button_press_pending = '-';
}
if ((pending & GPIO1) != 0) {
button_press_pending = '+';
}
if (!pending) {
pending = (gpio_get(GPIOC, GPIO3));
if ((pending & GPIO3) != 0) {
button_press_pending = '*';
}
}
exti_reset_request(GPIO0);
exti_reset_request(GPIO1);
exti_reset_request(GPIO3);
}
static uint32_t t0s, t0us;
static uint32_t t1s, t1us;
static uint32_t time_diff_ms(uint32_t s_a, uint32_t us_a, uint32_t s_b, uint32_t us_b)
{
uint32_t res = 0;
res = (s_a - s_b) * 1000;
if (us_b > us_a) {
us_a += 1000000;
res -= 1000;
}
res += (us_a - us_b) / 1000;
return res;
}
/* Button interface */
struct user_button
{
enum button_state state;
uint32_t transition_start_timestamp;
};
static struct user_button Buttons[N_BUTTONS];
int button_poll(void (*callback)(uint8_t press, int hold))
{
int b = 0;
int st;
static uint32_t last_event = 0;
static uint32_t pressed_start = 0;
while(rot_down > 0) {
callback('D',0);
rot_down--;
}
while(rot_up > 0) {
callback('U',0);
rot_up--;
}
if (jiffies - last_event < BUTTON_DEBOUNCE_TIME)
return;
last_event = jiffies;
st = !!(gpio_get(GPIOB, GPIO0 | GPIO1) | gpio_get(GPIOC, GPIO3));
if (!st) {
pressed_start = 0;
}
if ((button_press_pending) && st) {
if ((pressed_start == 0) || ((jiffies - pressed_start) > BUTTON_HOLD_TIME)) {
pressed_start = jiffies;
callback(button_press_pending, 0);
return 1;
}
}
button_press_pending = 0;
return 0;
}
void button_init(void)
{
memset(Buttons, 0, sizeof(struct user_button) * N_BUTTONS);
button_setup();
button_start_read();
}

16
button.h Normal file
View file

@ -0,0 +1,16 @@
#ifndef BUTTON_H_INCLUDED
#define BUTTON_H_INCLUDED
#include "unicore-mx/stm32/gpio.h"
static const uint32_t Channel[5] = { 8, 9, 7, 6, 5 };
static const uint32_t Channel_Pin[5] = { GPIO8, GPIO9, GPIO7, GPIO6, GPIO5 };
static const char Channel_name[5][16] = { "Red", "Purple", "Green", "Blue", "Yellow" };
void button_init(void);
int button_poll(void (*callback)(uint8_t press, int hold));
int input_get_swr(void);
#define N_BUTTONS 2
#endif

174
dac.c Normal file
View file

@ -0,0 +1,174 @@
/*
* (c) danielinux 2020
* GPLv.2
*
* See LICENSE for details
*/
#include <unicore-mx/cm3/nvic.h>
#include <unicore-mx/stm32/dma.h>
#include <unicore-mx/stm32/dac.h>
#include <unicore-mx/stm32/gpio.h>
#include <unicore-mx/stm32/rcc.h>
#include <unicore-mx/stm32/timer.h>
#include "pot.h"
#define DAC_BUFSIZ 512
extern const unsigned char raw_au[];
const unsigned int raw_au_len;
static volatile int dac_written;
static int dac_transfer_size;
static int dac_chunk_size;
static uint8_t dac_outb[DAC_BUFSIZ];
static void dac_xmit(void)
{
uint32_t size = DAC_BUFSIZ;
if ((dac_transfer_size - dac_written ) < size)
size = dac_transfer_size - dac_written;
dac_chunk_size = size;
/* Start DMA transfer of waveform */
dac_trigger_enable(CHANNEL_1);
dac_set_trigger_source(DAC_CR_TSEL1_T2);
dac_dma_enable(CHANNEL_1);
dma_set_memory_address(DMA1, DMA_STREAM5, (uint32_t) (dac_outb + dac_written));
dma_set_number_of_data(DMA1, DMA_STREAM5, size);
dma_enable_transfer_complete_interrupt(DMA1, DMA_STREAM5);
dma_channel_select(DMA1, DMA_STREAM5, DMA_SxCR_CHSEL_7);
dma_enable_stream(DMA1, DMA_STREAM5);
}
int dac_write(const void *buf, unsigned int len)
{
if (dac_written < dac_transfer_size) {
if ((len + dac_transfer_size) > DAC_BUFSIZ)
return 0;
}
if (dac_written >= dac_transfer_size) {
dac_written = 0;
dac_transfer_size = 0;
}
memcpy(dac_outb + dac_transfer_size, buf, len);
dac_transfer_size += len;
dac_xmit();
return dac_written;
}
int dac_space(void)
{
if (dac_written >= dac_transfer_size) {
dac_written = 0;
dac_transfer_size = 0;
}
return DAC_BUFSIZ - dac_transfer_size;
}
/* IRQ Handler */
void dma1_stream5_isr(void)
{
if (dma_get_interrupt_flag(DMA1, DMA_STREAM5, DMA_TCIF)) {
if (dac_written < dac_transfer_size)
dac_written += dac_chunk_size;
dma_clear_interrupt_flags(DMA1, DMA_STREAM5, DMA_TCIF);
dma_disable_stream(DMA1, DMA_STREAM5);
dac_trigger_disable(CHANNEL_1);
dac_dma_disable(CHANNEL_1);
if (dac_written >= dac_transfer_size) {
return;
} else {
dac_xmit();
}
}
}
/* Initialization functions */
//#define PERIOD (5200)
#define PERIOD 8800
static void timer_setup(void)
{
/* Enable TIM2 clock. */
rcc_periph_clock_enable(RCC_TIM2);
timer_reset(TIM2);
/* Timer global mode: - No divider, Alignment edge, Direction up */
timer_set_mode(TIM2, TIM_CR1_CKD_CK_INT,
TIM_CR1_CMS_EDGE, TIM_CR1_DIR_UP);
timer_continuous_mode(TIM2);
timer_set_period(TIM2, PERIOD);
timer_disable_oc_output(TIM2, TIM_OC2 | TIM_OC3 | TIM_OC4);
timer_enable_oc_output(TIM2, TIM_OC1);
timer_disable_oc_clear(TIM2, TIM_OC1);
timer_disable_oc_preload(TIM2, TIM_OC1);
timer_set_oc_slow_mode(TIM2, TIM_OC1);
timer_set_oc_mode(TIM2, TIM_OC1, TIM_OCM_TOGGLE);
timer_set_oc_value(TIM2, TIM_OC1, 500);
timer_disable_preload(TIM2);
/* Set the timer trigger output (for the DAC) to the channel 1 output
* compare */
timer_set_master_mode(TIM2, TIM_CR2_MMS_COMPARE_OC1REF);
timer_enable_counter(TIM2);
}
static void dac_dma_setup(void)
{
/* DAC channel 1 uses DMA controller 1 Stream 5 Channel 7. */
/* Enable DMA1 clock and IRQ */
rcc_periph_clock_enable(RCC_DMA1);
nvic_set_priority(NVIC_DMA1_STREAM5_IRQ, 1);
nvic_enable_irq(NVIC_DMA1_STREAM5_IRQ);
dma_stream_reset(DMA1, DMA_STREAM5);
dma_set_priority(DMA1, DMA_STREAM5, DMA_SxCR_PL_LOW);
dma_set_memory_size(DMA1, DMA_STREAM5, DMA_SxCR_MSIZE_8BIT);
dma_set_peripheral_size(DMA1, DMA_STREAM5, DMA_SxCR_PSIZE_8BIT);
dma_enable_memory_increment_mode(DMA1, DMA_STREAM5);
dma_enable_circular_mode(DMA1, DMA_STREAM5);
dma_set_transfer_mode(DMA1, DMA_STREAM5,
DMA_SxCR_DIR_MEM_TO_PERIPHERAL);
/* The register to target is the DAC1 8-bit right justified data
register */
dma_set_peripheral_address(DMA1, DMA_STREAM5, (uint32_t) &DAC_DHR8R1);
}
static void dac_hw_init(data_channel c)
{
/* Set DAC GPIO pin to analog mode */
rcc_periph_clock_enable(RCC_GPIOC);
gpio_mode_setup(GPIOA, GPIO_MODE_ANALOG, GPIO_PUPD_NONE, GPIO4);
timer_setup();
/* Set up DAC */
rcc_periph_clock_enable(RCC_DAC);
dac_enable(c);
}
void dac_play(const uint8_t *buf, int len)
{
int i = 0;
int space;
while(i < len) {
space = dac_space();
if (space > 0) {
if (space > (len - i))
space = len - i;
dac_write(buf + i, space);
i += space;
}
}
}
int dac_init(void)
{
int i;
dac_hw_init(CHANNEL_1);
dac_dma_setup();
pot_set_master(200);
dac_play(raw_au, raw_au_len);
return 0;
}

15
dac.h Normal file
View file

@ -0,0 +1,15 @@
#ifndef DAC_H_INCLUDED
#define DAC_H_INCLUDED
#include <stdint.h>
void dac_init(void);
int dac_write(const void *buf, unsigned int len);
int dac_play(const void *buf, unsigned int len);
#define pot_get_master() pot_get(2)
#define pot_set_master(x) pot_set(2,x)
#endif

137
display.c Normal file
View file

@ -0,0 +1,137 @@
/*
* (c) danielinux 2019
* GPLv.2
*
* See LICENSE for details
*/
#include <stdlib.h>
#include <string.h>
#include "display.h"
#include "systick.h"
#include "system.h"
static uint8_t contrast = 0xcf;
void display_scroll(void *priv, uint8_t line)
{
display_send_cmd1(priv, SSD1306_SETSTARTLINE, (line % 0x40) + 0x40);
}
void display_setcontrast(void *priv, uint8_t c)
{
contrast = c;
display_send_cmd1(priv, SSD1306_SETCONTRAST, contrast);
}
uint8_t display_getcontrast(void *priv)
{
return contrast;
}
void display_clear(void *priv)
{
int i,j;
uint8_t zeros[8] = {0, 0, 0, 0, 0, 0, 0, 0 };
display_send_cmd(NULL, 0x00);
display_send_cmd(NULL, 0x10);
for (i = 0; i < 8; i++)
{
display_send_cmd2(NULL, SSD1306_PAGEADDR, i, 0x00);
display_send_cmd2(NULL, SSD1306_COLUMNADDR, 0, WIDTH - 1);
for (j = 0; j < 16; j++)
display_send_data(NULL, zeros, 8);
}
WFI();
WFI();
WFI();
}
void display_text(int row, const char *text)
{
int k;
uint8_t zeros[8] = {0, 0, 0, 0, 0, 0, 0, 0 };
int len = strlen(text);
if (len > 15)
len = 15;
display_send_cmd(NULL, 0x00);
display_send_cmd(NULL, 0x10);
WFI();
display_send_cmd2(NULL, SSD1306_PAGEADDR, 7 - row, 0x00);
display_send_cmd2(NULL, SSD1306_COLUMNADDR, 0, WIDTH - 1);
for(k = 0; k < len; k++)
display_send_data(NULL, fb_font[text[k]], 8);
for(; k < 16; k++)
display_send_data(NULL, zeros, 8);
}
void display_text_inverse(int row, const char *text)
{
int k, j;
uint8_t inv_buf[8];
uint8_t ones[8] = {0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF };
int len = strlen(text);
if (len > 15)
len = 15;
display_send_cmd(NULL, 0x00);
display_send_cmd(NULL, 0x10);
WFI();
display_send_cmd2(NULL, SSD1306_PAGEADDR, 7 - row, 0x00);
display_send_cmd2(NULL, SSD1306_COLUMNADDR, 0, WIDTH - 1);
for(k = 0; k < len; k++) {
for (j = 0; j < 8; j++)
inv_buf[j] = ~fb_font[text[k]][j];
display_send_data(NULL, inv_buf, 8);
}
for(; k < 16; k++)
display_send_data(NULL, ones, 8);
}
int display_init(void *priv)
{
int i;
int k = 0;
int row = 0;
volatile int j;
uint8_t dbuf2[64] = {};
int page = 0;
int seg = 0;
volatile uint32_t now;
for (i = 1; i < 65; i++) {
dbuf2[i] = 0;
}
display_send_cmd(priv, SSD1306_DISPLAYOFF);
display_send_cmd1(priv, 0xD6, 0x01);
display_send_cmd(priv, 0xA1);
display_setcontrast(priv, contrast);
display_send_cmd1(priv, SSD1306_CHARGEPUMP, 0x14);
display_send_cmd1(priv, SSD1306_MEMORYMODE, 0x00);
display_send_cmd1(priv, SSD1306_SETCOMPINS, 0x12);
display_send_cmd1(priv, SSD1306_SETDISPLAYOFFSET, 0x00);
display_send_cmd1(priv, SSD1306_SETVCOMDETECT, 0x00);
display_send_cmd1(priv, SSD1306_SETMULTIPLEX, 63);
display_send_cmd(priv, SSD1306_COMSCANINC);
display_send_cmd(priv, SSD1306_DISPLAYALLON_RESUME);
display_send_cmd(priv, SSD1306_DISPLAYON);
display_send_cmd(priv, 0x2E);
display_send_cmd2(priv, SSD1306_PAGEADDR, 0, 0xFF);
display_send_cmd2(priv, SSD1306_COLUMNADDR, 0, WIDTH - 1);
display_send_cmd1(priv, SSD1306_SETSTARTLINE, 0);
display_send_cmd(priv, 0x00);
display_send_cmd(priv, 0x10);
for (page = 0; page < 8; page++) {
display_send_cmd2(priv, SSD1306_PAGEADDR, page, 0xFF);
for (seg= 0; seg < 32; seg++) {
display_send_data(priv, dbuf2, 8);
}
display_send_cmd1(priv, SSD1306_SETSTARTLINE, row);
}
return 0;
}

56
display.h Normal file
View file

@ -0,0 +1,56 @@
#ifndef DISPLAY_H_INCLUDED
#define DISPLAY_H_INCLUDED
#include <stdint.h>
#define WIDTH 128
#define PIXEL_HEIGHT 64
#define HEIGHT (PIXEL_HEIGHT / 8)
extern const unsigned char fb_font[256][8];
#define SSD1306_MEMORYMODE 0x20
#define SSD1306_COLUMNADDR 0x21
#define SSD1306_PAGEADDR 0x22
#define SSD1306_SETCONTRAST 0x81
#define SSD1306_CHARGEPUMP 0x8D
#define SSD1306_SEGREMAP 0xA0
#define SSD1306_DISPLAYALLON_RESUME 0xA4
#define SSD1306_DISPLAYALLON 0xA5
#define SSD1306_NORMALDISPLAY 0xA6
#define SSD1306_INVERTDISPLAY 0xA7
#define SSD1306_SETMULTIPLEX 0xA8
#define SSD1306_DISPLAYOFF 0xAE
#define SSD1306_DISPLAYON 0xAF
#define SSD1306_COMSCANINC 0xC0
#define SSD1306_COMSCANDEC 0xC8
#define SSD1306_SETDISPLAYOFFSET 0xD3
#define SSD1306_SETDISPLAYCLOCKDIV 0xD5
#define SSD1306_SETPRECHARGE 0xD9
#define SSD1306_SETCOMPINS 0xDA
#define SSD1306_SETVCOMDETECT 0xDB
#define SSD1306_SETLOWCOLUMN 0x00
#define SSD1306_SETHIGHCOLUMN 0x10
#define SSD1306_SETSTARTLINE 0x40
#define SSD1306_RIGHT_HORIZONTAL_SCROLL 0x26
#define SSD1306_LEFT_HORIZONTAL_SCROLL 0x27
#define SSD1306_VERTICAL_AND_RIGHT_HORIZONTAL_SCROLL 0x29
#define SSD1306_VERTICAL_AND_LEFT_HORIZONTAL_SCROLL 0x2A
#define SSD1306_DEACTIVATE_SCROLL 0x2E
#define SSD1306_ACTIVATE_SCROLL 0x2F
#define SSD1306_SET_VERTICAL_SCROLL_AREA 0xA3
/* driver module plug-in (SPI or I2C) */
void display_send_data(void *priv, const uint8_t *buf, int len);
void display_send_cmd(void *priv, uint8_t cmd);
void display_send_cmd1(void *priv, uint8_t cmd, uint8_t arg1);
void display_send_cmd2(void *priv, uint8_t cmd, uint8_t arg1, uint8_t arg2);
int display_init(void *priv);
void display_text(int row, const char *text);
void display_text_inverse(int row, const char *text);
void display_scroll(void *priv, uint8_t line);
void display_setcontrast(void *priv, uint8_t c);
uint8_t display_getcontrast(void *priv);
void display_clear(void *priv);
#endif

BIN
font_twisted.c Normal file

Binary file not shown.

313
i2c.c Normal file
View file

@ -0,0 +1,313 @@
/*
* (c) danielinux 2019
* GPLv.2
*
* See LICENSE for details
*/
#include <stdint.h>
#include <stdlib.h>
#include "system.h"
#include "i2c.h"
#include "display.h"
#define DISPLAY_I2C_ADDR 0x3C
#define DJHERO_I2C_ADDR 0x52
//#define DJHERO_I2C_ADDR 0x29
#define I2C1 (0x40005400)
#define APB1_SPEED_IN_MHZ (42)
#define I2C1_CR1 (*(volatile uint32_t *)(I2C1))
#define I2C1_CR2 (*(volatile uint32_t *)(I2C1 + 0x04))
#define I2C1_OAR1 (*(volatile uint32_t *)(I2C1 + 0x08))
#define I2C1_OAR2 (*(volatile uint32_t *)(I2C1 + 0x0c))
#define I2C1_DR (*(volatile uint32_t *)(I2C1 + 0x10))
#define I2C1_SR1 (*(volatile uint32_t *)(I2C1 + 0x14))
#define I2C1_SR2 (*(volatile uint32_t *)(I2C1 + 0x18))
#define I2C1_CCR (*(volatile uint32_t *)(I2C1 + 0x1c))
#define I2C1_TRISE (*(volatile uint32_t *)(I2C1 + 0x20))
#define I2C_CR1_ENABLE (1 << 0)
#define I2C_CR1_START (1 << 8)
#define I2C_CR1_STOP (1 << 9)
#define I2C_CR1_ACK (1 << 10)
#define I2C_CR2_FREQ_MASK (0x3ff)
#define I2C_CCR_MASK (0xfff)
#define I2C_TRISE_MASK (0x3f)
#define I2C_SR1_START (1 << 0)
#define I2C_SR1_TX_BTF (1 << 2)
#define I2C_SR1_ADDR_SENT (1 << 1)
#define I2C_SR1_RX_NOTEMPTY (1 << 6)
#define I2C_SR1_TX_EMPTY (1 << 7)
#define I2C_SR2_MASTER (1 << 0)
#define I2C_SR2_BUSY (1 << 1)
#define I2C_SR2_XMIT (1 << 2)
#define APB1_CLOCK_ER (*(volatile uint32_t *)(0x40023840))
#define APB1_CLOCK_RST (*(volatile uint32_t *)(0x40023820))
#define I2C1_APB1_CLOCK_ER_VAL (1 << 21)
static void i2c1_pins_setup(void)
{
uint32_t reg;
AHB1_CLOCK_ER |= GPIOB_AHB1_CLOCK_ER;
/* Set mode = AF */
reg = GPIOB_MODE & ~ (0x03 << (I2C1_SCL * 2));
GPIOB_MODE = reg | (2 << (I2C1_SCL * 2));
reg = GPIOB_MODE & ~ (0x03 << (I2C1_SDA * 2));
GPIOB_MODE = reg | (2 << (I2C1_SDA * 2));
/* Set pull-up */
#if 0
reg = GPIOB_PUPD & (0x03 << (I2C1_SCL * 2));
GPIOB_PUPD = reg | (0x01 << (I2C1_SCL * 2));
reg = GPIOB_PUPD & (0x03 << (I2C1_SDA * 2));
GPIOB_PUPD = reg | (0x01 << (I2C1_SDA * 2));
#endif
/* Alternate function: */
reg = GPIOB_AFL & ~(0xf << ((I2C1_SCL) * 4));
GPIOB_AFL = reg | (I2C1_PIN_AF << ((I2C1_SCL) * 4));
reg = GPIOB_AFL & ~(0xf << ((I2C1_SDA) * 4));
GPIOB_AFL = reg | (I2C1_PIN_AF << ((I2C1_SDA) * 4));
}
static void i2c1_reset(void)
{
APB1_CLOCK_RST |= I2C1_APB1_CLOCK_ER_VAL;
APB1_CLOCK_RST &= ~I2C1_APB1_CLOCK_ER_VAL;
}
static void i2c1_send_start(void)
{
volatile uint32_t sr1;
I2C1_CR1 |= I2C_CR1_START;
do {
sr1 = I2C1_SR1;
} while ((sr1 & I2C_SR1_START) == 0);;
}
static void i2c1_send_stop(void)
{
I2C1_CR1 |= I2C_CR1_STOP;
}
void display_send_data(void *priv, const uint8_t *buf, int len)
{
volatile uint32_t sr1, sr2;
int i;
volatile uint8_t drval;
uint32_t start_data = 0x00000040;
uint8_t address = DISPLAY_I2C_ADDR;
I2C1_CR1 &= ~I2C_CR1_ENABLE;
I2C1_CR1 &= ~I2C_CR1_STOP;
I2C1_CR1 &= ~I2C_CR1_ACK;
I2C1_CR1 |= I2C_CR1_ENABLE;
/* Wait if the bus is busy */
do {
sr2 = I2C1_SR2;
} while ((sr2 & I2C_SR2_BUSY) != 0);;
/* Send a start condition */
i2c1_send_start();
/* Send address + R/W = 0 */
I2C1_DR = (address << 1);
do {
sr1 = I2C1_SR1;
} while ((sr1 & I2C_SR1_ADDR_SENT) != I2C_SR1_ADDR_SENT);
do {
sr2 = I2C1_SR2;
} while ((sr2 & (I2C_SR2_BUSY | I2C_SR2_MASTER)) != (I2C_SR2_BUSY | I2C_SR2_MASTER));;
I2C1_DR = start_data;
do {
sr1 = I2C1_SR1;
} while ((sr1 & (I2C_SR1_TX_EMPTY)) == 0);
for (i = 0; i < len; i++) {
I2C1_DR = buf[i];
do {
sr1 = I2C1_SR1;
if ((sr1 & I2C_SR1_RX_NOTEMPTY) == I2C_SR1_RX_NOTEMPTY) {
drval = I2C1_DR;
}
} while ((sr1 & (I2C_SR1_TX_EMPTY)) == 0);
}
while ((sr1 & (I2C_SR1_TX_BTF)) == 0) {
sr1 = I2C1_SR1;
}
i2c1_send_stop();
}
int i2c1_sendrecv(uint8_t address, const uint8_t *wbuf, int wlen, uint8_t *rbuf, int rlen)
{
volatile uint32_t sr1, sr2;
int i;
volatile uint8_t drval;
I2C1_CR1 &= ~I2C_CR1_ENABLE;
I2C1_CR1 &= ~I2C_CR1_STOP;
I2C1_CR1 &= ~I2C_CR1_ACK;
I2C1_CR1 |= I2C_CR1_ENABLE;
/* Wait if the bus is busy */
do {
sr2 = I2C1_SR2;
} while ((sr2 & I2C_SR2_BUSY) != 0);;
/* Send a start condition */
i2c1_send_start();
/* Send address + R/W = 0 */
I2C1_DR = (address << 1);
do {
sr1 = I2C1_SR1;
} while ((sr1 & I2C_SR1_ADDR_SENT) != I2C_SR1_ADDR_SENT);
do {
sr2 = I2C1_SR2;
} while ((sr2 & (I2C_SR2_BUSY | I2C_SR2_MASTER)) != (I2C_SR2_BUSY | I2C_SR2_MASTER));;
for (i = 0; i < wlen; i++) {
I2C1_DR = wbuf[i];
do {
sr1 = I2C1_SR1;
if ((sr1 & I2C_SR1_RX_NOTEMPTY) == I2C_SR1_RX_NOTEMPTY) {
drval = I2C1_DR;
}
} while ((sr1 & (I2C_SR1_TX_EMPTY)) == 0);
}
for (i = 0; i < rlen; i++) {
I2C1_DR = 0xFF;
do {
sr1 = I2C1_SR1;
if ((sr1 & I2C_SR1_RX_NOTEMPTY) == I2C_SR1_RX_NOTEMPTY) {
rbuf[i] = I2C1_DR;
}
} while ((sr1 & (I2C_SR1_TX_EMPTY)) == 0);
}
while ((sr1 & (I2C_SR1_TX_BTF)) == 0) {
sr1 = I2C1_SR1;
}
i2c1_send_stop();
return i;
}
int i2c1_send(uint8_t address, const uint8_t *buf, int len)
{
volatile uint32_t sr1, sr2;
int i;
volatile uint8_t drval;
I2C1_CR1 &= ~I2C_CR1_ENABLE;
I2C1_CR1 &= ~I2C_CR1_STOP;
I2C1_CR1 &= ~I2C_CR1_ACK;
I2C1_CR1 |= I2C_CR1_ENABLE;
/* Wait if the bus is busy */
do {
sr2 = I2C1_SR2;
} while ((sr2 & I2C_SR2_BUSY) != 0);;
/* Send a start condition */
i2c1_send_start();
/* Send address + R/W = 0 */
I2C1_DR = (address << 1);
do {
sr1 = I2C1_SR1;
} while ((sr1 & I2C_SR1_ADDR_SENT) != I2C_SR1_ADDR_SENT);
do {
sr2 = I2C1_SR2;
} while ((sr2 & (I2C_SR2_BUSY | I2C_SR2_MASTER)) != (I2C_SR2_BUSY | I2C_SR2_MASTER));;
for (i = 0; i < len; i++) {
I2C1_DR = buf[i];
do {
sr1 = I2C1_SR1;
if ((sr1 & I2C_SR1_RX_NOTEMPTY) == I2C_SR1_RX_NOTEMPTY) {
drval = I2C1_DR;
}
} while ((sr1 & (I2C_SR1_TX_EMPTY)) == 0);
}
while ((sr1 & (I2C_SR1_TX_BTF)) == 0) {
sr1 = I2C1_SR1;
}
i2c1_send_stop();
return i;
}
void i2c1_setup(void)
{
uint32_t reg;
i2c1_pins_setup();
APB1_CLOCK_ER |= I2C1_APB1_CLOCK_ER_VAL;
I2C1_CR1 &= ~I2C_CR1_ENABLE;
i2c1_reset();
reg = I2C1_CR2 & ~(I2C_CR2_FREQ_MASK);
I2C1_CR2 = reg | APB1_SPEED_IN_MHZ;
reg = I2C1_CCR & ~(I2C_CCR_MASK);
I2C1_CCR = reg | (APB1_SPEED_IN_MHZ * 5); /* 400 Khz */
// I2C1_CCR = reg | (APB1_SPEED_IN_MHZ * 20); /* 100 Khz */
// I2C1_CCR = reg | (APB1_SPEED_IN_MHZ * 40); /* 50 Khz */
reg = I2C1_TRISE & ~(I2C_TRISE_MASK);
I2C1_TRISE = reg | (APB1_SPEED_IN_MHZ + 1);
I2C1_CR1 |= I2C_CR1_ENABLE;
}
void i2c_display_init(void)
{
display_init(NULL);
}
void display_send_cmd(void *priv, uint8_t cmd)
{
uint8_t buf[2] = {0x00, cmd};
volatile int j;
i2c1_send(DISPLAY_I2C_ADDR, buf, 2);
}
void display_send_cmd1(void *priv, uint8_t cmd, uint8_t arg1)
{
uint8_t buf[3] = {0x00, cmd, arg1};
volatile int j;
i2c1_send(DISPLAY_I2C_ADDR, buf, 3);
}
void display_send_cmd2(void *priv, uint8_t cmd, uint8_t arg1, uint8_t arg2)
{
uint8_t buf[4] = {0x00, cmd, arg1, arg2};
volatile int j;
i2c1_send(DISPLAY_I2C_ADDR, buf, 3);
}
void djhero_init(void)
{
const uint8_t cmd1[2] = { 0xf0, 0x55 };
const uint8_t cmd2[2] = { 0xfb, 0x00 };
const uint8_t cmdquery[1] = { 0xFA };
uint8_t serial[6];
i2c1_send(DJHERO_I2C_ADDR, cmd1, 2);
i2c1_send(DJHERO_I2C_ADDR, cmd2, 2);
i2c1_sendrecv(DJHERO_I2C_ADDR, cmdquery, 1, serial, 6);
}

12
i2c.h Normal file
View file

@ -0,0 +1,12 @@
#ifndef I2C_H_INCLUDED
#define I2C_H_INCLUDED
#include <stdint.h>
void i2c1_setup(void);
void i2c1_write(uint8_t addr, const char byte);
uint8_t i2c1_read(uint8_t addr);
int i2c1_send(uint8_t address, const uint8_t *buf, int len);
int i2c1_send_data(uint8_t address, const uint8_t *buf, int len);
#endif

92
led.c Normal file
View file

@ -0,0 +1,92 @@
/*
* (c) danielinux 2019
* GPLv.2
*
* See LICENSE for details
*/
#include <stdint.h>
#include "unicore-mx/stm32/gpio.h"
#include "unicore-mx/stm32/rcc.h"
#include "system.h"
#include "led.h"
#include "pinout.h"
/* LEDS mapping:
*
* E0 - Heartbeat
* E10 - 1
* B2 - 2
* E8 - 3
* E9 - 4
* E1 - 5
* E7 - 6
* B8 - 7
* B9 - 8
*/
#define NUM_LEDS 9
#define LD0 (1 << 0)
#define LD1 (1 << 10)
#define LD2 (1 << 2)
#define LD3 (1 << 8)
#define LD4 (1 << 9)
#define LD5 (1 << 1)
#define LD6 (1 << 7)
#define LD7 (1 << 8)
#define LD8 (1 << 9)
#define BANK_B_LD (LD2 | LD7 | LD8)
#define BANK_E_LD (LD0 | LD1 | LD3 | LD4 | LD5 | LD6)
struct pin Leds[9] = {
{ GPIOE, 1 << 0 },
{ GPIOE, 1 << 10 },
{ GPIOB, 1 << 2 },
{ GPIOE, 1 << 8 },
{ GPIOE, 1 << 9 },
{ GPIOE, 1 << 1 },
{ GPIOB, 1 << 8 },
{ GPIOB, 1 << 9 },
};
void led_setup(void)
{
rcc_periph_clock_enable(RCC_GPIOB);
rcc_periph_clock_enable(RCC_GPIOE);
gpio_mode_setup(GPIOB, GPIO_MODE_OUTPUT, GPIO_PUPD_PULLDOWN, BANK_B_LD);
gpio_set(GPIOB, BANK_B_LD);
gpio_mode_setup(GPIOE, GPIO_MODE_OUTPUT, GPIO_PUPD_PULLDOWN, BANK_E_LD);
gpio_set(GPIOE, BANK_E_LD);
}
void led_on(int led)
{
gpio_set(Leds[led].bank, Leds[led].pin);
}
void led_off(int led)
{
gpio_clear(Leds[led].bank, Leds[led].pin);
}
void led_toggle(int led)
{
if (gpio_get(Leds[led].bank, Leds[led].pin))
gpio_clear(Leds[led].bank, Leds[led].pin);
else
gpio_set(Leds[led].bank, Leds[led].pin);
}
void led_beat(int b)
{
if (b < 1 || b > 8)
return;
gpio_clear(GPIOB, BANK_B_LD);
gpio_clear(GPIOE, BANK_E_LD);
led_on(b);
}

13
led.h Normal file
View file

@ -0,0 +1,13 @@
#ifndef LED_H
#define LED_H
#include <stdint.h>
#include "system.h"
void led_setup(void);
void led_on(int led);
void led_off(int led);
void led_toggle(int led);
void led_beat(int b);
#endif

1
lib/unicore-mx Submodule

@ -0,0 +1 @@
Subproject commit 72be4686cba2d190765695477e735ca10ca473cf

153
main.c Normal file
View file

@ -0,0 +1,153 @@
/*
* (c) danielinux 2019
* GPLv.2
*
* See LICENSE for details
*/
#include <string.h>
#include <stdio.h>
#include "system.h"
#include "led.h"
#include "display.h"
#include "spi_flash.h"
#include "uart.h"
#include "systick.h"
#include "ui.h"
#include "button.h"
#include "adc.h"
extern uint32_t cpu_freq;
#define BLINK_INTERVAL 500
static int sdcard_detected = 0;
static void bootlevel_0(void)
{
clock_pll_on();
uart2_setup(115200, 8, 0, 1);
systick_enable();
WFI();
printf("Console on USART2 Enabled.\r\n");
printf("\r\n=====================\r\n");
printf("Entering bootlevel 0.\r\n");
led_setup();
led_on(0);
printf("System clock started.\r\n");
button_init();
//pin_exti_init();
printf("Buttons initialized.\r\n");
}
extern void timer_init(void);
static void bootlevel_1(void)
{
uint16_t spiflash_vendor;
int sdcard_present;
printf("=====================\r\n");
printf("Entering bootlevel 1.\r\n");
printf("Initializing ADC...\r\n");
adc_init();
printf("Initializing digital-potmeters\r\n");
pot_init();
printf("Initializing DAC...\r\n");
dac_init();
printf("Activating I2C bus...\r\n");
i2c1_setup();
i2c_display_init();
printf("Display initialized.\r\n");
printf("Displaying splash screen...\r\n");
ui_init();
printf("UI initialized.\r\n");
//djhero_init();
timer_init();
printf("System up and running.\r\n\n\n");
}
static void (*process_input_callback)(uint8_t press, int hold) = NULL;
static void (*keepalive_callback)(void) = NULL;
void set_input_callback(void (*cb)(uint8_t press, int hold))
{
process_input_callback = cb;
}
void clear_input_callback(void)
{
process_input_callback = NULL;
}
void set_keepalive(void (*cb)(void))
{
keepalive_callback = cb;
}
void clear_keepalive(void)
{
keepalive_callback = NULL;
}
void process_button(uint8_t press, int hold)
{
static uint32_t last_b_time = 0;
if (jiffies - last_b_time < 100)
return;
last_b_time = jiffies;
if (process_input_callback)
process_input_callback(press, hold);
else
ui_button_press(press, hold);
}
extern void gettime(uint32_t *s, uint32_t *us);
int main(void) {
int hb = 1;
int fs_on = 0;
int ret;
char uc;
volatile uint32_t poll_time = 0;
uint32_t bstatus = 0;
const uint32_t hb_len = 20;
const uint32_t hb_pulse = 5;
bootlevel_0();
bootlevel_1();
//pin_exti_start_read();
while(1) {
hb = 1;
led_on(LED);
poll_time = jiffies;
if (!keepalive_callback)
ui_keepalive(hb_len);
else
keepalive_callback();
do {
WFI();
ret = button_poll(process_button);
uc = uart_read();
if (uc)
process_button(uc, 0);
if (jiffies - poll_time > hb_pulse) {
if (hb) {
uint32_t s, us;
hb = 0;
led_off(LED);
// gettime(&s, &us);
// printf("TIME: %u.%05u\r\n", s, us);
}
}
} while ((jiffies - poll_time) < hb_len);
}
return 0;
}

37
mem.c Normal file
View file

@ -0,0 +1,37 @@
/*
* (c) danielinux 2019
* GPLv.2
*
* See LICENSE for details
*/
extern unsigned int _start_heap;
#define NULL (((void *)0))
void * _sbrk(unsigned int incr)
{
static unsigned char *heap = (unsigned char *)&_start_heap;
void *old_heap = heap;
if (((incr >> 2) << 2) != incr)
incr = ((incr >> 2) + 1) << 2;
if (heap == NULL)
heap = (unsigned char *)&_start_heap;
else
heap += incr;
return old_heap;
}
void * _sbrk_r(unsigned int incr)
{
static unsigned char *heap = NULL;
void *old_heap = heap;
if (((incr >> 2) << 2) != incr)
incr = ((incr >> 2) + 1) << 2;
if (old_heap == NULL)
old_heap = heap = (unsigned char *)&_start_heap;
heap += incr;
return old_heap;
}

47
mutex.S Normal file
View file

@ -0,0 +1,47 @@
.syntax unified
/* Lock function.
* On success, return 0.
* On failure, return -1 (Locked, try again later).
*/
.global _mutex_lock
_mutex_lock:
LDREX r1, [r0]
CMP r1, #0 // Test if mutex holds the value 0
BEQ _mutex_lock_fail // If it does, return -1
SUBS r1, #1 // If not, decrement temporary copy
STREX r2, r1, [r0] // Attempt Store-Exclusive
CMP r2, #0 // Check if Store-Exclusive succeeded
BNE _mutex_lock // If Store-Exclusive failed, retry from start
DMB // Required before accessing protected resource
MOVS r0, #0 // Successfully locked.
BX lr
_mutex_lock_fail:
DMB
MOV r0, #-1 // Already locked!
BX lr
/* Unlock mutex.
* On success, return 0.
* On failure, return -1 (Already unlocked!).
*/
.global _mutex_unlock
_mutex_unlock:
LDREX r1, [r0]
CMP r1, #0 // Test if mutex holds the value 0
BNE _mutex_unlock_fail // If it does not, it's already unlocked!
ADDS r1, #1 // Increment temporary copy
STREX r2, r1, [r0] // Attempt Store-Exclusive
CMP r2, #0 // Check if Store-Exclusive succeeded
BNE _mutex_unlock // Store failed - retry immediately
DMB // Required before releasing protected resource
MOVS r0, #0 // Successfully unlocked.
BX lr
_mutex_unlock_fail:
DMB
MOV r0, #-1 // Already unlocked!
BX lr

35
newlib.c Normal file
View file

@ -0,0 +1,35 @@
/*
* (c) danielinux 2019
* GPLv.2
*
* See LICENSE for details
*/
#include <stdlib.h>
#include <stdint.h>
int _close(int fd)
{
return -1;
}
int _fstat(int fd)
{
return -1;
}
int _lseek(int fd, int whence, int off)
{
return -1;
}
int _read(uint8_t *buf, int len)
{
return -1;
}
int _isatty(int fd)
{
return 1;
}

13
pinout.h Normal file
View file

@ -0,0 +1,13 @@
#ifndef PIN_INCLUDED
#define PIN_INCLUDED
#include <stdint.h>
struct pin {
uint32_t bank;
uint32_t pin;
};
#endif

129
pot.c Normal file
View file

@ -0,0 +1,129 @@
#include <stdint.h>
#include "unicore-mx/stm32/gpio.h"
#include "unicore-mx/stm32/rcc.h"
#include "system.h"
#include "led.h"
#include "pinout.h"
extern volatile uint32_t jiffies;
uint32_t p1_lvl, p0_lvl, master_lvl;
static int pot_cs[3] = { 8, 7, 6 }; // PC6, PC7, PC8
#define POT0 GPIO8 // C8
#define POT1 GPIO7 // C7
#define POTM GPIO6 // C6
#define POTINC GPIO15 // D15
#define POTUD GPIO14 // D14
#define NUM_POTS 3
#define POT_CS_PINS (POT0 | POT1 | POTM)
#define POT_CTRL_PINS (POTINC | POTUD)
static uint32_t Pots[NUM_POTS] = { POT0, POT1, POTM };
static int Levels[NUM_POTS] = { 0, 0, 0 };
static void p_offset(int p, int offset)
{
uint32_t cs;
int i;
int sign = 0;
int u_off = offset;
volatile uint32_t now;
if((p < 0) || (p > NUM_POTS))
return;
cs = Pots[p];
if (offset < 0) {
sign = 1;
u_off = 0 - offset;
}
/* U/!D setting */
if (sign)
gpio_clear(GPIOD, POTUD);
else
gpio_set(GPIOD, POTUD);
for (i = 0; i < u_off; i++) {
/* /CS on */
gpio_clear(GPIOC, cs);
DMB();
/* /INC on */
gpio_clear(GPIOD, POTINC);
DMB();
/* /INC off */
gpio_set(GPIOD, POTINC);
/* /CS off first (no store) */
gpio_set(GPIOC,cs);
//WFI();
for (int j = 0; j < 4000; j++)
;;
}
Levels[p] += offset;
if (Levels[p] > 100)
Levels[p] = 100;
if (Levels[p] < 0)
Levels[p] = 0;
}
void pot_offset(int p, int offset)
{
if ((Levels[p] + offset) > 100) {
offset = 100 - Levels[p];
}
if ((Levels[p] + offset) < 0) {
offset = 0 - Levels[p];
}
if (offset == 0)
return;
p_offset(p, offset);
}
void pot_init(void)
{
int i;
rcc_periph_clock_enable(RCC_GPIOC);
rcc_periph_clock_enable(RCC_GPIOD);
gpio_mode_setup(GPIOC, GPIO_MODE_OUTPUT, GPIO_PUPD_PULLUP, POT_CS_PINS);
gpio_set_output_options(GPIOC, GPIO_OTYPE_OD, GPIO_OSPEED_100MHZ, POT_CS_PINS);
gpio_set(GPIOC, POT_CS_PINS);
gpio_mode_setup(GPIOD, GPIO_MODE_OUTPUT, GPIO_PUPD_PULLUP, POT_CTRL_PINS);
gpio_set_output_options(GPIOD, GPIO_OTYPE_OD, GPIO_OSPEED_100MHZ, POT_CTRL_PINS);
gpio_set(GPIOD, POT_CTRL_PINS);
for (i = 0; i < NUM_POTS; i++)
p_offset(i, -100);
}
int pot_get(int p)
{
return Levels[p];
}
void pot_set(int p, int val)
{
int old = Levels[p];
int off;
if (val < 0)
val = 0;
if (val > 100)
val = 100;
off = val - old;
if (off == 0)
return;
pot_offset(p, off);
}

15
pot.h Normal file
View file

@ -0,0 +1,15 @@
#ifndef POT_H_INCLUDED
#define POT_H_INCLUDED
#include <stdint.h>
void pot_init(void);
int pot_get(int p);
void pot_set(int p, int val);
void pot_offset(int p, int offset);
#define pot_get_master() pot_get(2)
#define pot_set_master(x) pot_set(2,x)
#endif

3078
sound.c Normal file

File diff suppressed because it is too large Load diff

105
spi.c Normal file
View file

@ -0,0 +1,105 @@
/*
* (c) danielinux 2019
*
* GPLv.2
*
* See LICENSE for details
*/
#include <stdint.h>
#include "spi_drv.h"
#include "system.h"
void spi_cs_off(void)
{
GPIOA_BSRR |= (1 << SPI_FLASH_PIN);
DMB();
while(!(GPIOA_ODR & (1 << SPI_FLASH_PIN)))
;
}
void spi_cs_on(void)
{
volatile int i;
GPIOA_BSRR |= (1 << (SPI_FLASH_PIN + 16));
DMB();
while(GPIOA_ODR & (1 << SPI_FLASH_PIN))
;
}
static void spi_flash_pin_setup(void)
{
uint32_t reg;
AHB1_CLOCK_ER |= GPIOA_AHB1_CLOCK_ER;
reg = GPIOA_MODE & ~ (0x03 << (SPI_FLASH_PIN * 2));
GPIOA_MODE = reg | (1 << (SPI_FLASH_PIN * 2));
reg = GPIOA_PUPD & (0x03 << (SPI_FLASH_PIN * 2));
GPIOA_PUPD = reg | (0x01 << (SPI_FLASH_PIN * 2));
reg = GPIOA_OSPD & ~(0x03 << (SPI_FLASH_PIN * 2));
GPIOA_OSPD |= (0x03 << (SPI_FLASH_PIN * 2));
}
static void spi1_pins_setup(void)
{
uint32_t reg;
AHB1_CLOCK_ER |= GPIOA_AHB1_CLOCK_ER;
/* Set mode = AF */
reg = GPIOA_MODE & ~ (0x03 << (SPI1_CLOCK_PIN * 2));
GPIOA_MODE = reg | (2 << (SPI1_CLOCK_PIN * 2));
reg = GPIOA_MODE & ~ (0x03 << (SPI1_MOSI_PIN * 2));
GPIOA_MODE = reg | (2 << (SPI1_MOSI_PIN * 2));
reg = GPIOA_MODE & ~ (0x03 << (SPI1_MISO_PIN * 2));
GPIOA_MODE = reg | (2 << (SPI1_MISO_PIN * 2));
/* Alternate function: use low pins (5,6,7) */
reg = GPIOA_AFL & ~(0xf << ((SPI1_CLOCK_PIN) * 4));
GPIOA_AFL = reg | (SPI1_PIN_AF << ((SPI1_CLOCK_PIN) * 4));
reg = GPIOA_AFL & ~(0xf << ((SPI1_MOSI_PIN) * 4));
GPIOA_AFL = reg | (SPI1_PIN_AF << ((SPI1_MOSI_PIN) * 4));
reg = GPIOA_AFL & ~(0xf << ((SPI1_MISO_PIN) * 4));
GPIOA_AFL = reg | (SPI1_PIN_AF << ((SPI1_MISO_PIN) * 4));
}
static void spi1_reset(void)
{
APB2_CLOCK_RST |= SPI1_APB2_CLOCK_ER_VAL;
APB2_CLOCK_RST &= ~SPI1_APB2_CLOCK_ER_VAL;
}
uint8_t spi_read(void)
{
volatile uint32_t reg;
do {
reg = SPI1_SR;
} while(!(reg & SPI_SR_RX_NOTEMPTY));
return (uint8_t)SPI1_DR;
}
void spi_write(const char byte)
{
int i;
volatile uint32_t reg;
do {
reg = SPI1_SR;
} while ((reg & SPI_SR_TX_EMPTY) == 0);
SPI1_DR = byte;
do {
reg = SPI1_SR;
} while ((reg & SPI_SR_TX_EMPTY) == 0);
}
void spi_init(int polarity, int phase)
{
spi1_pins_setup();
spi_flash_pin_setup();
APB2_CLOCK_ER |= SPI1_APB2_CLOCK_ER_VAL;
spi1_reset();
SPI1_CR1 = SPI_CR1_MASTER | (5 << 3) | (polarity << 1) | (phase << 0);
SPI1_CR2 |= SPI_CR2_SSOE;
SPI1_CR1 |= SPI_CR1_SPI_EN;
}

11
spi_drv.h Normal file
View file

@ -0,0 +1,11 @@
#ifndef SPI_DRV_H_INCLUDED
#define SPI_DRV_H_INCLUDED
#include <stdint.h>
void spi_init(int polarity, int phase);
void spi_write(const char byte);
uint8_t spi_read(void);
void spi_cs_on(void);
void spi_cs_off(void);
#endif

254
spi_flash.c Normal file
View file

@ -0,0 +1,254 @@
/*
* (c) danielinux 2019
*
* GPLv.2
*
* See LICENSE for details
*/
#include "system.h"
#include "spi_drv.h"
#define SPI_FLASH_SECTOR_SIZE (4096)
#define SPI_FLASH_PAGE_SIZE (256)
#define MDID 0x90
#define RDSR 0x05
#define WRSR 0x01
# define ST_BUSY (1 << 0)
# define ST_WEL (1 << 1)
# define ST_BP0 (1 << 2)
# define ST_BP1 (1 << 3)
# define ST_BP2 (1 << 4)
# define ST_BP3 (1 << 5)
# define ST_AAI (1 << 6)
# define ST_BRO (1 << 7)
#define WREN 0x06
#define WRDI 0x04
#define SECTOR_ERASE 0x20
#define BYTE_READ 0x03
#define BYTE_WRITE 0x02
#define AUTOINC 0xAD
#define EWSR 0x50
#define EBSY 0x70
#define DBSY 0x80
static enum write_mode {
WB_WRITEPAGE = 0x00,
SST_AAI = 0x01
} chip_write_mode = WB_WRITEPAGE;
static void write_address(uint32_t address)
{
spi_write((address & 0xFF00) >> 8);
spi_read();
spi_write((address & 0xFF0000) >> 16);
spi_read();
spi_write((address & 0xFF000000) >> 24);
spi_read();
}
static uint8_t read_status(void)
{
uint8_t status;
int i;
spi_cs_on();
spi_write(RDSR);
spi_read();
spi_write(0xFF);
status = spi_read();
spi_cs_off();
return status;
}
static void spi_cmd(uint8_t cmd)
{
spi_cs_on();
spi_write(cmd);
spi_read();
spi_cs_off();
}
static inline void flash_aai_enable(void)
{
spi_cmd(EBSY);
}
static inline void flash_aai_disable(void)
{
spi_cmd(DBSY);
}
static void flash_write_enable(void)
{
uint8_t status;
do {
spi_cmd(WREN);
status = read_status();
} while ((status & ST_WEL) == 0);
}
static void flash_write_disable(void)
{
uint8_t status;
spi_cmd(WRDI);
}
static void wait_busy(void)
{
uint8_t status;
do {
status = read_status();
} while(status & ST_BUSY);
}
static int spi_flash_write_page(uint32_t address, const void *data, int len)
{
const uint8_t *buf = data;
int j = 0;
while (len > 0) {
wait_busy();
flash_write_enable();
spi_cs_on();
spi_write(BYTE_WRITE);
spi_read();
write_address(address);
do {
spi_write(buf[j++]);
address++;
spi_read();
len--;
} while ((address % SPI_FLASH_PAGE_SIZE) != 0);
spi_cs_off();
}
wait_busy();
return j;
}
static int spi_flash_write_aai(uint32_t address, const void *data, int len)
{
const uint8_t *buf = data;
int j = 0;
int cont = 0;
wait_busy();
if (len < 1)
return -1;
while (len > 0) {
if ((address & 0x01) || (len < 2)) {
flash_write_enable();
spi_cs_on();
spi_write(BYTE_WRITE);
spi_read();
write_address(address);
spi_write(buf[j++]);
spi_read();
spi_cs_off();
len--;
address++;
} else {
if (!cont) {
flash_aai_enable();
flash_write_enable();
}
spi_cs_on();
spi_write(AUTOINC);
spi_read();
if (!cont) {
/* First AAI transaction, send address. */
write_address(address);
cont = 1;
}
spi_write(buf[j++]);
spi_read();
spi_write(buf[j++]);
spi_read();
spi_cs_off();
len -= 2;
address += 2;
read_status();
}
}
if (cont) {
flash_write_disable();
flash_aai_disable();
}
wait_busy();
return j;
}
/* --- */
uint16_t spi_flash_probe(void)
{
uint8_t manuf, product, b0;
int i;
wait_busy();
spi_cs_on();
spi_write(MDID);
b0 = spi_read();
write_address(0);
spi_write(0xFF);
manuf = spi_read();
spi_write(0xFF);
product = spi_read();
spi_cs_off();
if (manuf == 0xBF)
chip_write_mode = SST_AAI;
if (manuf == 0xEF)
chip_write_mode = WB_WRITEPAGE;
#ifndef READONLY
spi_cmd(EWSR);
spi_cs_on();
spi_write(WRSR);
spi_read();
spi_write(0x00);
spi_read();
spi_cs_off();
#endif
return (uint16_t)(manuf << 8 | product);
}
void spi_flash_sector_erase(uint32_t address)
{
uint8_t status;
address &= (~(SPI_FLASH_SECTOR_SIZE - 1));
wait_busy();
flash_write_enable();
spi_cs_on();
spi_write(SECTOR_ERASE);
spi_read();
write_address(address);
spi_cs_off();
wait_busy();
}
int spi_flash_read(uint32_t address, void *data, int len)
{
uint8_t *buf = data;
int i = 0;
wait_busy();
spi_cs_on();
spi_write(BYTE_READ);
spi_read();
write_address(address);
while (len > 0) {
spi_write(0xFF);
buf[i++] = spi_read();
len--;
}
spi_cs_off();
return i;
}
int spi_flash_write(uint32_t address, const void *data, int len)
{
if (chip_write_mode == SST_AAI)
return spi_flash_write_aai(address, data, len);
if (chip_write_mode == WB_WRITEPAGE)
return spi_flash_write_page(address, data, len);
return -1;
}

9
spi_flash.h Normal file
View file

@ -0,0 +1,9 @@
#ifndef SPI_FLASH_DRI_H
#define SPI_FLASH_DRI_H
#include <stdint.h>
uint16_t spi_flash_probe(void);
void spi_flash_sector_erase(uint32_t address);
int spi_flash_read(uint32_t address, void *data, int len);
int spi_flash_write(uint32_t address, const void *data, int len);
#endif

212
startup.c Normal file
View file

@ -0,0 +1,212 @@
/*
* (c) danielinux 2019
*
* GPLv.2
*
* See LICENSE for details
*/
extern unsigned int _stored_data;
extern unsigned int _start_data;
extern unsigned int _end_data;
extern unsigned int _start_bss;
extern unsigned int _end_bss;
extern unsigned int _end_stack;
extern unsigned int _start_heap;
#define STACK_PAINTING
static volatile unsigned int avail_mem = 0;
static unsigned int sp;
extern void main(void);
extern void isr_exti_rot0(void);
//extern void isr_exti_rot1(void);
extern void isr_exti_channel(void);
extern void isr_exti_button(void);
//extern void isr_tim1(void);
//extern void isr_tim2(void);
//extern void isr_tim3(void);
extern void isr_tim4(void);
extern void isr_systick(void);
extern void otg_fs_isr(void);
extern void usb_fs_wkup_isr(void);
extern void dma1_stream5_isr(void);
void isr_reset(void) {
register unsigned int *src, *dst;
src = (unsigned int *) &_stored_data;
dst = (unsigned int *) &_start_data;
/* Copy the .data section from flash to RAM. */
while (dst < (unsigned int *)&_end_data) {
*dst = *src;
dst++;
src++;
}
/* Initialize the BSS section to 0 */
dst = &_start_bss;
while (dst < (unsigned int *)&_end_bss) {
*dst = 0U;
dst++;
}
/* Paint the stack. */
avail_mem = &_end_stack - &_start_heap;
#ifdef STACK_PAINTING
{
asm volatile("mrs %0, msp" : "=r"(sp));
dst = ((unsigned int *)(&_end_stack)) - (8192 / sizeof(unsigned int)); ;
while ((unsigned int)dst < sp) {
*dst = 0xDEADC0DE;
dst++;
}
}
#endif
/* Run the program! */
main();
}
void isr_fault(void)
{
/* Panic. */
while(1) ;;
}
void isr_memfault(void)
{
/* Panic. */
while(1) ;;
}
void isr_busfault(void)
{
/* Panic. */
while(1) ;;
}
void isr_usagefault(void)
{
/* Panic. */
while(1) ;;
}
void isr_empty(void)
{
/* Ignore the event and continue */
}
__attribute__ ((section(".isr_vector")))
void (* const IV[])(void) =
{
(void (*)(void))(&_end_stack),
isr_reset, // Reset
isr_fault, // NMI
isr_fault, // HardFault
isr_memfault, // MemFault
isr_busfault, // BusFault
isr_usagefault, // UsageFault
0, 0, 0, 0, // 4x reserved
isr_empty, // SVC
isr_empty, // DebugMonitor
0, // reserved
isr_empty, // PendSV
isr_systick, // SysTick
isr_empty, // NVIC_WWDG_IRQ 0
isr_empty, // PVD_IRQ 1
isr_empty, // TAMP_STAMP_IRQ 2
isr_empty, // RTC_WKUP_IRQ 3
isr_empty, // FLASH_IRQ 4
isr_empty, // RCC_IRQ 5
isr_exti_button, // EXTI0_IRQ 6
isr_exti_button, // EXTI1_IRQ 7
isr_empty, // EXTI2_IRQ 8
isr_exti_button, // EXTI3_IRQ 9
isr_exti_rot0, // EXTI4_IRQ 10
isr_empty, // DMA1_STREAM0_IRQ 11
isr_empty, // DMA1_STREAM1_IRQ 12
isr_empty, // DMA1_STREAM2_IRQ 13
isr_empty, // DMA1_STREAM3_IRQ 14
isr_empty, // DMA1_STREAM4_IRQ 15
dma1_stream5_isr, // DMA1_STREAM5_IRQ 16
isr_empty, // DMA1_STREAM6_IRQ 17
isr_empty, // ADC_IRQ 18
isr_empty, // CAN1_TX_IRQ 19
isr_empty, // CAN1_RX0_IRQ 20
isr_empty, // CAN1_RX1_IRQ 21
isr_empty, // CAN1_SCE_IRQ 22
isr_empty, // EXTI9_5_IRQ 23 // ROT-1
isr_empty, // TIM1_BRK_TIM9_IRQ 24
isr_empty, // TIM1_UP_TIM10_IRQ 25
isr_empty, // TIM1_TRG_COM_TIM11_IRQ 26
isr_empty, // TIM1_CC_IRQ 27
isr_empty, // TIM2_IRQ 28
isr_empty, // TIM3_IRQ 29
isr_tim4, // TIM4_IRQ 30
isr_empty, // I2C1_EV_IRQ 31
isr_empty, // I2C1_ER_IRQ 32
isr_empty, // I2C2_EV_IRQ 33
isr_empty, // I2C2_ER_IRQ 34
isr_empty, // SPI1_IRQ 35
isr_empty, // SPI2_IRQ 36
isr_empty, // USART1_IRQ 37
isr_empty, // USART2_IRQ 38
isr_empty, // USART3_IRQ 39
isr_empty, // EXTI15_10_IRQ 40
isr_empty, // RTC_ALARM_IRQ 41
usb_fs_wkup_isr, // USB_FS_WKUP_IRQ 42
isr_empty, // TIM8_BRK_TIM12_IRQ 43
isr_empty, // TIM8_UP_TIM13_IRQ 44
isr_empty, // TIM8_TRG_COM_TIM14_IRQ 45
isr_empty, // TIM8_CC_IRQ 46
isr_empty, // DMA1_STREAM7_IRQ 47
isr_empty, // FSMC_IRQ
isr_empty, // SDIO_IRQ
isr_empty, // TIM5_IRQ
isr_empty, // SPI3_IRQ
isr_empty, // UART4_IRQ
isr_empty, // UART5_IRQ
isr_empty, // TIM6_DAC_IRQ
isr_empty, // TIM7_IRQ
isr_empty, // DMA2_STREAM0_IRQ
isr_empty, // DMA2_STREAM1_IRQ
isr_empty, // DMA2_STREAM2_IRQ
isr_empty, // DMA2_STREAM3_IRQ
isr_empty, // DMA2_STREAM4_IRQ
isr_empty, // ETH_IRQ
isr_empty, // ETH_WKUP_IRQ
isr_empty, // CAN2_TX_IRQ
isr_empty, // CAN2_RX0_IRQ
isr_empty, // CAN2_RX1_IRQ
isr_empty, // CAN2_SCE_IRQ
otg_fs_isr, // OTG_FS_IRQ
isr_empty, // DMA2_STREAM5_IRQ
isr_empty, // DMA2_STREAM6_IRQ
isr_empty, // DMA2_STREAM7_IRQ
isr_empty, // USART6_IRQ
isr_empty, // I2C3_EV_IRQ
isr_empty, // I2C3_ER_IRQ
isr_empty, // OTG_HS_EP1_OUT_IRQ
isr_empty, // OTG_HS_EP1_IN_IRQ
isr_empty, // OTG_HS_WKUP_IRQ
isr_empty, // OTG_HS_IRQ
isr_empty, // DCMI_IRQ
isr_empty, // CRYP_IRQ
isr_empty, // HASH_RNG_IRQ
isr_empty, // FPU_IRQ
isr_empty, // UART7_IRQ
isr_empty, // UART8_IRQ
isr_empty, // SPI4_IRQ
isr_empty, // SPI5_IRQ
isr_empty, // SPI6_IRQ
isr_empty, // SAI1_IRQ
isr_empty, // LCD_TFT_IRQ
isr_empty, // LCD_TFT_ERR_IRQ
isr_empty, // DMA2D_IRQ
};

170
system.c Normal file
View file

@ -0,0 +1,170 @@
/*
* (c) danielinux 2019
*
* GPLv.2
*
* See LICENSE for details
*/
#include <stdint.h>
#include "system.h"
uint32_t cpu_freq = 168000000;
/*** FLASH ***/
#define FLASH_BASE (0x40023C00)
#define FLASH_ACR (*(volatile uint32_t *)(FLASH_BASE + 0x00))
#define FLASH_ACR_ENABLE_DATA_CACHE (1 << 10)
#define FLASH_ACR_ENABLE_INST_CACHE (1 << 9)
static void flash_set_waitstates(int waitstates)
{
FLASH_ACR |= waitstates | FLASH_ACR_ENABLE_DATA_CACHE | FLASH_ACR_ENABLE_INST_CACHE;
}
/*** RCC ***/
#define RCC_BASE (0x40023800)
#define RCC_CR (*(volatile uint32_t *)(RCC_BASE + 0x00))
#define RCC_PLLCFGR (*(volatile uint32_t *)(RCC_BASE + 0x04))
#define RCC_CFGR (*(volatile uint32_t *)(RCC_BASE + 0x08))
#define RCC_CR_PLLRDY (1 << 25)
#define RCC_CR_PLLON (1 << 24)
#define RCC_CR_HSERDY (1 << 17)
#define RCC_CR_HSEON (1 << 16)
#define RCC_CR_HSIRDY (1 << 1)
#define RCC_CR_HSION (1 << 0)
#define RCC_CFGR_SW_HSI 0x0
#define RCC_CFGR_SW_HSE 0x1
#define RCC_CFGR_SW_PLL 0x2
#define RCC_PLLCFGR_PLLSRC (1 << 22)
#define RCC_PRESCALER_DIV_NONE 0
#define RCC_PRESCALER_DIV_2 8
#define RCC_PRESCALER_DIV_4 9
void clock_pll_off(void)
{
uint32_t reg32;
/* Enable internal high-speed oscillator. */
RCC_CR |= RCC_CR_HSION;
DMB();
while ((RCC_CR & RCC_CR_HSIRDY) == 0) {};
/* Select HSI as SYSCLK source. */
reg32 = RCC_CFGR;
reg32 &= ~((1 << 1) | (1 << 0));
RCC_CFGR = (reg32 | RCC_CFGR_SW_HSI);
DMB();
/* Turn off PLL */
RCC_CR &= ~RCC_CR_PLLON;
DMB();
}
void clock_pll_on(void)
{
uint32_t reg32;
uint32_t plln, pllm, pllq, pllp, pllr, hpre, ppre1, ppre2, flash_waitstates;
/* Enable Power controller */
APB1_CLOCK_ER |= PWR_APB1_CLOCK_ER_VAL;
/* Select clock parameters (CPU Speed = 168MHz) */
pllm = 8;
plln = 336;
pllp = 2;
pllq = 7;
pllr = 0;
hpre = RCC_PRESCALER_DIV_NONE;
ppre1 = RCC_PRESCALER_DIV_4;
ppre2 = RCC_PRESCALER_DIV_2;
flash_waitstates = 3;
flash_set_waitstates(flash_waitstates);
/* Enable internal high-speed oscillator. */
RCC_CR |= RCC_CR_HSION;
DMB();
while ((RCC_CR & RCC_CR_HSIRDY) == 0) {};
/* Select HSI as SYSCLK source. */
reg32 = RCC_CFGR;
reg32 &= ~((1 << 1) | (1 << 0));
RCC_CFGR = (reg32 | RCC_CFGR_SW_HSI);
DMB();
/* Enable external high-speed oscillator 8MHz. */
RCC_CR |= RCC_CR_HSEON;
DMB();
while ((RCC_CR & RCC_CR_HSERDY) == 0) {};
/*
* Set prescalers for AHB, ADC, ABP1, ABP2.
*/
reg32 = RCC_CFGR;
reg32 &= ~(0xF0);
RCC_CFGR = (reg32 | (hpre << 4));
DMB();
reg32 = RCC_CFGR;
reg32 &= ~(0x1C00);
RCC_CFGR = (reg32 | (ppre1 << 10));
DMB();
reg32 = RCC_CFGR;
reg32 &= ~(0x07 << 13);
RCC_CFGR = (reg32 | (ppre2 << 13));
DMB();
/* Set PLL config */
reg32 = RCC_PLLCFGR;
reg32 &= ~(PLL_FULL_MASK);
RCC_PLLCFGR = reg32 | RCC_PLLCFGR_PLLSRC | pllm |
(plln << 6) | (((pllp >> 1) - 1) << 16) |
(pllq << 24);
DMB();
/* Enable PLL oscillator and wait for it to stabilize. */
RCC_CR |= RCC_CR_PLLON;
DMB();
while ((RCC_CR & RCC_CR_PLLRDY) == 0) {};
/* Select PLL as SYSCLK source. */
reg32 = RCC_CFGR;
reg32 &= ~((1 << 1) | (1 << 0));
RCC_CFGR = (reg32 | RCC_CFGR_SW_PLL);
DMB();
/* Wait for PLL clock to be selected. */
while ((RCC_CFGR & ((1 << 1) | (1 << 0))) != RCC_CFGR_SW_PLL) {};
/* Disable internal high-speed oscillator. */
RCC_CR &= ~RCC_CR_HSION;
}
void *__attribute__((weak)) memcpy(void *d, void *s, uint32_t len)
{
uint32_t *src, *dst;
uint8_t *sb, *db;
src = s;
dst = d;
while(len > 3) {
*(dst++) = *(src++);
len -= 4;
}
sb = (uint8_t *)src;
db = (uint8_t *)dst;
while(len > 0) {
*(db++) = *(sb++);
len--;
}
return d;
}
void panic(void)
{
printf("PANIC!");
while(1)
;
}

559
system.h Normal file
View file

@ -0,0 +1,559 @@
#ifndef SYSTEM_H_INCLUDED
#define SYSTEM_H_INCLUDED
#include <stdint.h>
/* System specific: PLL with 8 MHz external oscillator, CPU at 168MHz */
#define PLL_FULL_MASK (0x7F037FFF)
extern uint32_t cpu_freq;
void panic(void);
void printbin(const uint8_t *buf, int len); /* Defined in uart.c */
extern int _mutex_lock(void *); /* defined in mutex.S */
extern int _mutex_unlock(void *);
/* PIN CONFIG TARGET */
#define LED 0 // PE0
#define SPI_FLASH_PIN 4 /* Flash CS connected to GPIOA4 */
#define SPI1_PIN_AF 5
#define SPI1_CLOCK_PIN 5
#define SPI1_MISO_PIN 6
#define SPI1_MOSI_PIN 7
#define SPI2_PIN_AF 5
#define SPI2_CLOCK_PIN 13
#define SPI2_MISO_PIN 14
#define SPI2_MOSI_PIN 15
#define I2C1_PIN_AF 4
#define I2C1_SDA 7 /* GPIOB P7 */
#define I2C1_SCL 6 /* GPIOB P6 */
#define GPIO_MODE_AF (2)
/* STM32 specific defines */
#define APB1_CLOCK_ER (*(volatile uint32_t *)(0x40023840))
#define APB1_CLOCK_RST (*(volatile uint32_t *)(0x40023820))
#define TIM2_APB1_CLOCK_ER_VAL (1 << 0)
#define TIM3_APB1_CLOCK_ER_VAL (1 << 1)
#define TIM4_APB1_CLOCK_ER_VAL (1 << 2)
#define PWR_APB1_CLOCK_ER_VAL (1 << 28)
#define SPI2_APB1_CLOCK_ER_VAL (1 << 14)
#define APB2_CLOCK_ER (*(volatile uint32_t *)(0x40023844))
#define APB2_CLOCK_RST (*(volatile uint32_t *)(0x40023824))
#define SYSCFG_APB2_CLOCK_ER (1 << 14)
#define SPI1_APB2_CLOCK_ER_VAL (1 << 12)
#define SDIO_APB2_CLOCK_ER_VAL (1 << 11)
#define ADC1_APB2_CLOCK_ER_VAL (1 << 8)
#define TIM1_APB2_CLOCK_ER_VAL (1 << 0)
#define RCC_BACKUP (*(volatile uint32_t *)(0x40023870))
#define RCC_BACKUP_RESET (1 << 16)
#define RCC_BACKUP_RTCEN (1 << 15)
#define RCC_BACKUP_RTCSEL_SHIFT 8
#define RCC_BACKUP_RTCSEL_MASK 0x3
#define RCC_BACKUP_RTCSEL_NONE 0
#define RCC_BACKUP_RTCSEL_LSE 1
#define RCC_BACKUP_RTCSEL_LSI 2
#define RCC_BACKUP_RTCSEL_HSE 3
#define RCC_BACKUP_LSEMOD (1 << 3)
#define RCC_BACKUP_LSEBYP (1 << 2)
#define RCC_BACKUP_LSERDY (1 << 1)
#define RCC_BACKUP_LSEON (1 << 0)
#define RCC_CSR_LSION (1 << 0)
#define RCC_CSR_LSIRDY (1 << 1)
/* EXTI */
#define EXTI_CR_BASE (0x40013808)
#define EXTI_CR0 (*(volatile uint32_t *)(EXTI_CR_BASE + 0x00))
#define EXTI_CR_EXTI0_MASK (0xFFFF)
#define EXTI_IMR (*(volatile uint32_t *)(EXTI_BASE + 0x00))
#define EXTI_EMR (*(volatile uint32_t *)(EXTI_BASE + 0x04))
#define EXTI_RTSR (*(volatile uint32_t *)(EXTI_BASE + 0x08))
#define EXTI_FTSR (*(volatile uint32_t *)(EXTI_BASE + 0x0c))
#define EXTI_SWIER (*(volatile uint32_t *)(EXTI_BASE + 0x10))
#define EXTI_PR (*(volatile uint32_t *)(EXTI_BASE + 0x14))
/* HW RNG */
#define RNG_BASE (0x50060800)
#define RNG_CR (*(volatile uint32_t *)(RNG_BASE + 0x00))
#define RNG_SR (*(volatile uint32_t *)(RNG_BASE + 0x04))
#define RNG_DR (*(volatile uint32_t *)(RNG_BASE + 0x08))
#define RNG_CR_IE (1 << 3)
#define RNG_CR_RNGEN (1 << 2)
#define RNG_SR_DRDY (1 << 0)
#define RNG_SR_CECS (1 << 1)
#define RNG_SR_SECS (1 << 2)
/* SCB for sleep configuration */
#define SCB_SCR (*(volatile uint32_t *)(0xE000ED10))
#define SCB_SCR_SEVONPEND (1 << 4)
#define SCB_SCR_SLEEPDEEP (1 << 2)
#define SCB_SCR_SLEEPONEXIT (1 << 1)
/* Assembly helpers */
#define DMB() __asm__ volatile ("dmb")
#define WFI() __asm__ volatile ("wfi")
#define WFE() __asm__ volatile ("wfe")
#define SEV() __asm__ volatile ("sev")
/* Master clock setting */
void clock_pll_on(void);
void clock_pll_off(void);
/* NVIC */
/* NVIC ISER Base register (Cortex-M) */
#define NVIC_RTC_IRQ (3)
#define NVIC_TIM1_IRQN (27)
#define NVIC_TIM2_IRQN (28)
#define NVIC_TIM3_IRQN (29)
#define NVIC_TIM4_IRQN (30)
#define NVIC_ISER_BASE (0xE000E100)
#define NVIC_ICER_BASE (0xE000E180)
#define NVIC_ICPR_BASE (0xE000E280)
#define NVIC_IPRI_BASE (0xE000E400)
#define NVIC_EXTI0_IRQ (6)
#define NVIC_EXTI9_5_IRQ (23)
#define NVIC_EXTI15_10_IRQ (40)
static inline void nvic_irq_enable(uint8_t n)
{
int i = n / 32;
volatile uint32_t *nvic_iser = ((volatile uint32_t *)(NVIC_ISER_BASE + 4 * i));
*nvic_iser |= (1 << (n % 32));
}
static inline void nvic_irq_disable(uint8_t n)
{
int i = n / 32;
volatile uint32_t *nvic_icer = ((volatile uint32_t *)(NVIC_ICER_BASE + 4 * i));
*nvic_icer |= (1 << (n % 32));
}
static inline void nvic_irq_setprio(uint8_t n, uint8_t prio)
{
volatile uint8_t *nvic_ipri = ((volatile uint8_t *)(NVIC_IPRI_BASE + n));
*nvic_ipri = prio;
}
static inline void nvic_irq_clear(uint8_t n)
{
int i = n / 32;
volatile uint8_t *nvic_icpr = ((volatile uint8_t *)(NVIC_ICPR_BASE + 4 * i));
*nvic_icpr = (1 << (n % 32));
}
/*** FLASH ***/
#define FLASH_BASE (0x40023C00)
#define FLASH_ACR (*(volatile uint32_t *)(FLASH_BASE + 0x00))
#define FLASH_ACR_ENABLE_DATA_CACHE (1 << 10)
#define FLASH_ACR_ENABLE_INST_CACHE (1 << 9)
/*** SPI ***/
#define SPI1 (0x40013000)
#define SPI1_CR1 (*(volatile uint32_t *)(SPI1))
#define SPI1_CR2 (*(volatile uint32_t *)(SPI1 + 0x04))
#define SPI1_SR (*(volatile uint32_t *)(SPI1 + 0x08))
#define SPI1_DR (*(volatile uint32_t *)(SPI1 + 0x0c))
#define SPI2 (0x40003800)
#define SPI2_CR1 (*(volatile uint32_t *)(SPI2))
#define SPI2_CR2 (*(volatile uint32_t *)(SPI2 + 0x04))
#define SPI2_SR (*(volatile uint32_t *)(SPI2 + 0x08))
#define SPI2_DR (*(volatile uint32_t *)(SPI2 + 0x0c))
#define SPI_CR1_CLOCK_PHASE (1 << 0)
#define SPI_CR1_CLOCK_POLARITY (1 << 1)
#define SPI_CR1_MASTER (1 << 2)
#define SPI_CR1_BAUDRATE (0x07 << 3)
#define SPI_CR1_SPI_EN (1 << 6)
#define SPI_CR1_LSBFIRST (1 << 7)
#define SPI_CR1_SSI (1 << 8)
#define SPI_CR1_SSM (1 << 9)
#define SPI_CR1_16BIT_FORMAT (1 << 11)
#define SPI_CR1_TX_CRC_NEXT (1 << 12)
#define SPI_CR1_HW_CRC_EN (1 << 13)
#define SPI_CR1_BIDIOE (1 << 14)
#define SPI_CR2_SSOE (1 << 2)
#define SPI_SR_RX_NOTEMPTY (1 << 0)
#define SPI_SR_TX_EMPTY (1 << 1)
#define SPI_SR_BUSY (1 << 7)
/*** RCC ***/
#define RCC_CR_PLLRDY (1 << 25)
#define RCC_CR_PLLON (1 << 24)
#define RCC_CR_HSERDY (1 << 17)
#define RCC_CR_HSEON (1 << 16)
#define RCC_CR_HSIRDY (1 << 1)
#define RCC_CR_HSION (1 << 0)
#define RCC_CFGR_SW_HSI 0x0
#define RCC_CFGR_SW_HSE 0x1
#define RCC_CFGR_SW_PLL 0x2
#define RCC_PRESCALER_DIV_NONE 0
#define RCC_PRESCALER_DIV_2 8
#define RCC_PRESCALER_DIV_4 9
#define RCC_PLLCFGR_PLLSRC (1 << 22)
#define AHB1_CLOCK_ER (*(volatile uint32_t *)(0x40023830))
#define GPIOA_AHB1_CLOCK_ER (1 << 0)
#define GPIOB_AHB1_CLOCK_ER (1 << 1)
#define GPIOC_AHB1_CLOCK_ER (1 << 2)
#define GPIOD_AHB1_CLOCK_ER (1 << 3)
#define GPIOE_AHB1_CLOCK_ER (1 << 4)
#define GPIOA_BASE 0x40020000
#define GPIOB_BASE 0x40020400
#define GPIOC_BASE 0x40020800
#define GPIOD_BASE 0x40020C00
#define GPIOE_BASE 0x40021000
#define GPIOA GPIOA_BASE
#define GPIOB GPIOB_BASE
#define GPIOC GPIOC_BASE
#define GPIOD GPIOD_BASE
#define GPIOE GPIOE_BASE
#define AHB2_CLOCK_ER (*(volatile uint32_t *)(0x40023834))
#define RNG_AHB2_CLOCK_ER (1 << 6)
/* POWER CONTROL REGISTER */
#define POW_BASE (0x40007000)
#define POW_CR (*(volatile uint32_t *)(POW_BASE + 0x00))
#define POW_SCR (*(volatile uint32_t *)(POW_BASE + 0x04))
#define POW_CR_VOS (1 << 14)
#define POW_CR_FPDS (1 << 9)
#define POW_CR_DPB (1 << 8)
#define POW_CR_CSBF (1 << 3)
#define POW_CR_CWUF (1 << 2)
#define POW_CR_PDDS (1 << 1)
#define POW_CR_LPDS (1 << 0)
#define POW_SCR_BRE (1 << 9)
#define POW_SCR_EWUP (1 << 4)
#define POW_SCR_BRR (1 << 3)
#define POW_SCR_WUF (1 << 0)
/* GPIOS */
#define GPIOA_MODE (*(volatile uint32_t *)(GPIOA_BASE + 0x00))
#define GPIOA_AFL (*(volatile uint32_t *)(GPIOA_BASE + 0x20))
#define GPIOA_AFH (*(volatile uint32_t *)(GPIOA_BASE + 0x24))
#define GPIOA_OSPD (*(volatile uint32_t *)(GPIOA_BASE + 0x08))
#define GPIOA_PUPD (*(volatile uint32_t *)(GPIOA_BASE + 0x0c))
#define GPIOA_BSRR (*(volatile uint32_t *)(GPIOA_BASE + 0x18))
#define GPIOA_ODR (*(volatile uint32_t *)(GPIOA_BASE + 0x14))
#define GPIOA_IDR (*(volatile uint32_t *)(GPIOA_BASE + 0x10))
#define GPIOB_MODE (*(volatile uint32_t *)(GPIOB_BASE + 0x00))
#define GPIOB_AFL (*(volatile uint32_t *)(GPIOB_BASE + 0x20))
#define GPIOB_AFH (*(volatile uint32_t *)(GPIOB_BASE + 0x24))
#define GPIOB_OSPD (*(volatile uint32_t *)(GPIOB_BASE + 0x08))
#define GPIOB_PUPD (*(volatile uint32_t *)(GPIOB_BASE + 0x0c))
#define GPIOB_BSRR (*(volatile uint32_t *)(GPIOB_BASE + 0x18))
#define GPIOB_ODR (*(volatile uint32_t *)(GPIOB_BASE + 0x14))
#define GPIOC_MODE (*(volatile uint32_t *)(GPIOC_BASE + 0x00))
#define GPIOC_OTYPE (*(volatile uint32_t *)(GPIOC_BASE + 0x04))
#define GPIOC_OSPEED (*(volatile uint32_t *)(GPIOC_BASE + 0x08))
#define GPIOC_AFL (*(volatile uint32_t *)(GPIOC_BASE + 0x20))
#define GPIOC_AFH (*(volatile uint32_t *)(GPIOC_BASE + 0x24))
#define GPIOC_OSPD (*(volatile uint32_t *)(GPIOC_BASE + 0x08))
#define GPIOC_PUPD (*(volatile uint32_t *)(GPIOC_BASE + 0x0c))
#define GPIOC_BSRR (*(volatile uint32_t *)(GPIOC_BASE + 0x18))
#define GPIOC_ODR (*(volatile uint32_t *)(GPIOC_BASE + 0x14))
#define GPIOD_MODE (*(volatile uint32_t *)(GPIOD_BASE + 0x00))
#define GPIOD_OTYPE (*(volatile uint32_t *)(GPIOD_BASE + 0x04))
#define GPIOD_OSPEED (*(volatile uint32_t *)(GPIOD_BASE + 0x08))
#define GPIOD_AFL (*(volatile uint32_t *)(GPIOD_BASE + 0x20))
#define GPIOD_AFH (*(volatile uint32_t *)(GPIOD_BASE + 0x24))
#define GPIOD_OSPD (*(volatile uint32_t *)(GPIOD_BASE + 0x08))
#define GPIOD_PUPD (*(volatile uint32_t *)(GPIOD_BASE + 0x0c))
#define GPIOD_BSRR (*(volatile uint32_t *)(GPIOD_BASE + 0x18))
#define GPIOD_ODR (*(volatile uint32_t *)(GPIOD_BASE + 0x14))
#define GPIOD_MODE (*(volatile uint32_t *)(GPIOD_BASE + 0x00))
#define GPIOD_OTYPE (*(volatile uint32_t *)(GPIOD_BASE + 0x04))
#define GPIOD_PUPD (*(volatile uint32_t *)(GPIOD_BASE + 0x0c))
#define GPIOD_ODR (*(volatile uint32_t *)(GPIOD_BASE + 0x14))
#define GPIOE_MODE (*(volatile uint32_t *)(GPIOE_BASE + 0x00))
#define GPIOE_AFL (*(volatile uint32_t *)(GPIOE_BASE + 0x20))
#define GPIOE_AFH (*(volatile uint32_t *)(GPIOE_BASE + 0x24))
#define GPIOE_OSPD (*(volatile uint32_t *)(GPIOE_BASE + 0x08))
#define GPIOE_PUPD (*(volatile uint32_t *)(GPIOE_BASE + 0x0c))
#define GPIOE_BSRR (*(volatile uint32_t *)(GPIOE_BASE + 0x18))
#define GPIOE_ODR (*(volatile uint32_t *)(GPIOE_BASE + 0x14))
#define GPIO_MODE_AF (2)
/* SDIO */
#define SDIO_BASE (0x40012C00)
#define SDIO_POWER (*(volatile uint32_t *)((SDIO_BASE) + 0x00))
#define SDIO_CLKCR (*(volatile uint32_t *)((SDIO_BASE) + 0x04))
#define SDIO_ARG (*(volatile uint32_t *)((SDIO_BASE) + 0x08))
#define SDIO_CMD (*(volatile uint32_t *)((SDIO_BASE) + 0x0C))
#define SDIO_RESPCMD (*(volatile uint32_t *)((SDIO_BASE) + 0x10))
#define SDIO_RESP1 (*(volatile uint32_t *)((SDIO_BASE) + 0x14))
#define SDIO_RESP2 (*(volatile uint32_t *)((SDIO_BASE) + 0x18))
#define SDIO_RESP3 (*(volatile uint32_t *)((SDIO_BASE) + 0x1C))
#define SDIO_RESP4 (*(volatile uint32_t *)((SDIO_BASE) + 0x20))
#define SDIO_DTIMER (*(volatile uint32_t *)((SDIO_BASE) + 0x24))
#define SDIO_DLEN (*(volatile uint32_t *)((SDIO_BASE) + 0x28))
#define SDIO_DCTRL (*(volatile uint32_t *)((SDIO_BASE) + 0x2C))
#define SDIO_DCOUNT (*(volatile uint32_t *)((SDIO_BASE) + 0x30))
#define SDIO_STA (*(volatile uint32_t *)((SDIO_BASE) + 0x34))
#define SDIO_ICR (*(volatile uint32_t *)((SDIO_BASE) + 0x38))
#define SDIO_MASK (*(volatile uint32_t *)((SDIO_BASE) + 0x3C))
#define SDIO_FIFOCNT (*(volatile uint32_t *)((SDIO_BASE) + 0x48))
#define SDIO_FIFO (*(volatile uint32_t *)((SDIO_BASE) + 0x80))
#define SDIO_POWER_PWRCTRL_SHIFT 0
#define SDIO_POWER_PWRCTRL_PWROFF (0x0 << SDIO_POWER_PWRCTRL_SHIFT)
#define SDIO_POWER_PWRCTRL_RSVPWRUP (0x2 << SDIO_POWER_PWRCTRL_SHIFT)
#define SDIO_POWER_PWRCTRL_PWRON (0x3 << SDIO_POWER_PWRCTRL_SHIFT)
#define SDIO_CLKCR_HWFC_EN (1 << 14)
#define SDIO_CLKCR_NEGEDGE (1 << 13)
#define SDIO_CLKCR_WIDBUS_SHIFT 11
#define SDIO_CLKCR_WIDBUS_1 (0x0 << SDIO_CLKCR_WIDBUS_SHIFT)
#define SDIO_CLKCR_WIDBUS_4 (0x1 << SDIO_CLKCR_WIDBUS_SHIFT)
#define SDIO_CLKCR_WIDBUS_8 (0x2 << SDIO_CLKCR_WIDBUS_SHIFT)
#define SDIO_CLKCR_BYPASS (1 << 10)
#define SDIO_CLKCR_PWRSAV (1 << 9)
#define SDIO_CLKCR_CLKEN (1 << 8)
#define SDIO_CLKCR_CLKDIV_SHIFT 0
#define SDIO_CLKCR_CLKDIV_MSK (0xFF << SDIO_CLKCR_CLKDIV_SHIFT)
#define SDIO_CMD_ATACMD (1 << 14)
#define SDIO_CMD_NIEN (1 << 13)
#define SDIO_CMD_ENCMDCOMPL (1 << 12)
#define SDIO_CMD_SDIOSUSPEND (1 << 11)
#define SDIO_CMD_CPSMEN (1 << 10)
#define SDIO_CMD_WAITPEND (1 << 9)
#define SDIO_CMD_WAITINT (1 << 8)
#define SDIO_CMD_WAITRESP_SHIFT 6
#define SDIO_CMD_WAITRESP_NO_0 (0x0 << SDIO_CMD_WAITRESP_SHIFT)
#define SDIO_CMD_WAITRESP_SHORT (0x1 << SDIO_CMD_WAITRESP_SHIFT)
#define SDIO_CMD_WAITRESP_NO_2 (0x2 << SDIO_CMD_WAITRESP_SHIFT)
#define SDIO_CMD_WAITRESP_LONG (0x3 << SDIO_CMD_WAITRESP_SHIFT)
#define SDIO_CMD_CMDINDEX_SHIFT 0
#define SDIO_CMD_CMDINDEX_MSK (0x3F << SDIO_CMD_CMDINDEX_SHIFT)
#define SDIO_RESPCMD_SHIFT 0
#define SDIO_RESPCMD_MSK (0x3F << SDIO_RESPCMD_SHIFT)
#define SDIO_DCTRL_SDIOEN (1 << 11)
#define SDIO_DCTRL_RWMOD (1 << 10)
#define SDIO_DCTRL_RWSTOP (1 << 9)
#define SDIO_DCTRL_RWSTART (1 << 8)
#define SDIO_DCTRL_DBLOCKSIZE_SHIFT 4
#define SDIO_DCTRL_DBLOCKSIZE_0 (0x0 << SDIO_DCTRL_DBLOCKSIZE_SHIFT)
#define SDIO_DCTRL_DBLOCKSIZE_1 (0x1 << SDIO_DCTRL_DBLOCKSIZE_SHIFT)
#define SDIO_DCTRL_DBLOCKSIZE_2 (0x2 << SDIO_DCTRL_DBLOCKSIZE_SHIFT)
#define SDIO_DCTRL_DBLOCKSIZE_3 (0x3 << SDIO_DCTRL_DBLOCKSIZE_SHIFT)
#define SDIO_DCTRL_DBLOCKSIZE_4 (0x4 << SDIO_DCTRL_DBLOCKSIZE_SHIFT)
#define SDIO_DCTRL_DBLOCKSIZE_5 (0x5 << SDIO_DCTRL_DBLOCKSIZE_SHIFT)
#define SDIO_DCTRL_DBLOCKSIZE_6 (0x6 << SDIO_DCTRL_DBLOCKSIZE_SHIFT)
#define SDIO_DCTRL_DBLOCKSIZE_7 (0x7 << SDIO_DCTRL_DBLOCKSIZE_SHIFT)
#define SDIO_DCTRL_DBLOCKSIZE_8 (0x8 << SDIO_DCTRL_DBLOCKSIZE_SHIFT)
#define SDIO_DCTRL_DBLOCKSIZE_9 (0x9 << SDIO_DCTRL_DBLOCKSIZE_SHIFT)
#define SDIO_DCTRL_DBLOCKSIZE_10 (0xA << SDIO_DCTRL_DBLOCKSIZE_SHIFT)
#define SDIO_DCTRL_DBLOCKSIZE_11 (0xB << SDIO_DCTRL_DBLOCKSIZE_SHIFT)
#define SDIO_DCTRL_DBLOCKSIZE_12 (0xC << SDIO_DCTRL_DBLOCKSIZE_SHIFT)
#define SDIO_DCTRL_DBLOCKSIZE_13 (0xD << SDIO_DCTRL_DBLOCKSIZE_SHIFT)
#define SDIO_DCTRL_DBLOCKSIZE_14 (0xE << SDIO_DCTRL_DBLOCKSIZE_SHIFT)
#define SDIO_DCTRL_DMAEN (1 << 3)
#define SDIO_DCTRL_DTMODE (1 << 2)
#define SDIO_DCTRL_DTDIR (1 << 1)
#define SDIO_DCTRL_DTEN (1 << 0)
#define SDIO_STA_CEATAEND (1 << 23)
#define SDIO_STA_SDIOIT (1 << 22)
#define SDIO_STA_RXDAVL (1 << 21)
#define SDIO_STA_TXDAVL (1 << 20)
#define SDIO_STA_RXFIFOE (1 << 19)
#define SDIO_STA_TXFIFOE (1 << 18)
#define SDIO_STA_RXFIFOF (1 << 17)
#define SDIO_STA_TXFIFOF (1 << 16)
#define SDIO_STA_RXFIFOHF (1 << 15)
#define SDIO_STA_TXFIFOHE (1 << 14)
#define SDIO_STA_RXACT (1 << 13)
#define SDIO_STA_TXACT (1 << 12)
#define SDIO_STA_CMDACT (1 << 11)
#define SDIO_STA_DBCKEND (1 << 10)
#define SDIO_STA_STBITERR (1 << 9)
#define SDIO_STA_DATAEND (1 << 8)
#define SDIO_STA_CMDSENT (1 << 7)
#define SDIO_STA_CMDREND (1 << 6)
#define SDIO_STA_RXOVERR (1 << 5)
#define SDIO_STA_TXUNDERR (1 << 4)
#define SDIO_STA_DTIMEOUT (1 << 3)
#define SDIO_STA_CTIMEOUT (1 << 2)
#define SDIO_STA_DCRCFAIL (1 << 1)
#define SDIO_STA_CCRCFAIL (1 << 0)
#define SDIO_ICR_CEATAENDC (1 << 23)
#define SDIO_ICR_SDIOITC (1 << 22)
#define SDIO_ICR_DBCKENDC (1 << 10)
#define SDIO_ICR_STBITERRC (1 << 9)
#define SDIO_ICR_DATAENDC (1 << 8)
#define SDIO_ICR_CMDSENTC (1 << 7)
#define SDIO_ICR_CMDRENDC (1 << 6)
#define SDIO_ICR_RXOVERRC (1 << 5)
#define SDIO_ICR_TXUNDERRC (1 << 4)
#define SDIO_ICR_DTIMEOUTC (1 << 3)
#define SDIO_ICR_CTIMEOUTC (1 << 2)
#define SDIO_ICR_DCRCFAILC (1 << 1)
#define SDIO_ICR_CCRCFAILC (1 << 0)
#define SDIO_MASK_CEATAENDIE (1 << 23)
#define SDIO_MASK_SDIOITIE (1 << 22)
#define SDIO_MASK_RXDAVLIE (1 << 21)
#define SDIO_MASK_TXDAVLIE (1 << 20)
#define SDIO_MASK_RXFIFOEIE (1 << 19)
#define SDIO_MASK_TXFIFOEIE (1 << 18)
#define SDIO_MASK_RXFIFOFIE (1 << 17)
#define SDIO_MASK_TXFIFOFIE (1 << 16)
#define SDIO_MASK_RXFIFOHFIE (1 << 15)
#define SDIO_MASK_TXFIFOHEIE (1 << 14)
#define SDIO_MASK_RXACTIE (1 << 13)
#define SDIO_MASK_TXACTIE (1 << 12)
#define SDIO_MASK_CMDACTIE (1 << 11)
#define SDIO_MASK_DBCKENDIE (1 << 10)
#define SDIO_MASK_STBITERRIE (1 << 9)
#define SDIO_MASK_DATAENDIE (1 << 8)
#define SDIO_MASK_CMDSENTIE (1 << 7)
#define SDIO_MASK_CMDRENDIE (1 << 6)
#define SDIO_MASK_RXOVERRIE (1 << 5)
#define SDIO_MASK_TXUNDERRIE (1 << 4)
#define SDIO_MASK_DTIMEOUTIE (1 << 3)
#define SDIO_MASK_CTIMEOUTIE (1 << 2)
#define SDIO_MASK_DCRCFAILIE (1 << 1)
#define SDIO_MASK_CCRCFAILIE (1 << 0)
/* Timers */
#define TIM1_BASE (0x40010000)
#define TIM1_CR1 (*(volatile uint32_t *)(TIM1_BASE + 0x00))
#define TIM1_DIER (*(volatile uint32_t *)(TIM1_BASE + 0x0c))
#define TIM1_SR (*(volatile uint32_t *)(TIM1_BASE + 0x10))
#define TIM1_EGR (*(volatile uint16_t *)(TIM1_BASE + 0x14))
#define TIM1_CCMR1 (*(volatile uint16_t *)(TIM1_BASE + 0x18))
#define TIM1_CCMR2 (*(volatile uint16_t *)(TIM1_BASE + 0x1c))
#define TIM1_CCER (*(volatile uint16_t *)(TIM1_BASE + 0x20))
#define TIM1_CNT (*(volatile uint16_t *)(TIM1_BASE + 0x24))
#define TIM1_PSC (*(volatile uint16_t *)(TIM1_BASE + 0x28))
#define TIM1_ARR (*(volatile uint16_t *)(TIM1_BASE + 0x2c))
#define TIM1_CCR1 (*(volatile uint32_t *)(TIM1_BASE + 0x34))
#define TIM1_CCR2 (*(volatile uint32_t *)(TIM1_BASE + 0x3C))
#define TIM1_CCR3 (*(volatile uint32_t *)(TIM1_BASE + 0x38))
#define TIM1_CCR4 (*(volatile uint32_t *)(TIM1_BASE + 0x40))
#define TIM2_BASE (0x40000000)
#define TIM2_CR1 (*(volatile uint32_t *)(TIM2_BASE + 0x00))
#define TIM2_DIER (*(volatile uint32_t *)(TIM2_BASE + 0x0c))
#define TIM2_SR (*(volatile uint32_t *)(TIM2_BASE + 0x10))
#define TIM2_EGR (*(volatile uint16_t *)(TIM2_BASE + 0x14))
#define TIM2_CCMR1 (*(volatile uint16_t *)(TIM2_BASE + 0x18))
#define TIM2_CCMR2 (*(volatile uint16_t *)(TIM2_BASE + 0x1c))
#define TIM2_CCER (*(volatile uint16_t *)(TIM2_BASE + 0x20))
#define TIM2_CNT (*(volatile uint32_t *)(TIM2_BASE + 0x24))
#define TIM2_PSC (*(volatile uint32_t *)(TIM2_BASE + 0x28))
#define TIM2_ARR (*(volatile uint32_t *)(TIM2_BASE + 0x2c))
#define TIM2_CCR1 (*(volatile uint32_t *)(TIM2_BASE + 0x34))
#define TIM2_CCR2 (*(volatile uint32_t *)(TIM2_BASE + 0x3C))
#define TIM2_CCR3 (*(volatile uint32_t *)(TIM2_BASE + 0x38))
#define TIM2_CCR4 (*(volatile uint32_t *)(TIM2_BASE + 0x40))
#define TIM3_BASE (0x40000400)
#define TIM3_CR1 (*(volatile uint32_t *)(TIM3_BASE + 0x00))
#define TIM3_DIER (*(volatile uint32_t *)(TIM3_BASE + 0x0c))
#define TIM3_SR (*(volatile uint32_t *)(TIM3_BASE + 0x10))
#define TIM3_EGR (*(volatile uint16_t *)(TIM3_BASE + 0x14))
#define TIM3_CCMR1 (*(volatile uint16_t *)(TIM3_BASE + 0x18))
#define TIM3_CCMR2 (*(volatile uint16_t *)(TIM3_BASE + 0x1c))
#define TIM3_CCER (*(volatile uint16_t *)(TIM3_BASE + 0x20))
#define TIM3_CNT (*(volatile uint16_t *)(TIM3_BASE + 0x24))
#define TIM3_PSC (*(volatile uint16_t *)(TIM3_BASE + 0x28))
#define TIM3_ARR (*(volatile uint16_t *)(TIM3_BASE + 0x2c))
#define TIM3_CCR1 (*(volatile uint32_t *)(TIM3_BASE + 0x34))
#define TIM3_CCR2 (*(volatile uint32_t *)(TIM3_BASE + 0x3C))
#define TIM3_CCR3 (*(volatile uint32_t *)(TIM3_BASE + 0x38))
#define TIM3_CCR4 (*(volatile uint32_t *)(TIM3_BASE + 0x40))
#define TIM4_BASE (0x40000800)
#define TIM4_CR1 (*(volatile uint32_t *)(TIM4_BASE + 0x00))
#define TIM4_DIER (*(volatile uint32_t *)(TIM4_BASE + 0x0c))
#define TIM4_SR (*(volatile uint32_t *)(TIM4_BASE + 0x10))
#define TIM4_CCMR1 (*(volatile uint16_t *)(TIM4_BASE + 0x18))
#define TIM4_CCMR2 (*(volatile uint16_t *)(TIM4_BASE + 0x1c))
#define TIM4_CCER (*(volatile uint16_t *)(TIM4_BASE + 0x20))
#define TIM4_CNT (*(volatile uint16_t *)(TIM4_BASE + 0x24))
#define TIM4_PSC (*(volatile uint16_t *)(TIM4_BASE + 0x28))
#define TIM4_ARR (*(volatile uint16_t *)(TIM4_BASE + 0x2c))
#define TIM_DIER_UIE (1 << 0)
#define TIM_SR_UIF (1 << 0)
#define TIM_CR1_CLOCK_ENABLE (1 << 0)
#define TIM_CR1_UPD_RS (1 << 2)
#define TIM_CR1_ARPE (1 << 7)
#define TIM_CCER_CC1_ENABLE (1 << 0)
#define TIM_CCER_CC2_ENABLE (1 << 4)
#define TIM_CCER_CC3_ENABLE (1 << 8)
#define TIM_CCER_CC4_ENABLE (1 << 12)
#define TIM_CCMR1_OC1M_PWM1 (0x06 << 4) | (1 << 3)
#define TIM_CCMR1_OC2M_PWM1 (0x06 << 12) | (1 << 11)
#define TIM_CCMR2_OC3M_PWM1 (0x06 << 4) | (1 << 3)
#define TIM_CCMR2_OC4M_PWM1 (0x06 << 12) | (1 << 11)
#define AHB1_CLOCK_ER (*(volatile uint32_t *)(0x40023830))
#define GPIOD_AHB1_CLOCK_ER (1 << 3)
/* ADC */
#define ADC1_BASE (0x40012000)
#define ADC_COM_BASE (0x40012300)
#define ADC_COM_CCR (*(volatile uint32_t *)(ADC_COM_BASE + 0x04))
#define ADC1_SR (*(volatile uint32_t *)(ADC1_BASE + 0x00))
#define ADC1_CR1 (*(volatile uint32_t *)(ADC1_BASE + 0x04))
#define ADC1_CR2 (*(volatile uint32_t *)(ADC1_BASE + 0x08))
#define ADC1_SMPR1 (*(volatile uint32_t *)(ADC1_BASE + 0x0c))
#define ADC1_SMPR2 (*(volatile uint32_t *)(ADC1_BASE + 0x10))
#define ADC1_SQR3 (*(volatile uint32_t *)(ADC1_BASE + 0x34))
#define ADC1_DR (*(volatile uint32_t *)(ADC1_BASE + 0x4c))
#define ADC_CR1_SCAN (1 << 8)
#define ADC_CR2_EN (1 << 0)
#define ADC_CR2_CONT (1 << 1)
#define ADC_CR2_SWSTART (1 << 30)
#define ADC_SR_EOC (1 << 1)
#define ADC_SMPR_SMP_480CYC (0x7)
/* Reboot */
#define AIRCR *(volatile uint32_t *)(0xE000ED0C)
#define AIRCR_VKEY (0x05FA << 16)
# define AIRCR_SYSRESETREQ (1 << 2)
static inline void reboot(void)
{
AIRCR = AIRCR_SYSRESETREQ | AIRCR_VKEY;
}
#endif

42
systick.c Normal file
View file

@ -0,0 +1,42 @@
/*
* (c) danielinux 2019
*
* GPLv.2
*
* See LICENSE for details
*/
#include "system.h"
#include "systick.h"
#include <stdint.h>
/*** SYSTICK ***/
#define SYSTICK_BASE (0xE000E010)
#define SYSTICK_CSR (*(volatile uint32_t *)(SYSTICK_BASE + 0x00))
#define SYSTICK_RVR (*(volatile uint32_t *)(SYSTICK_BASE + 0x04))
#define SYSTICK_CVR (*(volatile uint32_t *)(SYSTICK_BASE + 0x08))
#define SYSTICK_CALIB (*(volatile uint32_t *)(SYSTICK_BASE + 0x0C))
volatile unsigned int jiffies = 0;
void systick_enable(void)
{
SYSTICK_RVR = ((cpu_freq / 1000) - 1);
SYSTICK_CVR = 0;
SYSTICK_CSR |= 0x07;
}
void systick_disable(void)
{
SYSTICK_CSR &= ~1;
}
void isr_systick(void)
{
++jiffies;
}
uint32_t HAL_GetTick(void)
{
return jiffies;
}

5
systick.h Normal file
View file

@ -0,0 +1,5 @@
#ifndef SYSTICK_H_INCLUDED
#define SYSTICK_H_INCLUDED
extern volatile unsigned int jiffies;
void systick_enable(void);
#endif

49
target.ld Normal file
View file

@ -0,0 +1,49 @@
MEMORY
{
FLASH (rx) : ORIGIN = 0x00000000, LENGTH = 256K - 0x100
RAM (rw) : ORIGIN = 0x20001000, LENGTH = 60K
RAM_S (rw) : ORIGIN = 0x20000000, LENGTH = 4K
}
SECTIONS
{
.text :
{
_start_text = .;
KEEP(*(.isr_vector))
*(.text*)
*(.rodata*)
. = ALIGN(4);
_end_text = .;
} > FLASH
.edidx :
{
. = ALIGN(4);
*(.ARM.exidx*)
} > FLASH
_stored_data = .;
.data : AT (_stored_data)
{
_start_data = .;
*(.data*)
. = ALIGN(4);
_end_data = .;
} > RAM
.bss :
{
_start_bss = .;
*(.bss*)
*(COMMON)
. = ALIGN(4);
_end_bss = .;
_end = .;
} > RAM
}
PROVIDE(_start_heap = _end);
PROVIDE(_end_stack = ORIGIN(RAM_S) + LENGTH(RAM_S));

57
timer.c Normal file
View file

@ -0,0 +1,57 @@
#include <stdint.h>
#include "system.h"
static uint32_t master_clock = 0;
/* Timer 4: Use val 60000 with PSC 1400 for 1s tick (84 Mhz) */
/* Timer 4: Use val 52500 with PSC 200 for 1/8 s tick (84 Mhz) */
#define TMR4_INIT_VAL 52500
#define TMR4_INIT_PSC 200
void timer_init(void)
{
uint32_t val = 0;
uint32_t psc = 1;
uint32_t err = 0;
nvic_irq_enable(NVIC_TIM4_IRQN);
nvic_irq_setprio(NVIC_TIM4_IRQN, 0);
APB1_CLOCK_RST |= TIM4_APB1_CLOCK_ER_VAL;
__asm__ volatile ("dmb");
APB1_CLOCK_RST &= ~TIM4_APB1_CLOCK_ER_VAL;
APB1_CLOCK_ER |= TIM4_APB1_CLOCK_ER_VAL;
TIM4_CR1 = 0;
__asm__ volatile ("dmb");
TIM4_PSC = TMR4_INIT_PSC;
TIM4_ARR = TMR4_INIT_VAL;
TIM4_CR1 |= TIM_CR1_CLOCK_ENABLE;
TIM4_DIER |= TIM_DIER_UIE;
__asm__ volatile ("dmb");
}
static volatile uint32_t tim4_ticks = 0;
void isr_tim1(void)
{
TIM1_SR &= ~TIM_SR_UIF;
}
void isr_tim3(void)
{
TIM3_SR &= ~TIM_SR_UIF;
}
void isr_tim4(void)
{
TIM4_SR &= ~TIM_SR_UIF;
tim4_ticks++;
}
void gettime(uint32_t *seconds, uint32_t *microseconds)
{
*microseconds = ((TIM4_CNT * TMR4_INIT_PSC) / 84) + (tim4_ticks & 0x07) * 125000;
*seconds = (tim4_ticks >> 3);
}

142
uart.c Normal file
View file

@ -0,0 +1,142 @@
/*
* (c) danielinux 2019
*
* GPLv.2
*
* See LICENSE for details
*/
#include <stdint.h>
#include <stdio.h>
#include "uart.h"
#include "system.h"
#define UART2 (0x40004400)
#define UART2_SR (*(volatile uint32_t *)(UART2))
#define UART2_DR (*(volatile uint32_t *)(UART2 + 0x04))
#define UART2_BRR (*(volatile uint32_t *)(UART2 + 0x08))
#define UART2_CR1 (*(volatile uint32_t *)(UART2 + 0x0c))
#define UART2_CR2 (*(volatile uint32_t *)(UART2 + 0x10))
#define UART_CR1_UART_ENABLE (1 << 13)
#define UART_CR1_SYMBOL_LEN (1 << 12)
#define UART_CR1_PARITY_ENABLED (1 << 10)
#define UART_CR1_PARITY_ODD (1 << 9)
#define UART_CR1_TX_ENABLE (1 << 3)
#define UART_CR1_RX_ENABLE (1 << 2)
#define UART_CR2_STOPBITS (3 << 12)
#define UART_SR_TX_EMPTY (1 << 7)
#define UART_SR_RX_NOTEMPTY (1 << 5)
#define APB1_CLOCK_ER (*(volatile uint32_t *)(0x40023840))
#define UART2_APB1_CLOCK_ER_VAL (1 << 17)
#define AHB1_CLOCK_ER (*(volatile uint32_t *)(0x40023830))
#define GPIO_MODE_AF (2)
#define UART2_PIN_AF 7
#define UART2_RX_PIN 2
#define UART2_TX_PIN 3
static void uart2_pins_setup(void)
{
uint32_t reg;
AHB1_CLOCK_ER |= GPIOA_AHB1_CLOCK_ER;
/* Set mode = AF */
reg = GPIOA_MODE & ~ (0x03 << (UART2_RX_PIN * 2));
GPIOA_MODE = reg | (2 << (UART2_RX_PIN * 2));
reg = GPIOA_MODE & ~ (0x03 << (UART2_TX_PIN * 2));
GPIOA_MODE = reg | (2 << (UART2_TX_PIN * 2));
/* Alternate function: use low pins */
reg = GPIOA_AFL & ~(0xf << ((UART2_TX_PIN) * 4));
GPIOA_AFL = reg | (UART2_PIN_AF << ((UART2_TX_PIN) * 4));
reg = GPIOA_AFL & ~(0xf << ((UART2_RX_PIN) * 4));
GPIOA_AFL = reg | (UART2_PIN_AF << ((UART2_RX_PIN) * 4));
}
int uart2_setup(uint32_t bitrate, uint8_t data, char parity, uint8_t stop)
{
uint32_t reg;
int pin_rx, pin_tx, pin_af;
/* Enable pins and configure for AF7 */
uart2_pins_setup();
/* Turn on the device */
APB1_CLOCK_ER |= UART2_APB1_CLOCK_ER_VAL;
/* Configure for TX */
UART2_CR1 |= UART_CR1_TX_ENABLE | UART_CR1_RX_ENABLE;
/* Configure clock */
UART2_BRR = cpu_freq / bitrate;
/* Configure data bits */
if (data == 8)
UART2_CR1 &= ~UART_CR1_SYMBOL_LEN;
else
UART2_CR1 |= UART_CR1_SYMBOL_LEN;
/* Configure parity */
switch (parity) {
case 'O':
UART2_CR1 |= UART_CR1_PARITY_ODD;
/* fall through to enable parity */
case 'E':
UART2_CR1 |= UART_CR1_PARITY_ENABLED;
break;
default:
UART2_CR1 &= ~(UART_CR1_PARITY_ENABLED | UART_CR1_PARITY_ODD);
}
/* Set stop bits */
reg = UART2_CR2 & ~UART_CR2_STOPBITS;
if (stop > 1)
UART2_CR2 = reg & (2 << 12);
else
UART2_CR2 = reg;
/* Turn on uart */
UART2_CR1 |= UART_CR1_UART_ENABLE;
return 0;
}
int _write(void *r, uint8_t *text, int len)
{
char *p = (char *)text;
int i;
volatile uint32_t reg;
text[len - 1] = 0;
while(*p) {
do {
reg = UART2_SR;
} while ((reg & UART_SR_TX_EMPTY) == 0);
UART2_DR = *p;
p++;
}
return len;
}
char uart_read(void)
{
uint32_t reg;
reg = UART2_SR;
if (reg & UART_SR_RX_NOTEMPTY)
return (char)(UART2_DR);
else
return 0;
}
/* commodity to print binary buffers */
void printbin(const uint8_t *buf, int len)
{
int i;
for (i = 0; i < len; i++) {
if ((i % 16) == 0)
printf("\r\n%08x: ", i);
printf("%02x ", buf[i]);
}
printf("\r\n");
}

9
uart.h Normal file
View file

@ -0,0 +1,9 @@
#ifndef UART_H_INCLUDED
#define UART_H_INCLUDED
#include <stdint.h>
int uart2_setup(uint32_t bitrate, uint8_t data, char parity, uint8_t stop);
void uart2_write(const char *text);
#endif

181
ui.c Normal file
View file

@ -0,0 +1,181 @@
/*
* (c) danielinux 2019
*
* GPLv.2
*
* See LICENSE for details
*/
#include <stdint.h>
#include "system.h"
#include "display.h"
#include "systick.h"
#include "button.h"
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
#include "ui.h"
/* Uncomment for device initialization */
//#define DEVICE_INITIALIZATION
static const char welcome_message0[]= " Waveblender ";
static const char welcome_message1[]= " (c) 2020 ";
static const char welcome_message2[]= " danielinux ";
static uint32_t last_action = 0;
static uint32_t offset = 0;
#define ST_LOCKED 0
#define ST_PIN_ENTRY 1
#define ST_UNLOCKED 2
#define MAX_PASSWORD 32
static int fsm_state = ST_LOCKED;
static int sleeping = 0;
static char password[MAX_PASSWORD] = {};
static int pin_idx = 0;
#define SLEEP_TIME (5000)
static void ui_sleep(void)
{
display_scroll(NULL, 0);
display_clear(NULL);
sleeping = 1;
}
static int ui_wakeup(void)
{
last_action = jiffies;
if (sleeping) {
sleeping = 0;
return 1;
}
return 0;
}
void ui_msg(const char *txt)
{
ui_wakeup();
display_scroll(NULL, 0);
display_clear(NULL);
display_text(6, txt);
}
static uint8_t display_cur_v = 0;
static uint8_t menu_selection = 0;
void ui_menu_autoscroll(void)
{
int lines = CurrentMenu->entry_n;
if ((lines < 5) || (menu_selection < 2))
display_cur_v = 0;
else if (menu_selection > lines - 2)
display_cur_v = 0x40 - ((lines - 4) * 8);
else
display_cur_v = 0x40 - ((menu_selection - 2) * 8);
display_scroll(NULL, display_cur_v);
}
static void ui_display_menu_refresh(void)
{
const struct display_menu *menu = CurrentMenu;
uint8_t vline;
int i;
display_scroll(NULL, display_cur_v);
display_clear(NULL);
for (i = 0; i < menu->entry_n; i++) {
vline = i + 4;
if (vline > 7)
vline -= 8;
if (i == menu_selection)
display_text_inverse(vline, menu->entry[i].title);
else
display_text(vline, menu->entry[i].title);
}
WFI();
}
void ui_display_menu(const struct display_menu *menu)
{
uint8_t i;
display_clear(NULL);
menu_selection = 0;
display_cur_v = 0;
CurrentMenu = (struct display_menu *)menu;
ui_display_menu_refresh();
}
void ui_button_press(uint8_t b, int hold)
{
if (b == '+') {
int n = menu_selection;
menu_selection = 0;
if (CurrentMenu->entry[n].action) {
display_cur_v = 0;
display_clear(NULL);
display_scroll(NULL, display_cur_v);
CurrentMenu->entry[n].action(
CurrentMenu->entry[n].arg);
}
return;
}
if (b == 'U') {
if (menu_selection > 0) {
menu_selection--;
ui_menu_autoscroll();
ui_display_menu_refresh();
}
}
if (b == 'D') {
if (menu_selection < CurrentMenu->entry_n - 1) {
menu_selection++;
ui_menu_autoscroll();
ui_display_menu_refresh();
}
}
}
void ui_init(void)
{
uint32_t now;
int i;
display_scroll(NULL, 0x3f);
display_text(0, welcome_message0);
display_text(1, welcome_message1);
display_text(2, welcome_message2);
now = jiffies;
for (i = 0x3f; i >= 0x20; i--) {
display_scroll(NULL, i);
while ((jiffies - now) < 30)
WFI();
now = jiffies;
}
for (i = display_getcontrast(NULL); i >= 0; i--) {
display_setcontrast(NULL, i);
while ((jiffies - now) < 10)
WFI();
now = jiffies;
}
display_scroll(NULL, display_cur_v);
display_clear(NULL);
display_setcontrast(NULL, 0xcf);
ui_display_menu(CurrentMenu);
now = jiffies;
for (i = 1; i < 9; i++) {
led_beat(i);
while((jiffies - now < 100))
WFI();
now = jiffies;
}
}
void ui_keepalive(uint32_t timeslice)
{
}

32
ui.h Normal file
View file

@ -0,0 +1,32 @@
#ifndef UI_H
#define UI_H
#include <stdint.h>
void ui_init(void);
struct display_menu {
struct display_menu *next;
int entry_n;
struct display_menu_entry {
char title[16];
void (*action)(const void *arg);
const void *arg;
} entry[8];
};
const struct display_menu MainMenu, MeasureMenu, SignalGenMenu,
ExtraMenu;
void ui_display_menu(const struct display_menu *menu);
void ui_button_press(uint8_t b, int hold);
struct display_menu *CurrentMenu;
/* Defined in main to intercept input controls */
void set_input_callback(void (*cb)(uint8_t press, int hold));
void clear_input_callback(void);
void set_keepalive(void (*cb)(void));
void clear_keepalive(void);
#endif

268
ui_drone.c Normal file
View file

@ -0,0 +1,268 @@
#include <stddef.h>
#include "ui.h"
#include <string.h>
#include "adc.h"
#include "button.h"
#include "system.h"
#include "unicore-mx/stm32/gpio.h"
#include "unicore-mx/stm32/rcc.h"
#include "pot.h"
#define CENTER_X ((int)(52))
#define CENTER_Y ((int)(50))
#define NEUTRAL 2
struct display_menu *CurrentMenu = &MainMenu;
extern volatile uint32_t jiffies;
static uint32_t drone_xy_gain = 1;
static void ui_return(uint8_t press, int hold)
{
display_clear(NULL);
clear_input_callback();
ui_display_menu(&MainMenu);
}
static void ui_action_interrupt(uint8_t press, int hold)
{
if (press == '+') {
clear_keepalive();
display_clear(NULL);
display_text(5, "Interrupted!");
set_input_callback(ui_return);
}
}
static void display_drone(int line, uint16_t val)
{
char txt[] = "0000";
if (val >= 1000)
txt[0] = '0' + val / 1000;
val %= 1000;
if (val != 0)
txt[3] = '0' + val % 10;
if (val > 9)
txt[2] = '0' + ((val / 10) % 10);
if (val > 99)
txt[1] = '0' + (val / 100);
display_text(line, txt);
}
static void display_volume(void)
{
char txt[4] = "000";
int master_vol = pot_get_master();
txt[0] = '0' + master_vol / 100;
txt[1] = '0' + (master_vol % 100) / 10;
txt[2] = '0' + (master_vol % 10);
display_text(6, txt);
}
void ui_drone_xy_poll(void)
{
uint16_t x = 0, y = 0;
char TXT[]="Bender!";
static uint32_t bend_update = 0;
int X, Y;
char bgain[4] = "000";
rcc_periph_clock_enable(RCC_GPIOA);
gpio_mode_setup(GPIOA, GPIO_MODE_ANALOG, GPIO_PUPD_NONE, GPIO1 | GPIO2);
adc_pin_val(2, &x);
adc_pin_val(1, &y);
X = (100 * x) / 4096;
Y = (100 * y) / 4096;
if (((X > CENTER_X) && ((X - CENTER_X) > NEUTRAL)) || ((X < CENTER_X) && ((CENTER_X - X) > NEUTRAL))) {
int off = X - CENTER_X;
pot_offset(0, off/10);
}
if (((Y > CENTER_Y) && ((Y - CENTER_Y) > NEUTRAL)) || ((Y < CENTER_Y) && ((CENTER_Y - Y) > NEUTRAL))) {
int off = Y - CENTER_Y;
pot_offset(1, off/10);
}
led_beat(((jiffies / 100) % 8) + 1);
display_text(4, TXT);
display_drone(5, pot_get(0));
display_drone(6, pot_get(1));
bgain[0] = '0' + drone_xy_gain / 100;
bgain[1] = '0' + (drone_xy_gain % 100) / 10;
bgain[2] = '0' + (drone_xy_gain % 10);
display_text(7, bgain);
}
void ui_bender_poll(void)
{
uint16_t x = 0, y = 0;
char TXT[]="Bender!";
static uint32_t bend_update = 0;
int X, Y;
char bgain[4] = "000";
rcc_periph_clock_enable(RCC_GPIOA);
gpio_mode_setup(GPIOA, GPIO_MODE_ANALOG, GPIO_PUPD_NONE, GPIO1 | GPIO2);
adc_pin_val(2, &x);
adc_pin_val(1, &y);
X = (100 * x) / 4096;
Y = (100 * y) / 4096;
pot_set(0, X);
pot_set(1, Y);
led_beat(((jiffies / 100) % 8) + 1);
display_text(4, TXT);
display_drone(5, pot_get(0));
display_drone(6, pot_get(1));
bgain[0] = '0' + drone_xy_gain / 100;
bgain[1] = '0' + (drone_xy_gain % 100) / 10;
bgain[2] = '0' + (drone_xy_gain % 10);
display_text(7, bgain);
}
static void ui_gain_input(uint8_t press, int hold)
{
if (press == '+') {
display_clear(NULL);
display_text(5, "Interrupted!");
clear_keepalive();
set_input_callback(ui_return);
return;
}
if (press == 'U') {
if (drone_xy_gain < 10)
drone_xy_gain++;
}
if (press == 'D') {
if (drone_xy_gain > 0)
drone_xy_gain--;
}
ui_drone_xy_poll();
}
static void ui_drone_xy(const void *arg)
{
set_input_callback(ui_gain_input);
set_keepalive(ui_drone_xy_poll);
display_clear(NULL);
ui_drone_xy_poll();
}
static void ui_bender(const void *arg)
{
set_input_callback(ui_gain_input);
set_keepalive(ui_bender_poll);
display_clear(NULL);
ui_bender_poll();
}
static void ui_mastervol_input(uint8_t press, int hold)
{
int master_vol = pot_get_master();
if (press == 'U')
if (master_vol < 1000)
pot_set_master(master_vol + 5);
if (press == 'D') {
if (master_vol > 4)
pot_set_master(master_vol - 5);
}
if (press == '+') {
display_clear(NULL);
clear_input_callback();
ui_display_menu(&MainMenu);
return;
}
display_text(5, "Master Volume");
display_volume();
}
static void ui_mastervol(const void *arg)
{
set_input_callback(ui_mastervol_input);
display_clear(NULL);
display_text(5, "Master Volume");
display_volume();
}
static void ui_bytebeat_input(uint8_t press, int hold) {
if (press == '+') {
display_clear(NULL);
clear_input_callback();
clear_keepalive();
ui_display_menu(&MainMenu);
}
}
#define PLAY_SIZE 512
static uint8_t bb_buffer[PLAY_SIZE];
void ui_bytebeat_keepalive(void)
{
static uint32_t t = 0;
int r = 0;
if (dac_space() >= PLAY_SIZE) {
for(;;t++) {
bb_buffer[r++] = (t<<1)|(t>>4)*(((t>>12)|(t>>13)|(t>>6) | ((t>>2)|(t>>4))|(t<<1)|(t<<12)|((t<<5)&~(t>>22))));
if (r >= PLAY_SIZE) {
dac_write(bb_buffer, r);
break;
}
}
}
}
static void ui_bytebeat(const void *arg)
{
set_input_callback(ui_bytebeat_input);
display_clear(NULL);
display_text(5, " Bytebeat! ");
set_keepalive(ui_bytebeat_keepalive);
}
static void ui_submenu(const void *arg)
{
ui_display_menu(arg);
}
const struct display_menu PatternMenu = {
.entry_n = 1,
.entry = {
{ "TODO! ", ui_submenu, &MainMenu},
{ "", NULL, NULL}
}
};
const struct display_menu DroneMenu = {
.entry_n = 2,
.entry = {
{ "Drone X, Y ", ui_drone_xy, NULL},
{ "Bender ", ui_bender, NULL},
{ "", NULL, NULL}
}
};
const struct display_menu SettingsMenu = {
.entry_n = 1,
.entry = {
{ "TODO", ui_submenu, &MainMenu },
{ "", NULL, NULL}
}
};
const struct display_menu MainMenu = {
.entry_n = 5,
.entry = {
{ "Master Volume ", ui_mastervol, NULL },
{ "Settings ", ui_submenu, &SettingsMenu },
{ "Pattern ", ui_submenu, &PatternMenu },
{ "Drone ", ui_submenu, &DroneMenu},
{ "Bytebeat ", ui_bytebeat },
{ "", NULL, NULL}
}
};