├── main.c ├── .gitignore ├── initfs.S ├── src ├── pi │ ├── bcmframebuffer.h │ ├── hal_lld.h │ ├── bcm2835_spi.h │ ├── bcmmailbox.h │ ├── bcm2835_dma.h │ ├── bcmmailbox.c │ ├── spi_lld.h │ ├── hal_lld.c │ ├── bcm2835_dma.c │ ├── i2c_lld.h │ ├── serial_lld.c │ ├── spi_lld.c │ ├── bcmframebuffer.c │ ├── i2c_lld.c │ └── sdc_lld.c ├── utime.h ├── os │ ├── os.h │ ├── initfs.h │ ├── dirent_os.h │ ├── ffadaptor.c │ └── initfs.c ├── py │ ├── app.c │ ├── thread_chibios.c │ ├── chibiosmodule.c │ ├── config.c │ ├── i2cmodule.c │ ├── pyadaptor.c │ ├── spimodule.c │ └── _rpimodule.c ├── adaptor.h ├── zloader │ ├── zloader.ld │ ├── zloader_asm.s │ └── zloader.c ├── dirent.h ├── mcuconf.h ├── condvar.h ├── halconf.h └── ffconf.h ├── python ├── loader.py └── _readline.py ├── tools ├── time_import.py ├── mkziplib.py ├── mkzloader.py └── mkinitfs.py ├── .gitmodules ├── deps └── ff13a │ ├── 00readme.txt │ ├── integer.h │ ├── diskio.h │ ├── ffsystem.c │ ├── diskio.c │ └── 00history.txt ├── LICENSE ├── BCM2835.ld ├── README.md ├── main_pipyos.c └── SConstruct /main.c: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | int main() 4 | { 5 | printf("Hello World!\n"); 6 | return 0; 7 | } 8 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | *.o 2 | *.pyc 3 | /*.map 4 | /*.elf 5 | /*.img 6 | /initfs.bin 7 | /.sconsign.dblite 8 | /libm.a 9 | 10 | .DS_Store -------------------------------------------------------------------------------- /initfs.S: -------------------------------------------------------------------------------- 1 | .section ".data" 2 | .align 4 3 | 4 | .global _binary_initfs_bin_start 5 | _binary_initfs_bin_start: 6 | 7 | .incbin "initfs.bin" 8 | 9 | .global _binary_initfs_bin_end 10 | _binary_initfs_bin_end: 11 | -------------------------------------------------------------------------------- /src/pi/bcmframebuffer.h: -------------------------------------------------------------------------------- 1 | #ifndef _BCMFRAMEBUFFER_H 2 | #define _BCMFRAMEBUFFER_H 3 | 4 | void PiPyOS_bcm_framebuffer_init(int width, int height); 5 | void PiPyOS_bcm_framebuffer_putstring(const char *s, int count); 6 | 7 | #endif 8 | -------------------------------------------------------------------------------- /python/loader.py: -------------------------------------------------------------------------------- 1 | import posix 2 | import __main__ 3 | 4 | def load(): 5 | a = b'\n' 6 | while True: 7 | b = posix.read(2,1) 8 | if b == b'\x1b': 9 | exec(a, __main__.__dict__) 10 | break 11 | a+=b 12 | -------------------------------------------------------------------------------- /src/utime.h: -------------------------------------------------------------------------------- 1 | #ifndef _UTIME_H 2 | #define _UTIME_H 3 | 4 | struct utimbuf { 5 | time_t actime; /* access time */ 6 | time_t modtime; /* modification time */ 7 | }; 8 | 9 | 10 | int utime(const char *filename, const struct utimbuf *times); 11 | 12 | 13 | 14 | #endif -------------------------------------------------------------------------------- /tools/time_import.py: -------------------------------------------------------------------------------- 1 | import time 2 | # 2 sec for no compression 3 | def test(): 4 | t0 = time.monotonic() 5 | import os 6 | t1 = time.monotonic() 7 | return t1 - t0 8 | 9 | def test2(): 10 | t0 = time.monotonic() 11 | a=open('/sd/python36z.zip','rb').read() 12 | t1 = time.monotonic() 13 | return t1 - t0 14 | -------------------------------------------------------------------------------- /src/os/os.h: -------------------------------------------------------------------------------- 1 | #ifndef _OS_H 2 | #define _OS_H 3 | 4 | #include 5 | 6 | int clock_getres(clockid_t clk_id, struct timespec *res); 7 | int clock_gettime(clockid_t clk_id, struct timespec *tp); 8 | void os_init_stdio(void); 9 | 10 | typedef void (*sighandler_t)(int); 11 | 12 | sighandler_t signal(int signum, sighandler_t handler); 13 | 14 | #endif -------------------------------------------------------------------------------- /src/py/app.c: -------------------------------------------------------------------------------- 1 | /* Weak implementations of the app* functions 2 | * 3 | */ 4 | #include "Python.h" 5 | 6 | #pragma weak PyInit_app 7 | 8 | 9 | PyMODINIT_FUNC 10 | PyInit_app(void) { 11 | PyErr_SetString(PyExc_NotImplementedError, "app module is not present"); 12 | return NULL; 13 | } 14 | 15 | #pragma weak app_init 16 | 17 | void app_init(void) { } -------------------------------------------------------------------------------- /.gitmodules: -------------------------------------------------------------------------------- 1 | [submodule "deps/uspi"] 2 | path = deps/uspi 3 | url = https://github.com/rsta2/uspi.git 4 | [submodule "deps/cpython"] 5 | path = deps/cpython 6 | url = https://github.com/python/cpython 7 | branch = 3.6 8 | [submodule "deps/ChibiOS-RPi"] 9 | path = deps/ChibiOS-RPi 10 | url = https://github.com/rreilink/ChibiOS-RPi 11 | [submodule "deps/pylvgl"] 12 | path = deps/pylvgl 13 | url = https://github.com/rreilink/pylvgl.git 14 | -------------------------------------------------------------------------------- /src/os/initfs.h: -------------------------------------------------------------------------------- 1 | #ifndef _INITFS_H 2 | #define _INITFS_H 3 | 4 | #include "dirent_os.h" 5 | 6 | typedef struct { 7 | char *data; 8 | int pos; 9 | int size; 10 | 11 | } initfs_openfile_t; 12 | 13 | 14 | int PiPyOS_initfs_open(initfs_openfile_t *file, const char *pathname, int flags); 15 | int PiPyOS_initfs_read(initfs_openfile_t *file, void *buf, size_t count); 16 | int PiPyOS_initfs_opendir(const char *pathname, DIR *dir); 17 | int PiPyOS_initfs_readdir(DIR *dirp); 18 | int PiPyOS_initfs_stat(const char *pathname, struct stat *buf); 19 | int PiPyOS_initfs_lseek(initfs_openfile_t *file, int offset, int whence); 20 | 21 | #endif -------------------------------------------------------------------------------- /tools/mkziplib.py: -------------------------------------------------------------------------------- 1 | import zipfile 2 | import os 3 | 4 | # TODO: check Python version 5 | os.chdir('../deps/cpython') 6 | path = 'Lib' 7 | with zipfile.PyZipFile('../python36.zip', 'w') as zf: 8 | for item in os.listdir(path): 9 | if item == '__pycache__' or item == 'test': 10 | continue 11 | 12 | zf.writepy(os.path.join(path, item)) 13 | 14 | with zipfile.PyZipFile('../python36z.zip', 'w', zipfile.ZIP_DEFLATED) as zf: 15 | for item in os.listdir(path): 16 | if item == '__pycache__' or item == 'test': 17 | continue 18 | 19 | zf.writepy(os.path.join(path, item)) 20 | -------------------------------------------------------------------------------- /src/pi/hal_lld.h: -------------------------------------------------------------------------------- 1 | 2 | #ifndef _HAL_LLD_H_ 3 | #define _HAL_LLD_H_ 4 | 5 | #define PLATFORM_NAME "BCM2835" 6 | 7 | #define HAL_IMPLEMENTS_COUNTERS 1 8 | #define PAL_MODE_OUTPUT 0xFF 9 | 10 | typedef uint32_t halrtcnt_t; 11 | 12 | #define hal_lld_get_counter_value() SYSTIMER_CLO 13 | #define hal_lld_get_counter_frequency() 1000000 14 | 15 | #ifdef __cplusplus 16 | extern "C" { 17 | #endif 18 | void hal_lld_init(void); 19 | void hal_register_interrupt(unsigned int interrupt, void (*handler) (void *), void *closure); 20 | void delayMicroseconds(uint32_t n); 21 | 22 | 23 | #ifdef __cplusplus 24 | } 25 | #endif 26 | 27 | #endif /* _HAL_LLD_H_ */ 28 | 29 | 30 | -------------------------------------------------------------------------------- /src/adaptor.h: -------------------------------------------------------------------------------- 1 | #ifndef ADAPTOR_H 2 | #define ADAPTOR_H 3 | 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | 10 | 11 | int lstat(const char *path, struct stat *buf); 12 | 13 | extern int fileno(FILE *f); // TODO: should come from stdio.h 14 | 15 | //TODO 16 | 17 | #define VERSION "3.6" 18 | #define PYTHONPATH "/boot" 19 | #define PREFIX "/boot" 20 | #define EXEC_PREFIX "/boot" 21 | #define VPATH "/boot" 22 | 23 | 24 | 25 | 26 | extern void sig_ign(int); 27 | extern void sig_err(int); 28 | 29 | 30 | #define SIG_IGN sig_ign 31 | #define SIG_ERR sig_err 32 | 33 | #define CLOCK_MONOTONIC 0 34 | 35 | 36 | #define PYTHREAD_NAME "chibios" 37 | 38 | #endif -------------------------------------------------------------------------------- /src/zloader/zloader.ld: -------------------------------------------------------------------------------- 1 | 2 | MEMORY 3 | { 4 | /* start at 32MB from start of memory, size = 128MB */ 5 | //ram : org = 0x8000, len = 0x8000000 6 | ram : org = 0x2000000, len = 0x8000000 7 | } 8 | 9 | __reloc_base__ = 0x8000; 10 | __reloc_target__ = ORIGIN(ram); 11 | 12 | __stack_top__ = ORIGIN(ram)+LENGTH(ram); 13 | 14 | SECTIONS 15 | { 16 | . = 0; 17 | 18 | .text : ALIGN(16) SUBALIGN(16) 19 | { 20 | _text = .; 21 | KEEP(*(vectors)) 22 | *(.text) 23 | *(.text.*) 24 | *(.rodata) 25 | *(.rodata.*) 26 | } > ram 27 | 28 | 29 | . = ALIGN(4); 30 | 31 | .data : 32 | { 33 | _data = .; 34 | *(.data) 35 | . = ALIGN(4); 36 | *(.data.*) 37 | . = ALIGN(4); 38 | } > ram 39 | 40 | } 41 | 42 | _end = .; 43 | __reloc_end__ = __reloc_base__ + _end - ORIGIN(ram); 44 | 45 | -------------------------------------------------------------------------------- /deps/ff13a/00readme.txt: -------------------------------------------------------------------------------- 1 | FatFs Module Source Files R0.13a 2 | 3 | 4 | FILES 5 | 6 | 00readme.txt This file. 7 | 00history.txt Revision history. 8 | ff.c FatFs module. 9 | ffconf.h Configuration file of FatFs module. 10 | ff.h Common include file for FatFs and application module. 11 | diskio.h Common include file for FatFs and disk I/O module. 12 | diskio.c An example of glue function to attach existing disk I/O module to FatFs. 13 | integer.h Integer type definitions for FatFs. 14 | ffunicode.c Optional Unicode utility functions. 15 | ffsystem.c An example of optional O/S related functions. 16 | 17 | 18 | Low level disk I/O module is not included in this archive because the FatFs 19 | module is only a generic file system layer and it does not depend on any specific 20 | storage device. You need to provide a low level disk I/O module written to 21 | control the storage device that attached to the target system. 22 | 23 | -------------------------------------------------------------------------------- /src/os/dirent_os.h: -------------------------------------------------------------------------------- 1 | #ifndef _DIRENT_OS_H 2 | #define _DIRENT_OS_H 3 | 4 | 5 | /* See dirent.h on how dirent.h and dirent_os.h work together 6 | */ 7 | #ifdef _DIRENT_H 8 | #error Include dirent_os.h before dirent.h (or any file that includes dirent.h) 9 | #endif 10 | 11 | #include "dirent.h" 12 | 13 | #define DIR DIR_FF // ff.h defines the type DIR, but that is reserved for dirent.h. So define it to be DIR_FF 14 | #include "ff.h" 15 | #undef DIR 16 | 17 | 18 | typedef struct{ 19 | int handler; 20 | struct dirent dirent; 21 | union { // A union of structs for all possible filesystem handlers 22 | struct { 23 | int idx_parent; 24 | int idx_cur; 25 | } initfs; 26 | unsigned int rootfs_idx; 27 | DIR_FF ff_dir; 28 | }; 29 | } DIR; 30 | 31 | 32 | 33 | int closedir(DIR *); 34 | DIR *opendir(const char *); 35 | struct dirent *readdir(DIR *); 36 | void seekdir(DIR *, long); 37 | long telldir(DIR *); 38 | 39 | #endif -------------------------------------------------------------------------------- /deps/ff13a/integer.h: -------------------------------------------------------------------------------- 1 | /*-------------------------------------------*/ 2 | /* Integer type definitions for FatFs module */ 3 | /*-------------------------------------------*/ 4 | 5 | #ifndef FF_INTEGER 6 | #define FF_INTEGER 7 | 8 | #ifdef _WIN32 /* FatFs development platform */ 9 | 10 | #include 11 | #include 12 | typedef unsigned __int64 QWORD; 13 | 14 | 15 | #else /* Embedded platform */ 16 | 17 | /* These types MUST be 16-bit or 32-bit */ 18 | typedef int INT; 19 | typedef unsigned int UINT; 20 | 21 | /* This type MUST be 8-bit */ 22 | typedef unsigned char BYTE; 23 | 24 | /* These types MUST be 16-bit */ 25 | typedef short SHORT; 26 | typedef unsigned short WORD; 27 | typedef unsigned short WCHAR; 28 | 29 | /* These types MUST be 32-bit */ 30 | typedef long LONG; 31 | typedef unsigned long DWORD; 32 | 33 | /* This type MUST be 64-bit (Remove this for ANSI C (C89) compatibility) */ 34 | typedef unsigned long long QWORD; 35 | 36 | #endif 37 | 38 | #endif 39 | -------------------------------------------------------------------------------- /src/pi/bcm2835_spi.h: -------------------------------------------------------------------------------- 1 | #ifndef _BCM2835_SPI_H_ 2 | #define _BCM2835_SPI_H_ 3 | 4 | /* 5 | * Registers 6 | */ 7 | 8 | typedef struct { 9 | volatile uint32_t cs; 10 | volatile uint32_t fifo; 11 | volatile uint32_t clk; 12 | volatile uint32_t dlen; 13 | volatile uint32_t ltoh; 14 | volatile uint32_t dc; 15 | } bcm2835_spi_regs_t; 16 | 17 | #define BCM2835_SPI ((bcm2835_spi_regs_t *) (0x20204000)) 18 | 19 | 20 | /* 21 | * Register bits 22 | */ 23 | 24 | 25 | #define BCM2835_SPI_CS_CS(x) ((x&3)<<0) // Chip select 0,1,2 26 | #define BCM2835_SPI_CS_CPHA (1<<2) 27 | #define BCM2835_SPI_CS_CPOL (1<<3) 28 | #define BCM2835_SPI_CS_CLEAR_TX (1<<4) 29 | #define BCM2835_SPI_CS_CLEAR_RX (1<<5) 30 | 31 | #define BCM2835_SPI_CS_TA (1<<7) 32 | #define BCM2835_SPI_CS_DMAEN (1<<8) 33 | #define BCM2835_SPI_CS_INTD (1<<9) 34 | #define BCM2835_SPI_CS_ADCS (1<<11) 35 | #define BCM2835_SPI_CS_RXD (1<<17) 36 | #define BCM2835_SPI_CS_TXD (1<<18) 37 | 38 | #define BCM2835_DMA_TI_WAITS(x) ((x&0x1f)<<21) 39 | 40 | 41 | #endif -------------------------------------------------------------------------------- /src/dirent.h: -------------------------------------------------------------------------------- 1 | #ifndef _DIRENT_H 2 | #define _DIRENT_H 3 | 4 | #include 5 | #include 6 | 7 | struct dirent { 8 | ino_t d_ino; 9 | char d_name[NAME_MAX]; 10 | }; 11 | 12 | /* The actual DIR structure contents is defined in dirent_os.h. We define it 13 | * here as void such that code that uses dirent functions, will not need to 14 | * depend on all the dependencies that the DIR structure has (filesystem handler 15 | * specific stuff) 16 | * 17 | * All c-source files that actually implement (parts of) the following functions 18 | * and thus need access to the DIR structure internals, will include dirent_os.h 19 | * instead. 20 | * 21 | * To prevent conflicts, the following section is not included when included 22 | * from dirent_os.h 23 | */ 24 | 25 | #ifndef _DIRENT_OS_H 26 | 27 | typedef void DIR; 28 | 29 | int closedir(DIR *); 30 | DIR *opendir(const char *); 31 | struct dirent *readdir(DIR *); 32 | void seekdir(DIR *, long); 33 | long telldir(DIR *); 34 | 35 | #endif 36 | 37 | #endif -------------------------------------------------------------------------------- /src/os/ffadaptor.c: -------------------------------------------------------------------------------- 1 | /* Adaptor that connects the FatFs library to the ChibiOS SDC driver */ 2 | #include 3 | #include "ch.h" 4 | #include "hal.h" 5 | #include "ff.h" 6 | #include "diskio.h" 7 | 8 | 9 | DSTATUS disk_initialize (BYTE pdrv) { 10 | if (pdrv!=0) return RES_PARERR; 11 | 12 | if (sdcConnect(&SDCD1)==CH_SUCCESS) { 13 | return 0; 14 | } else { 15 | return STA_NOINIT; 16 | } 17 | } 18 | 19 | DSTATUS disk_status (BYTE pdrv) { 20 | if (pdrv!=0) return STA_NOINIT; 21 | return STA_PROTECT; 22 | } 23 | 24 | DRESULT disk_read (BYTE pdrv, BYTE* buff, DWORD sector, UINT count) { 25 | if (pdrv!=0) return RES_PARERR; 26 | if (sdcRead(&SDCD1, sector, buff, count)==CH_SUCCESS) { 27 | return RES_OK; 28 | } else { 29 | return RES_ERROR; 30 | } 31 | } 32 | 33 | DRESULT disk_write (BYTE pdrv, const BYTE* buff, DWORD sector, UINT count) { 34 | return RES_WRPRT; 35 | } 36 | 37 | DRESULT disk_ioctl (BYTE pdrv, BYTE cmd, void* buff) { 38 | printf("DISK IOCTL %d\n", cmd); 39 | return RES_ERROR; 40 | 41 | } 42 | -------------------------------------------------------------------------------- /tools/mkzloader.py: -------------------------------------------------------------------------------- 1 | ''' 2 | This script assembles an executable compressed binary image, consisting of a 3 | loader and a compressed binary image. 4 | 5 | The source binary image is compressed using zlib, and then byte-padded to a 6 | word boundary. The resulting output file consists of the concatenation of: 7 | - the loader 8 | - one word specifying the length of the compressed data in bytes (this is 9 | required by the loader to be able to relocate the compressed data) 10 | - the compressed data including the padding 11 | ''' 12 | 13 | 14 | import zlib 15 | import struct 16 | 17 | def main(target, source, env): 18 | assert len(target) == 1 and len(source) == 2 19 | 20 | with open(source[0].name, 'rb') as loaderfile: 21 | loader = loaderfile.read() 22 | 23 | with open(source[1].name, 'rb') as srcimg: 24 | compressed = zlib.compress(srcimg.read(), 9) 25 | 26 | length = len(compressed) 27 | padding = '\x00' * (3-((length-1) % 4)) # Pad to multiple of 4 bytes 28 | 29 | with open(target[0].name, 'wb') as outfile: 30 | outfile.write(loader + struct.pack('. 19 | */ 20 | 21 | /* 22 | * BCM2835 drivers configuration. 23 | * The following settings override the default settings present in 24 | * the various device driver implementation headers. 25 | * Note that the settings for each driver only have effect if the driver 26 | * is enabled in halconf.h. 27 | */ 28 | 29 | /* 30 | * ADC driver system settings. 31 | */ 32 | 33 | /* 34 | * CAN driver system settings. 35 | */ 36 | 37 | /* 38 | * MAC driver system settings. 39 | */ 40 | 41 | /* 42 | * PWM driver system settings. 43 | */ 44 | 45 | /* 46 | * SERIAL driver system settings. 47 | */ 48 | 49 | /* 50 | * SPI driver system settings. 51 | */ 52 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | BSD 3-Clause License 2 | 3 | Copyright (c) 2017, rreilink 4 | All rights reserved. 5 | 6 | Redistribution and use in source and binary forms, with or without 7 | modification, are permitted provided that the following conditions are met: 8 | 9 | * Redistributions of source code must retain the above copyright notice, this 10 | list of conditions and the following disclaimer. 11 | 12 | * Redistributions in binary form must reproduce the above copyright notice, 13 | this list of conditions and the following disclaimer in the documentation 14 | and/or other materials provided with the distribution. 15 | 16 | * Neither the name of the copyright holder nor the names of its 17 | contributors may be used to endorse or promote products derived from 18 | this software without specific prior written permission. 19 | 20 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 21 | AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 22 | IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 23 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE 24 | FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 25 | DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 26 | SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 27 | CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 28 | OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 29 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 30 | -------------------------------------------------------------------------------- /src/zloader/zloader_asm.s: -------------------------------------------------------------------------------- 1 | /* 2 | * This is the assembly startup and relocation code for the zloader. See 3 | * zloader.c for how the zloader works 4 | */ 5 | 6 | .set MODE_SYS, 0x1F 7 | 8 | .set I_BIT, 0x80 9 | .set F_BIT, 0x40 10 | 11 | 12 | .section vectors 13 | .code 32 14 | .balign 4 15 | 16 | /* 17 | * System points 18 | */ 19 | 20 | _start: 21 | // Setup stack, disable interrupts 22 | ldr r0, =__stack_top__ 23 | msr CPSR_c, #MODE_SYS | I_BIT | F_BIT 24 | mov sp, r0 25 | 26 | // For benchmarking: store SYSTIMER_CLO in r1 27 | ldr r0, =0x20003004 28 | ldr r1, [r0] 29 | 30 | // Code relocation 31 | ldr r5, =__reloc_base__ // Actual start of the code in memory 32 | ldr r2, =__reloc_target__ 33 | ldr r3, =__reloc_end__ // Actual end of the code in memory 34 | 35 | // r3, __reloc_end__ now points to the end of text + data in memory 36 | // After text + data, mkzloader appends the length of the compressed data 37 | // and then the actual compressed data. Adjust r3 to point to the end of 38 | // the compressed data 39 | 40 | ldr r0, [r3], #4 // Load zip file size, add 4 bytes (size of this word) 41 | add r3, r3, r0 // Add zip file size 42 | 43 | // Copy ourselves including compressed data to the relocation area 44 | relocloop: 45 | cmp r5, r3 46 | ldrlo r4, [r5], #4 47 | strlo r4, [r2], #4 48 | blo relocloop 49 | 50 | // Jump to the relocation area (using absolute branch) 51 | 52 | ldr pc, =relocjump 53 | relocjump: 54 | 55 | // Call main loader (C) 56 | bl loader 57 | 58 | ldr pc, =__reloc_base__ 59 | 60 | 61 | 62 | /** @} */ 63 | -------------------------------------------------------------------------------- /src/py/thread_chibios.c: -------------------------------------------------------------------------------- 1 | #include "Python.h" 2 | #include "pythread.h" 3 | #include "ch.h" 4 | 5 | /* 6 | * Thread support. 7 | */ 8 | void 9 | PyThread__init_thread(void) 10 | { 11 | } 12 | 13 | long 14 | PyThread_start_new_thread(void (*func)(void *), void *arg) 15 | { 16 | Thread *thread = chThdCreateFromHeap(NULL, 65536, NORMALPRIO, (tfunc_t)func, arg); 17 | return thread != NULL; 18 | } 19 | 20 | long 21 | PyThread_get_thread_ident(void) 22 | { 23 | return (long)chThdSelf(); 24 | } 25 | 26 | void 27 | PyThread_exit_thread(void) 28 | { 29 | chThdExit(0); 30 | } 31 | 32 | /* 33 | * Lock support. Uses ChibiOS binary semaphores. 34 | */ 35 | PyThread_type_lock 36 | PyThread_allocate_lock(void) 37 | { 38 | BinarySemaphore *lock; 39 | lock = (BinarySemaphore *)PyMem_RawMalloc(sizeof(BinarySemaphore)); 40 | 41 | if (lock) chBSemInit(lock, 0); 42 | 43 | return (PyThread_type_lock) lock; 44 | } 45 | 46 | void 47 | PyThread_free_lock(PyThread_type_lock lock) 48 | { 49 | PyMem_RawFree((void *)lock); 50 | } 51 | 52 | int 53 | PyThread_acquire_lock(PyThread_type_lock lock, int waitflag) 54 | { 55 | return PyThread_acquire_lock_timed(lock, waitflag ? -1 : 0, 0); 56 | } 57 | 58 | 59 | PyLockStatus 60 | PyThread_acquire_lock_timed(PyThread_type_lock lock, PY_TIMEOUT_T microseconds, 61 | int intr_flag) 62 | { 63 | int success; 64 | systime_t timeout_value; 65 | if (microseconds == 0) { 66 | timeout_value = TIME_IMMEDIATE; 67 | } else if (microseconds < 0) { 68 | timeout_value = TIME_INFINITE; 69 | } else { 70 | timeout_value = (((long long) microseconds) * CH_FREQUENCY) / microseconds; 71 | } 72 | 73 | msg_t result = chBSemWaitTimeout((BinarySemaphore*) lock, timeout_value); 74 | 75 | return result == RDY_OK; 76 | } 77 | 78 | void 79 | PyThread_release_lock(PyThread_type_lock lock) 80 | { 81 | chBSemSignal((BinarySemaphore*) lock); 82 | } 83 | 84 | 85 | -------------------------------------------------------------------------------- /src/py/chibiosmodule.c: -------------------------------------------------------------------------------- 1 | 2 | #include "Python.h" 3 | #include "ch.h" 4 | 5 | #define DOC_GET_THREADS \ 6 | "get_threads()\n"\ 7 | "\n"\ 8 | "returns a list of tuples (name, state, priority, time, refcount, address, stack address)\n"\ 9 | "for each ChibiOS thread\n" 10 | 11 | static const char *states[] = {THD_STATE_NAMES}; 12 | 13 | static PyObject * 14 | chibios_get_threads(PyObject *self, PyObject *args){ 15 | 16 | Thread *tp; 17 | PyObject *list = PyList_New(0); 18 | PyObject *item = NULL; 19 | 20 | if (!list) return NULL; 21 | 22 | tp = chRegFirstThread(); 23 | //chprintf(chp, " addr stack prio refs state time name\r\n"); 24 | // name state prio time refs addr stack 25 | while(tp) { 26 | item = Py_BuildValue("ssIIIII", 27 | tp->p_name, states[tp->p_state], (uint32_t)tp->p_prio, 28 | (uint32_t)tp->p_time, (uint32_t)(tp->p_refs - 1), (uint32_t)tp, 29 | (uint32_t)tp->p_ctx.r13); 30 | 31 | if (!item) goto error; 32 | if (PyList_Append(list, item)) goto error; 33 | 34 | tp = chRegNextThread(tp); 35 | } 36 | 37 | return list; 38 | error: 39 | Py_XDECREF(item); 40 | Py_XDECREF(list); 41 | return NULL; 42 | } 43 | 44 | 45 | 46 | 47 | static PyMethodDef _ChibiOSMethods[] = { 48 | {"get_threads", chibios_get_threads, METH_NOARGS, DOC_GET_THREADS}, 49 | 50 | {NULL, NULL, 0, NULL} /* Sentinel */ 51 | }; 52 | 53 | static struct PyModuleDef chibios_module = { 54 | PyModuleDef_HEAD_INIT, 55 | "chibios", /* name of module */ 56 | NULL, /* module documentation, may be NULL */ 57 | -1, /* size of per-interpreter state of the module, 58 | or -1 if the module keeps state in global variables. */ 59 | _ChibiOSMethods 60 | }; 61 | 62 | 63 | PyMODINIT_FUNC 64 | PyInit_chibios(void) { 65 | 66 | PyObject *module = NULL; 67 | 68 | module = PyModule_Create(&chibios_module); 69 | if (!module) goto error; 70 | 71 | return module; 72 | 73 | error: 74 | Py_XDECREF(module); 75 | return NULL; 76 | } 77 | -------------------------------------------------------------------------------- /python/_readline.py: -------------------------------------------------------------------------------- 1 | ''' 2 | Python implementation of readline function: 3 | - editing of current line using left/right arrow keys, backspace 4 | - command history 5 | 6 | ''' 7 | 8 | import sys 9 | 10 | history = [] 11 | 12 | def readline(prompt): 13 | sys.stdout.write(prompt + '\x1b[K') 14 | 15 | buffer = '' 16 | pos = 0 17 | history.append('') 18 | histpos = len(history) - 1 19 | 20 | while True: 21 | sys.stdout.flush() 22 | 23 | cmd = '' 24 | while '\x1b['.startswith(cmd): 25 | cmd += sys.stdin.read(1) 26 | 27 | if cmd=='\n': 28 | history[-1] = buffer 29 | 30 | # Prevent duplicate entries at the end 31 | if len(history) > 1 and history[-2] == history[-1]: 32 | history.pop() 33 | 34 | sys.stdout.write('\n') 35 | 36 | return buffer + '\n' 37 | if cmd=='\b' or cmd == '\x7f': 38 | if pos>0: 39 | buffer = buffer[:pos-1] + buffer[pos:] 40 | nback = len(buffer) - pos + 1 41 | backcmd = '\x1b[' + str(nback) + 'D' if nback>0 else '' 42 | sys.stdout.write('\x1b[D' + buffer[pos-1:] + '\x1b[K' + backcmd) 43 | pos = pos -1 44 | history[-1] = buffer 45 | histpos = len(history) - 1 46 | 47 | elif len(cmd)==1 and ord(cmd) >= 32: # Normal char 48 | buffer = buffer[:pos] + cmd + buffer[pos:] 49 | nback = len(buffer) - pos - 1 50 | backcmd = '\x1b[' + str(nback) + 'D' if nback>0 else '' 51 | sys.stdout.write(buffer[pos:] + backcmd) 52 | pos += 1 53 | 54 | history[-1] = buffer 55 | histpos = len(history) - 1 56 | 57 | 58 | elif cmd == '\x1b[D': # left 59 | if pos > 0: 60 | pos-=1 61 | sys.stdout.write(cmd) 62 | elif cmd == '\x1b[C': # right 63 | if pos < len(buffer): 64 | pos+=1 65 | sys.stdout.write(cmd) 66 | 67 | elif cmd == '\x1b[A': # up 68 | if histpos > 0: 69 | histpos -= 1 70 | backcmd = '\x1b[' + str(pos) + 'D' if pos>0 else '' 71 | buffer = history[histpos] 72 | pos = len(buffer) 73 | sys.stdout.write(backcmd + '\x1b[K' + buffer) 74 | elif cmd == '\x1b[B': # down 75 | 76 | if histpos < len(history) - 1: 77 | histpos += 1 78 | backcmd = '\x1b[' + str(pos) + 'D' if pos>0 else '' 79 | buffer = history[histpos] 80 | pos = len(buffer) 81 | sys.stdout.write(backcmd + '\x1b[K' + buffer) -------------------------------------------------------------------------------- /deps/ff13a/diskio.h: -------------------------------------------------------------------------------- 1 | /*-----------------------------------------------------------------------/ 2 | / Low level disk interface modlue include file (C)ChaN, 2014 / 3 | /-----------------------------------------------------------------------*/ 4 | 5 | #ifndef _DISKIO_DEFINED 6 | #define _DISKIO_DEFINED 7 | 8 | #ifdef __cplusplus 9 | extern "C" { 10 | #endif 11 | 12 | #include "integer.h" 13 | 14 | 15 | /* Status of Disk Functions */ 16 | typedef BYTE DSTATUS; 17 | 18 | /* Results of Disk Functions */ 19 | typedef enum { 20 | RES_OK = 0, /* 0: Successful */ 21 | RES_ERROR, /* 1: R/W Error */ 22 | RES_WRPRT, /* 2: Write Protected */ 23 | RES_NOTRDY, /* 3: Not Ready */ 24 | RES_PARERR /* 4: Invalid Parameter */ 25 | } DRESULT; 26 | 27 | 28 | /*---------------------------------------*/ 29 | /* Prototypes for disk control functions */ 30 | 31 | 32 | DSTATUS disk_initialize (BYTE pdrv); 33 | DSTATUS disk_status (BYTE pdrv); 34 | DRESULT disk_read (BYTE pdrv, BYTE* buff, DWORD sector, UINT count); 35 | DRESULT disk_write (BYTE pdrv, const BYTE* buff, DWORD sector, UINT count); 36 | DRESULT disk_ioctl (BYTE pdrv, BYTE cmd, void* buff); 37 | 38 | 39 | /* Disk Status Bits (DSTATUS) */ 40 | 41 | #define STA_NOINIT 0x01 /* Drive not initialized */ 42 | #define STA_NODISK 0x02 /* No medium in the drive */ 43 | #define STA_PROTECT 0x04 /* Write protected */ 44 | 45 | 46 | /* Command code for disk_ioctrl fucntion */ 47 | 48 | /* Generic command (Used by FatFs) */ 49 | #define CTRL_SYNC 0 /* Complete pending write process (needed at _FS_READONLY == 0) */ 50 | #define GET_SECTOR_COUNT 1 /* Get media size (needed at _USE_MKFS == 1) */ 51 | #define GET_SECTOR_SIZE 2 /* Get sector size (needed at _MAX_SS != _MIN_SS) */ 52 | #define GET_BLOCK_SIZE 3 /* Get erase block size (needed at _USE_MKFS == 1) */ 53 | #define CTRL_TRIM 4 /* Inform device that the data on the block of sectors is no longer used (needed at _USE_TRIM == 1) */ 54 | 55 | /* Generic command (Not used by FatFs) */ 56 | #define CTRL_POWER 5 /* Get/Set power status */ 57 | #define CTRL_LOCK 6 /* Lock/Unlock media removal */ 58 | #define CTRL_EJECT 7 /* Eject media */ 59 | #define CTRL_FORMAT 8 /* Create physical format on the media */ 60 | 61 | /* MMC/SDC specific ioctl command */ 62 | #define MMC_GET_TYPE 10 /* Get card type */ 63 | #define MMC_GET_CSD 11 /* Get CSD */ 64 | #define MMC_GET_CID 12 /* Get CID */ 65 | #define MMC_GET_OCR 13 /* Get OCR */ 66 | #define MMC_GET_SDSTAT 14 /* Get SD status */ 67 | #define ISDIO_READ 55 /* Read data form SD iSDIO register */ 68 | #define ISDIO_WRITE 56 /* Write data to SD iSDIO register */ 69 | #define ISDIO_MRITE 57 /* Masked write data to SD iSDIO register */ 70 | 71 | /* ATA/CF specific ioctl command */ 72 | #define ATA_GET_REV 20 /* Get F/W revision */ 73 | #define ATA_GET_MODEL 21 /* Get model name */ 74 | #define ATA_GET_SN 22 /* Get serial number */ 75 | 76 | #ifdef __cplusplus 77 | } 78 | #endif 79 | 80 | #endif 81 | -------------------------------------------------------------------------------- /BCM2835.ld: -------------------------------------------------------------------------------- 1 | /* 2 | ChibiOS/RT - Copyright (C) 2006,2007,2008,2009,2010, 3 | 2011,2012 Giovanni Di Sirio. 4 | 5 | This file is part of ChibiOS/RT. 6 | 7 | ChibiOS/RT is free software; you can redistribute it and/or modify 8 | it under the terms of the GNU General Public License as published by 9 | the Free Software Foundation; either version 3 of the License, or 10 | (at your option) any later version. 11 | 12 | ChibiOS/RT is distributed in the hope that it will be useful, 13 | but WITHOUT ANY WARRANTY; without even the implied warranty of 14 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 15 | GNU General Public License for more details. 16 | 17 | You should have received a copy of the GNU General Public License 18 | along with this program. If not, see . 19 | */ 20 | 21 | /* 22 | * BCM2835 memory setup. 23 | */ 24 | 25 | 26 | /* 27 | * ATTENTION: all stack sizes must be multiple of 8 bytes, since stack pointer 28 | * must be 8-byte aligned 29 | */ 30 | 31 | __und_stack_size__ = 0x0008; 32 | __abt_stack_size__ = 0x0008; 33 | __fiq_stack_size__ = 0x0200; 34 | __irq_stack_size__ = 0x0200; 35 | __svc_stack_size__ = 0x0008; 36 | __sys_stack_size__ = 0x0400; 37 | __stacks_total_size__ = __und_stack_size__ + __abt_stack_size__ + __fiq_stack_size__ + __irq_stack_size__ + __svc_stack_size__ + __sys_stack_size__; 38 | 39 | MEMORY 40 | { 41 | ram : org = 0x8000, len = 0x06000000 - 0x20 42 | } 43 | 44 | __ram_start__ = ORIGIN(ram); 45 | __ram_size__ = LENGTH(ram); 46 | __ram_end__ = __ram_start__ + __ram_size__; 47 | 48 | SECTIONS 49 | { 50 | . = 0; 51 | 52 | .text : ALIGN(16) SUBALIGN(16) 53 | { 54 | _text = .; 55 | KEEP(*(vectors)) 56 | *(.text) 57 | *(.text.*) 58 | *(.rodata) 59 | *(.rodata.*) 60 | *(.glue_7t) 61 | *(.glue_7) 62 | *(.gcc*) 63 | *(.ctors) 64 | *(.dtors) 65 | } > ram 66 | 67 | .ARM.extab : {*(.ARM.extab* .gnu.linkonce.armextab.*)} 68 | 69 | __exidx_start = .; 70 | .ARM.exidx : {*(.ARM.exidx* .gnu.linkonce.armexidx.*)} > ram 71 | __exidx_end = .; 72 | 73 | .eh_frame_hdr : {*(.eh_frame_hdr)} 74 | 75 | .eh_frame : ONLY_IF_RO {*(.eh_frame)} 76 | 77 | . = ALIGN(4); 78 | _etext = .; 79 | _textdata = _etext; 80 | 81 | .data : 82 | { 83 | _data = .; 84 | *(.data) 85 | . = ALIGN(4); 86 | *(.data.*) 87 | . = ALIGN(4); 88 | *(.ramtext) 89 | . = ALIGN(4); 90 | _edata = .; 91 | } > ram 92 | 93 | .bss : 94 | { 95 | _bss_start = .; 96 | *(.bss) 97 | . = ALIGN(4); 98 | *(.bss.*) 99 | . = ALIGN(4); 100 | *(COMMON) 101 | . = ALIGN(4); 102 | _bss_end = .; 103 | } > ram 104 | } 105 | 106 | PROVIDE(end = .); 107 | _end = .; 108 | 109 | __heap_base__ = _end; 110 | __heap_end__ = __ram_end__ - __stacks_total_size__; 111 | __main_thread_stack_base__ = __ram_end__ - __stacks_total_size__; 112 | -------------------------------------------------------------------------------- /src/pi/bcm2835_dma.h: -------------------------------------------------------------------------------- 1 | #ifndef _BCM2835_DMA_H_ 2 | #define _BCM2835_DMA_H_ 3 | 4 | #include "bcm2835.h" 5 | 6 | /* 7 | * Registers 8 | */ 9 | 10 | typedef struct { 11 | volatile uint32_t cs; 12 | volatile uint32_t conblk_ad; 13 | volatile uint32_t ti; 14 | volatile uint32_t source_ad; 15 | volatile uint32_t dest_ad; 16 | volatile uint32_t txfr_len; 17 | volatile uint32_t stride; 18 | volatile uint32_t nextconblk; 19 | volatile uint32_t debug; 20 | } bcm2835_dma_regs_t; 21 | 22 | 23 | #define BCM2835_DMA(x) ((bcm2835_dma_regs_t *) (0x20007000 + ((x)<<8))) 24 | #define BCM2835_DMA_ENABLE (* (volatile uint32_t *) (0x20007FF0)) 25 | 26 | /* 27 | * Register bits 28 | */ 29 | 30 | 31 | #define BCM2835_DMA_CS_ACTIVE (1<<0) 32 | #define BCM2835_DMA_CS_INT (1<<2) 33 | 34 | #define BCM2835_DMA_TI_PERMAP(permap) (((permap) & 0x1f) << 16) 35 | #define BCM2835_DMA_TI_SRC_IGNORE (1<<11) 36 | #define BCM2835_DMA_TI_SRC_DREQ (1<<10) 37 | #define BCM2835_DMA_TI_SRC_WIDTH (1<<9) 38 | #define BCM2835_DMA_TI_SRC_INC (1<<8) 39 | #define BCM2835_DMA_TI_DEST_IGNORE (1<<7) 40 | #define BCM2835_DMA_TI_DEST_DREQ (1<<6) 41 | #define BCM2835_DMA_TI_DEST_WIDTH (1<<5) 42 | #define BCM2835_DMA_TI_DEST_INC (1<<4) 43 | #define BCM2835_DMA_TI_WAIT_RESP (1<<3) 44 | #define BCM2835_DMA_TI_TDMODE (1<<1) 45 | 46 | 47 | 48 | 49 | #include 50 | 51 | 52 | typedef struct __attribute__ ((aligned (32))) { 53 | uint32_t ti; 54 | uint32_t source_ad; 55 | uint32_t dest_ad; 56 | uint32_t txfr_len; 57 | uint32_t stride; 58 | uint32_t nextconblk; 59 | uint32_t reserved[2]; 60 | } bcm2835_dma_conblk; 61 | 62 | 63 | typedef unsigned int bcm2835_dma_channel_t; 64 | 65 | bcm2835_dma_channel_t bcm2835_dma_alloc(unsigned int lite); 66 | 67 | void bcm2835_dma_fill_conblk(bcm2835_dma_conblk *conblk, 68 | volatile void *destination, volatile const void *source, unsigned long length, 69 | unsigned long permap); 70 | 71 | void bcm2835_dma_fill_conblk_2d(bcm2835_dma_conblk *conblk, 72 | volatile void *destination, volatile const void *source, 73 | long destination_stride, long source_stride, 74 | unsigned long xlength, unsigned long ylength, 75 | unsigned long permap); 76 | 77 | 78 | static inline void bcm2835_dma_chain_conblk(bcm2835_dma_conblk *conblk, bcm2835_dma_conblk *next) { 79 | conblk->nextconblk = (uint32_t) next | 0x40000000; // L2 cached alias 80 | } 81 | 82 | void bcm2835_dma_reset(bcm2835_dma_channel_t channel); 83 | int bcm2835_dma_start(bcm2835_dma_channel_t channel, bcm2835_dma_conblk *conblk); 84 | 85 | int bcm2835_dma_isready(bcm2835_dma_channel_t channel); 86 | void bcm2835_dma_register_interrupt(bcm2835_dma_channel_t channel, void (*handler) (void *), void *closure); 87 | void bcm2835_dma_acknowledge_interrupt(bcm2835_dma_channel_t channel); 88 | 89 | static inline void bcm2835_dma_enable_interrupt(bcm2835_dma_channel_t channel) { 90 | if (channel<=12) { 91 | IRQ_ENABLE1 = 1<<(channel+16); 92 | } 93 | } 94 | 95 | static inline void bcm2835_dma_disable_interrupt(bcm2835_dma_channel_t channel) { 96 | if (channel<=12) { 97 | IRQ_DISABLE1 = 1<<(channel+16); 98 | } 99 | } 100 | 101 | #endif 102 | -------------------------------------------------------------------------------- /src/pi/bcmmailbox.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | #include "bcmmailbox.h" 6 | 7 | #define MAILBOX_BASE (0x20000000 + 0xB880) 8 | 9 | #define MAILBOX0_READ (MAILBOX_BASE + 0x00) 10 | #define MAILBOX0_STATUS (MAILBOX_BASE + 0x18) 11 | #define MAILBOX_STATUS_EMPTY 0x40000000 12 | #define MAILBOX1_WRITE (MAILBOX_BASE + 0x20) 13 | #define MAILBOX1_STATUS (MAILBOX_BASE + 0x38) 14 | #define MAILBOX_STATUS_FULL 0x80000000 15 | 16 | 17 | 18 | 19 | 20 | static inline unsigned int _read(unsigned int address) { 21 | unsigned int ret; 22 | DataMemBarrier(); 23 | ret = *((unsigned long *)address); 24 | DataMemBarrier(); 25 | return ret; 26 | } 27 | 28 | static inline void _write(unsigned int address, unsigned int value) { 29 | DataMemBarrier(); 30 | *((unsigned long *)address) = value; 31 | DataMemBarrier(); 32 | } 33 | 34 | void PiPyOS_bcm_mailbox_write_read(int channel, void *data) { 35 | 36 | assert(((unsigned int) data & 0xf)==0); // must be 16-byte aligned 37 | 38 | CleanDataCache (); 39 | DataSyncBarrier (); 40 | 41 | while(_read(MAILBOX1_STATUS) & MAILBOX_STATUS_FULL); 42 | _write(MAILBOX1_WRITE, channel | 0x40000000 | (unsigned int) data); //0x40000000 = GPU_CACHED_BASE 43 | 44 | unsigned long read; 45 | do { 46 | while (_read(MAILBOX0_STATUS) & MAILBOX_STATUS_EMPTY); 47 | read = _read(MAILBOX0_READ); 48 | } while ((read & 0xf) != channel); 49 | 50 | InvalidateDataCache (); 51 | } 52 | 53 | /* id: tag id 54 | * data: pointer to data to be sent; also where to store the reply 55 | * size: size of data area 56 | * 57 | * returns: size of response 58 | * -1 for error 59 | */ 60 | int PiPyOS_bcm_get_set_property_tag(int tagid, void *data, int size) { 61 | int buffersize = size + 32; 62 | int responsesize; 63 | char* buffer; 64 | unsigned long *buffer_aligned; 65 | 66 | if ((size & 0x3) != 0) return -1; //size must be whole words 67 | 68 | // get 16-byte aligned buffer 69 | buffer = malloc(buffersize + 15); 70 | if (!buffer) return -1; 71 | 72 | buffer_aligned = (void*)((((unsigned int)buffer)+15) & ~0xf); 73 | 74 | buffer_aligned[0] = buffersize; 75 | buffer_aligned[1] = 0; // CODE_REQUEST 76 | buffer_aligned[2] = tagid; 77 | buffer_aligned[3] = size; 78 | buffer_aligned[4] = 0; 79 | 80 | memcpy(&buffer_aligned[5], data, size); 81 | memset(((char*)&buffer_aligned[5]) + size, 0, 12); // add sentinel tag (0,0,0) 82 | 83 | 84 | PiPyOS_bcm_mailbox_write_read(8, (void*)buffer_aligned); 85 | 86 | if (buffer_aligned[1] != 0x80000000) { 87 | free(buffer); 88 | return -1; 89 | } 90 | 91 | responsesize = buffer_aligned[4] & ~(1<<31); 92 | if (responsesize>size) { 93 | free(buffer); 94 | return -1; 95 | } 96 | 97 | memcpy(data, &buffer_aligned[5], size); 98 | 99 | free(buffer); 100 | 101 | return responsesize; 102 | 103 | } 104 | 105 | 106 | /* Short-cut for tags that only need reading; clears data and calls 107 | * PiPyOS_bcm_get_set_property_tag. See PiPyOS_bcm_get_set_property_tag. 108 | */ 109 | int PiPyOS_bcm_get_property_tag(int tagid, void *data, int size) { 110 | memset(data, 0, size); // clear initial data 111 | return PiPyOS_bcm_get_set_property_tag(tagid, data, size); 112 | } 113 | 114 | 115 | -------------------------------------------------------------------------------- /src/condvar.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Portable condition variable support for windows and pthreads. 3 | * Everything is inline, this header can be included where needed. 4 | * 5 | * APIs generally return 0 on success and non-zero on error, 6 | * and the caller needs to use its platform's error mechanism to 7 | * discover the error (errno, or GetLastError()) 8 | * 9 | * Note that some implementations cannot distinguish between a 10 | * condition variable wait time-out and successful wait. Most often 11 | * the difference is moot anyway since the wait condition must be 12 | * re-checked. 13 | * PyCOND_TIMEDWAIT, in addition to returning negative on error, 14 | * thus returns 0 on regular success, 1 on timeout 15 | * or 2 if it can't tell. 16 | * 17 | * There are at least two caveats with using these condition variables, 18 | * due to the fact that they may be emulated with Semaphores on 19 | * Windows: 20 | * 1) While PyCOND_SIGNAL() will wake up at least one thread, we 21 | * cannot currently guarantee that it will be one of the threads 22 | * already waiting in a PyCOND_WAIT() call. It _could_ cause 23 | * the wakeup of a subsequent thread to try a PyCOND_WAIT(), 24 | * including the thread doing the PyCOND_SIGNAL() itself. 25 | * The same applies to PyCOND_BROADCAST(), if N threads are waiting 26 | * then at least N threads will be woken up, but not necessarily 27 | * those already waiting. 28 | * For this reason, don't make the scheduling assumption that a 29 | * specific other thread will get the wakeup signal 30 | * 2) The _mutex_ must be held when calling PyCOND_SIGNAL() and 31 | * PyCOND_BROADCAST(). 32 | * While e.g. the posix standard strongly recommends that the mutex 33 | * associated with the condition variable is held when a 34 | * pthread_cond_signal() call is made, this is not a hard requirement, 35 | * although scheduling will not be "reliable" if it isn't. Here 36 | * the mutex is used for internal synchronization of the emulated 37 | * Condition Variable. 38 | */ 39 | 40 | #ifndef _CONDVAR_H_ 41 | #define _CONDVAR_H_ 42 | 43 | #include "ch.h" 44 | 45 | #define Py_HAVE_CONDVAR 46 | 47 | /* The following functions return 0 on success, nonzero on error 48 | * 49 | * Since the ChibiOS functions return void, use the comma operator to return 0 50 | * 51 | * The ChibiOS chMtxUnlock() function has not parameter, but relies on 52 | * unlocking in lock-reverse order. This is actually the case in ceval_gil.h, 53 | * the only file from where this file is included. 54 | */ 55 | #define PyMUTEX_T Mutex 56 | #define PyMUTEX_INIT(mut) (chMtxInit(mut), 0) 57 | #define PyMUTEX_FINI(mut) (0) 58 | #define PyMUTEX_LOCK(mut) (chMtxLock(mut), 0) 59 | #define PyMUTEX_UNLOCK(mut) (chMtxUnlock(), 0) 60 | 61 | #define PyCOND_T CondVar 62 | #define PyCOND_INIT(cond) (chCondInit(cond), 0) 63 | #define PyCOND_FINI(cond) (0) 64 | #define PyCOND_SIGNAL(cond) (chCondSignal(cond), 0) 65 | #define PyCOND_BROADCAST(cond) (chCondBroadcast(cond), 0) 66 | #define PyCOND_WAIT(cond, mut) (chCondWait(cond), 0) 67 | 68 | /* return 0 for success, 1 on timeout, -1 on error */ 69 | static inline int 70 | PyCOND_TIMEDWAIT(PyCOND_T *cond, PyMUTEX_T *mut, long long us) 71 | { 72 | 73 | msg_t r = chCondWaitTimeout(cond, (us * CH_FREQUENCY)/1000000LL); 74 | 75 | if (r == RDY_TIMEOUT) { 76 | // ChibiOS does not re-aquire the mutex on a timeout, but Python expects it to 77 | // So we re-aquire it here 78 | chMtxLock(mut); 79 | return 1; 80 | } else if (r==RDY_OK) { 81 | return 0; 82 | } else { 83 | return -1; 84 | } 85 | } 86 | 87 | #endif /* _CONDVAR_H_ */ 88 | -------------------------------------------------------------------------------- /src/py/config.c: -------------------------------------------------------------------------------- 1 | /* -*- C -*- *********************************************** 2 | Copyright (c) 2000, BeOpen.com. 3 | Copyright (c) 1995-2000, Corporation for National Research Initiatives. 4 | Copyright (c) 1990-1995, Stichting Mathematisch Centrum. 5 | All rights reserved. 6 | 7 | See the file "Misc/COPYRIGHT" for information on usage and 8 | redistribution of this file, and for a DISCLAIMER OF ALL WARRANTIES. 9 | ******************************************************************/ 10 | 11 | /* Module configuration */ 12 | 13 | /* !!! !!! !!! This file is edited by the makesetup script !!! !!! !!! */ 14 | 15 | /* This file contains the table of built-in modules. 16 | See create_builtin() in import.c. */ 17 | 18 | #include "Python.h" 19 | 20 | #ifdef __cplusplus 21 | extern "C" { 22 | #endif 23 | 24 | extern PyObject* PyInit_posix(void); 25 | extern PyObject* PyInit__weakref(void); 26 | extern PyObject* PyInit__io(void); 27 | extern PyObject* PyInit_zipimport(void); 28 | extern PyObject* PyInit__codecs(void); 29 | extern PyObject* PyInit_errno(void); 30 | extern PyObject* PyInit__struct(void); 31 | extern PyObject* PyInit_math(void); 32 | extern PyObject* PyInit_itertools(void); 33 | extern PyObject* PyInit_time(void); 34 | extern PyObject* PyInit__functools(void); 35 | extern PyObject* PyInit_atexit(void); 36 | extern PyObject* PyInit_array(void); 37 | extern PyObject* PyInit_zlib(void); 38 | extern PyObject* PyInit__thread(void); 39 | extern PyObject* PyInit__sre(void); 40 | extern PyObject* PyInit__collections(void); 41 | extern PyObject* PyInit__rpi(void); 42 | extern PyObject* PyInit_chibios(void); 43 | extern PyObject* PyInit_spi(void); 44 | extern PyObject* PyInit_i2c(void); 45 | extern PyObject* PyInit_app(void); 46 | extern PyObject* PyInit_lvgl(void); 47 | extern PyObject* PyInit_pitft(void); 48 | 49 | /* -- ADDMODULE MARKER 1 -- */ 50 | 51 | extern PyObject* PyMarshal_Init(void); 52 | extern PyObject* PyInit_imp(void); 53 | extern PyObject* PyInit_gc(void); 54 | extern PyObject* PyInit__ast(void); 55 | extern PyObject* _PyWarnings_Init(void); 56 | extern PyObject* PyInit__string(void); 57 | 58 | struct _inittab _PyImport_Inittab[] = { 59 | 60 | {"posix", PyInit_posix}, 61 | {"_weakref", PyInit__weakref}, 62 | {"_io", PyInit__io}, 63 | {"zipimport", PyInit_zipimport}, 64 | {"_codecs", PyInit__codecs}, 65 | {"errno", PyInit_errno}, 66 | {"_struct", PyInit__struct}, 67 | {"math", PyInit_math}, 68 | {"itertools", PyInit_itertools}, 69 | {"time", PyInit_time}, 70 | {"_functools", PyInit__functools}, 71 | {"atexit", PyInit_atexit}, 72 | {"array", PyInit_array}, 73 | {"zlib", PyInit_zlib}, 74 | {"_thread", PyInit__thread}, 75 | {"_sre", PyInit__sre}, 76 | {"_collections", PyInit__collections}, 77 | {"_rpi", PyInit__rpi}, 78 | {"chibios", PyInit_chibios}, 79 | {"spi", PyInit_spi}, 80 | {"i2c", PyInit_i2c}, 81 | {"_app", PyInit_app}, 82 | {"lvgl", PyInit_lvgl}, 83 | {"pitft", PyInit_pitft}, 84 | 85 | /* -- ADDMODULE MARKER 2 -- */ 86 | 87 | /* This module lives in marshal.c */ 88 | {"marshal", PyMarshal_Init}, 89 | 90 | /* This lives in import.c */ 91 | {"_imp", PyInit_imp}, 92 | 93 | /* This lives in Python/Python-ast.c */ 94 | {"_ast", PyInit__ast}, 95 | 96 | /* These entries are here for sys.builtin_module_names */ 97 | {"builtins", NULL}, 98 | {"sys", NULL}, 99 | 100 | /* This lives in gcmodule.c */ 101 | {"gc", PyInit_gc}, 102 | 103 | /* This lives in _warnings.c */ 104 | {"_warnings", _PyWarnings_Init}, 105 | 106 | /* This lives in Objects/unicodeobject.c */ 107 | {"_string", PyInit__string}, 108 | 109 | /* Sentinel */ 110 | {0, 0} 111 | }; 112 | 113 | 114 | #ifdef __cplusplus 115 | } 116 | #endif 117 | -------------------------------------------------------------------------------- /src/py/i2cmodule.c: -------------------------------------------------------------------------------- 1 | #include "Python.h" 2 | #include "hal.h" 3 | 4 | 5 | #define I2C_START_DOC "start(channel, bitrate)" 6 | 7 | #define NUM_I2C_PERIPHERALS 2 8 | 9 | static I2CDriver *channels[NUM_I2C_PERIPHERALS] = {&I2C0, &I2C1}; 10 | static I2CConfig cfg[NUM_I2C_PERIPHERALS]; 11 | 12 | static PyObject * 13 | i2c_start(PyObject *self, PyObject *args) { 14 | char *error = NULL; 15 | int channel, bitrate; 16 | I2CDriver *ch; 17 | 18 | if (!PyArg_ParseTuple(args, "ii", &channel, &bitrate)) { 19 | return NULL; 20 | } 21 | 22 | memset(&cfg, 0, sizeof(cfg)); 23 | 24 | if ((channel != 0) && (channel !=1)) error = "Channel must be 0 or 1"; 25 | if (bitrate <=0) error = "Bitrate must be > 0"; 26 | if (error) { 27 | PyErr_SetString(PyExc_ValueError, error); 28 | return NULL; 29 | } 30 | 31 | cfg[channel].ic_speed = bitrate; 32 | 33 | ch = channels[channel]; 34 | i2cAcquireBus(ch); 35 | i2cStart(ch, &cfg[channel]); 36 | i2cReleaseBus(ch); 37 | 38 | Py_RETURN_NONE; 39 | } 40 | 41 | 42 | 43 | #define I2C_TRANSFER_DOC \ 44 | "transfer(channel, address, txdata, rxcnt, timeout)\n" \ 45 | "\n" \ 46 | "address: 7-bit I2C address\n" \ 47 | "txdata: bytes buffer or None, in which case data is transmitted\n" \ 48 | "rxcnt: number of bytes to be received\n" \ 49 | "timeout: timeout [s], float\n" \ 50 | "\n" \ 51 | "returns: received data : bytes\n" 52 | 53 | static PyObject * 54 | i2c_transfer(PyObject *self, PyObject *args) { 55 | int channel, address, rxcnt, txdatasize; 56 | unsigned char *txdata; 57 | char *error = NULL; 58 | float timeout; 59 | PyObject *rxbytes = NULL; 60 | systime_t timeout_val; 61 | msg_t result; 62 | I2CDriver *ch; 63 | 64 | if (!PyArg_ParseTuple(args, "iiz#if", &channel, &address, &txdata, &txdatasize, &rxcnt, &timeout)) { 65 | return NULL; 66 | } 67 | 68 | if ((channel != 0) && (channel !=1)) error = "channel must be 0 or 1"; 69 | if (address<0 || address >127) error = "address should be 0<=channel<=127"; 70 | if (rxcnt <0) error = "rxcnt should be >= 0"; 71 | if (timeout<=0 || isnan(timeout) || isinf(timeout)) error = "timeout should be >0"; 72 | if ((rxcnt==0) && (txdatasize==0)) error = "txdata is empty and rxcnt=0; no data to transfer"; 73 | if (error) { 74 | PyErr_SetString(PyExc_ValueError, error); 75 | return NULL; 76 | } 77 | 78 | timeout_val = timeout * CH_FREQUENCY; 79 | 80 | rxbytes = PyBytes_FromStringAndSize(NULL, rxcnt); 81 | if (!rxbytes) return NULL; 82 | 83 | ch = channels[channel]; 84 | i2cAcquireBus(ch); 85 | 86 | if (txdatasize > 0) { 87 | result = i2cMasterTransmitTimeout(ch, address, txdata, txdatasize, (unsigned char*)PyBytes_AS_STRING(rxbytes), rxcnt, timeout_val); 88 | } else { 89 | result = i2cMasterReceiveTimeout(ch, address, (unsigned char*)PyBytes_AS_STRING(rxbytes), rxcnt, timeout_val); 90 | } 91 | 92 | i2cReleaseBus(ch); 93 | 94 | switch(result) { 95 | case RDY_OK: 96 | return rxbytes; 97 | case RDY_RESET: 98 | PyErr_SetString(PyExc_IOError, "an I2C error occurred"); 99 | break; 100 | case RDY_TIMEOUT: 101 | PyErr_SetString(PyExc_TimeoutError, "I2C operation timed out"); 102 | break; 103 | } 104 | 105 | Py_DECREF(rxbytes); 106 | return NULL; 107 | } 108 | 109 | static PyMethodDef i2cMethods[] = { 110 | {"start", i2c_start, METH_VARARGS, I2C_START_DOC}, 111 | {"transfer", i2c_transfer, METH_VARARGS, I2C_TRANSFER_DOC}, 112 | 113 | {NULL, NULL, 0, NULL} /* Sentinel */ 114 | }; 115 | 116 | static struct PyModuleDef i2cmodule = { 117 | PyModuleDef_HEAD_INIT, 118 | "i2c", /* name of module */ 119 | NULL, /* module documentation, may be NULL */ 120 | -1, /* size of per-interpreter state of the module, 121 | or -1 if the module keeps state in global variables. */ 122 | i2cMethods 123 | }; 124 | 125 | 126 | PyMODINIT_FUNC 127 | PyInit_i2c(void) { 128 | 129 | return PyModule_Create(&i2cmodule); // could be NULL in case of error 130 | 131 | } 132 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # PiPyOS 2 | ### Bare-metal Python for Raspberry Pi 3 | 4 | The PiPyOS project aims at providing a bare-metal Python image for the Raspberry Pi, for use in embedded and/or real-time applications. It provides the agile development that is possible with Python, without the overhead of the Linux OS that is commonly employed on the Raspberry Pi. This results in, among others, faster boot-times and more control over the hardware. By using a minimal real-time operating system (RTOS), it is possible to combine a real-time component (written in C) with a high-level application component (written in Python). 5 | 6 | At the moment, PiPyOS only runs on the Raspberry Pi 1 and Raspberry Pi Zero (i.e., the BCM2835 based Raspberry Pi's, main development is done on a Pi Zero). This limitation is due to the fact that ChibiOS has so far only been ported to this platform. However, it should also be possible to port to the other platforms. 7 | 8 | PiPyOS depends on a few components that provide its main functionality: 9 | 10 | * A cross-compiler toolchain with the Newlib c-library 11 | This is required to build the code. 12 | 13 | * [cpython](https://www.python.org) 14 | This is the Python interpreter. Its C-source is used unchanged, but the build-process is customized when building from PiPyOS. At the current state, there are a few Python files in the standard library that are adapted, but this should not be necessary in te future. 15 | 16 | * [ChibiOS](http://www.chibios.org) 17 | This is the real-time OS. It provides a task scheduler with separate tasks for the Python interpreter and for the real-time functionality. It also provides a hardware abstraction layer (HAL) for several hardware components. PiPyOS uses the [Raspberry Pi port by Steven Bate](https://github.com/steve-bate/ChibiOS-RPi). 18 | 19 | * [FatFs](http://elm-chan.org/fsw/ff/00index_e.html) 20 | This is the FAT filesystem driver that is used to read files from the SD-card 21 | 22 | * [LittlevGL](https://littlevgl.com), [pylvgl](https://github.com/rreilink/pylvgl) 23 | This embedded graphics library provides GUI functionality from Python 24 | 25 | * [USPi](https://github.com/rsta2/uspi) 26 | USPi provides basic USB functionality required for keyboard and ethernet functionality. This is not yet integrated. 27 | 28 | In order to make things work, PiPyOS provides the following: 29 | 30 | * A SCons build script 31 | Similar to a Makefile, this script controls the build process, building all the dependencies with the required options. 32 | 33 | * Newlib interfaces for OS calls 34 | For calls like *open*, *read*, etc. the Newlib c-library does not provide the OS-functionality, since it is unaware of the OS. Thus, these calls need to be implemented. Some of these calls use ChibiOS to provide the required functionality (e.g. serial port terminal interface, clock, etc), some are manually implemented (e.g. sbrk(); the memory management below malloc()), and others interface to the initfs file system (see below) 35 | 36 | * Initfs read-only memory filesystem 37 | Although ChibiOS provides an interface to a FAT filesystem library, this is currently not implemented in PiPyOS as there is no driver for the SD-card (yet). Instead, when building PiPyOS, several required files for starting Python (and additionally, files required for the application) are combined into a binary file. PyPiOS exposes these files (read-only) to Python via the open(), read(), readdir() etc. calls from Newlib 38 | 39 | * Python modules for specific functionality 40 | E.g. spi, i2c, (for the Raspberry Pi peripherals), pitft (for the Adafruit PiTFT display) 41 | 42 | ## Status and roadmap 43 | 44 | The following functionality is currently implemented: 45 | 46 | * Starting Python upto the >>> prompt 47 | * Interface via the serial console 48 | * readline 49 | * Framebuffer (screen via HDMI) support 50 | * evaluation of real-time performance 51 | * SD-card interface 52 | * FAT filesystem support 53 | * GUI support using pylvgl / LittlevGL graphics library 54 | * Threading support 55 | 56 | The following functionality is foreseen (in order of development) 57 | 58 | * Loadable binary modules / shared libraries 59 | * USB keyboard support 60 | * Ethernet support via USB-to-Ethernet (either internal to Raspberry Pi or external for RPi Zero) 61 | * TCP/IP support 62 | 63 | 64 | 65 | 66 | -------------------------------------------------------------------------------- /src/zloader/zloader.c: -------------------------------------------------------------------------------- 1 | /* 2 | * This is the main code of the zloader 3 | * 4 | * zloader uncompresses a compressed image and then starts execution. 5 | * 6 | * In order to allow transparent operation, the decompressed image must be 7 | * stored at address 0x8000, which is where the Raspberry Pi start.elf loads 8 | * images and starts execution. However, obviously this is also where the 9 | * loader is loaded at startup. To circumvent this problem, the startup code 10 | * in zloader_asm.s copies (relocates) the loader image including the compressed 11 | * image to a location at some other place in memory before calling the C 12 | * loader() function. 13 | * 14 | * Note that the linker script does not define a .bss section, which means 15 | * that no 0-initalized global variables (or local static variables) can 16 | * exist in this file. (This would also require .bss zeroing code at startup, 17 | * which is unnecessary). 18 | * 19 | */ 20 | 21 | 22 | #include 23 | #include "zlib.h" 24 | 25 | 26 | /* 27 | * Enable/disable debugging via UART. Note that there is no UART initialization 28 | * code in the loader; thus debugging only works when the UART is already 29 | * initialized by an even earlier loader (e.g. a serial bootloader). Leave 30 | * disabled for normal operation 31 | */ 32 | #define UART_DEBUG 0 33 | 34 | #if UART_DEBUG 35 | 36 | #define REG(x) (*(volatile uint32_t *)(x)) 37 | #define AUX_MU_IO_REG REG(0x20215040) 38 | #define AUX_MU_LSR_REG REG(0x20215054) 39 | #define SYSTIMER_CLO REG(0x20003004) 40 | 41 | 42 | void uart_putch(char c) { 43 | while(!(AUX_MU_LSR_REG & 0x20)); 44 | AUX_MU_IO_REG = c; 45 | } 46 | 47 | 48 | void uart_puthex(unsigned long d) { 49 | int i; 50 | char c; 51 | for(i=0;i<8;i++) { 52 | c = (d>>28)&0xf; 53 | if (c>9) c+='A'- 10; else c+='0'; 54 | uart_putch(c); 55 | d<<=4; 56 | } 57 | uart_putch('\n'); 58 | } 59 | 60 | #endif 61 | 62 | /* Memory locations defined by the linker script zloader.ld */ 63 | extern unsigned char _end,__reloc_base__, __reloc_target__, __reloc_end__; 64 | 65 | /* Minimalistic, 100% leaking malloc/free implementation suffices for the loader */ 66 | unsigned char *heap = (void*)0x4000000; //64 MB 67 | void* zcalloc(voidpf ctx, uInt items, uInt size) { 68 | void *ret = heap; 69 | heap += (items*size); 70 | return ret; 71 | } 72 | 73 | void zcfree(voidpf ctx, void *ptr) { 74 | } 75 | 76 | 77 | /* This is the main code called by zloader_asm startup code. Upon return, 78 | * the startup code branches to 0x8000 to start execution. 79 | * 80 | * This is not called 'main' since the function signature is different. 81 | * 82 | * loader(size, t0) 83 | * size: size of the compressed data in bytes 84 | * t0: value of the system timer SYSTIMER_CLO upon start of the 85 | * startup code. Allows measureing startup and relocation time. 86 | */ 87 | int loader(unsigned long size, unsigned long t0) { 88 | int result; 89 | z_stream zst; 90 | 91 | #if UART_DEBUG 92 | unsigned long t1, t2; 93 | 94 | t1 = SYSTIMER_CLO; 95 | uart_putch('Z'); 96 | 97 | #endif 98 | 99 | // Set up z_stream struct with the compression information 100 | zst.opaque = NULL; 101 | zst.zalloc = zcalloc; 102 | zst.zfree = zcfree; 103 | zst.avail_in = size; 104 | zst.next_in = &_end+4; // Compressed data starts 1 word after the loader 105 | zst.next_out = &__reloc_base__; // Destination is where our loader was originally loaded 106 | zst.avail_out = 0x7000000; 107 | result = inflateInit2(&zst, 15); 108 | 109 | if (result) { 110 | for(;;); // Error, can do nothing but hang 111 | } 112 | 113 | result = inflate(&zst, Z_FINISH); 114 | 115 | if (result!=Z_STREAM_END) { 116 | for(;;); // Error, can do nothing but hang 117 | } 118 | 119 | #if UART_DEBUG 120 | t2 = SYSTIMER_CLO; 121 | uart_putch('\n'); 122 | uart_puthex(size); 123 | uart_puthex(t0); 124 | 125 | uart_puthex(t1-t0); 126 | uart_puthex(t2-t1); 127 | uart_putch('\n'); 128 | 129 | #endif 130 | 131 | return 0; 132 | } 133 | -------------------------------------------------------------------------------- /tools/mkinitfs.py: -------------------------------------------------------------------------------- 1 | ''' 2 | Initfs file format: 3 | 4 | 5 | main table: 6 | int,int,int (3x4 bytes): offset of filename, offset of data, file size 7 | 8 | names table: 9 | chars (null-terminated) 10 | 11 | data: 12 | bytes (not terminated) 13 | 14 | The main table also includes directory listings, these are automatically generated 15 | These are identified by a file size of 0xffffffff 16 | 17 | ''' 18 | 19 | import struct 20 | import os 21 | import glob 22 | 23 | class InitFS: 24 | recordformat = 'III' # name offset, data offset, file size 25 | def __init__(self): 26 | 27 | self.clear() 28 | def clear(self): 29 | self.filetable = [] 30 | self.data = b'' 31 | def addfile(self, localfile, destfile): 32 | with open(localfile, 'rb') as file: 33 | data = file.read() 34 | self.filetable.append((destfile, len(self.data), len(data))) 35 | self.data+=data 36 | 37 | def tostring(self): 38 | # Add directory names 39 | 40 | 41 | filetable = list(self.filetable) # Copy table 42 | newdirs = { os.path.dirname(f[0]) for f in filetable } 43 | dirs = newdirs 44 | 45 | # Recursively find all parent dirs of all files 46 | while True: 47 | newdirs = { os.path.dirname(d) for d in newdirs } 48 | if not newdirs - dirs: 49 | break # No new dirs found 50 | dirs |= newdirs 51 | 52 | 53 | for dir in dirs: 54 | if dir == '/': 55 | # For consistency: no file or dir ends with /, including root 56 | dir = '' 57 | filetable.append((dir, 0, 0xffffffff)) 58 | 59 | 60 | # Sort filetable to allow for proper directory listing: 61 | # For each directory, first the file, then subdir 62 | filetable.sort(key=lambda x: (x[0], x[1] is None, x[0])) 63 | 64 | # for line in filetable: 65 | # print(line) 66 | 67 | # Calculate number of bytes required for main table (add 1 for 0,0,0 sentinel) 68 | maintablesize = (len(filetable) + 1) * struct.calcsize(self.recordformat) 69 | 70 | # Build name string table 71 | nameoffsets = [] 72 | nametable = b'' 73 | 74 | for filename, dataoffset, size in filetable: 75 | nameoffsets.append(len(nametable)) 76 | nametable += filename.encode('ascii')+b'\x00' 77 | 78 | maintable = b'' 79 | for (filename, dataoffset, size), nameoffset in zip(filetable, nameoffsets): 80 | maintable += struct.pack(self.recordformat, 81 | nameoffset + maintablesize, 82 | dataoffset + len(nametable) + maintablesize, 83 | size) 84 | 85 | maintable += struct.pack(self.recordformat, 0, 0, 0) # Add sentinel 86 | assert len(maintable) == maintablesize 87 | return maintable + nametable + self.data 88 | 89 | def main(target=None, source=None, env=None): 90 | if target is None: 91 | outfile = 'initfs.bin' 92 | else: 93 | outfile = target[0].name 94 | 95 | fs = InitFS() 96 | 97 | 98 | for file in [ 99 | 'encodings/__init__.py', 100 | 'encodings/ascii.py', 101 | 'encodings/aliases.py', 102 | 'encodings/utf_8.py', 103 | 'encodings/latin_1.py', 104 | 'encodings/cp437.py', 105 | 'io.py', 106 | 'abc.py', 107 | '_weakrefset.py', 108 | 'site.py', 109 | '_sitebuiltins.py', 110 | 'os.py', 111 | 'stat.py', 112 | 'genericpath.py', 113 | '_collections_abc.py', 114 | 'struct.py', 115 | 'codecs.py']: 116 | pass # Only use if reading from zip file is not working 117 | # fs.addfile('deps/cpython/Lib/' + file, '/' + file) 118 | 119 | # 120 | fs.addfile('lib/posixpath.py','/posixpath.py') 121 | fs.addfile('lib/sysconfig.py','/sysconfig.py') 122 | fs.addfile('python/_readline.py','/_readline.py') 123 | fs.addfile('python/loader.py','/loader.py') 124 | for file in glob.glob('app/target/*'): 125 | fs.addfile(file, '/app/' + file[11:]) 126 | 127 | 128 | with open(outfile, 'wb') as file: 129 | file.write(fs.tostring()) 130 | 131 | if __name__ == '__main__': 132 | import os 133 | os.chdir('..') 134 | main() 135 | 136 | -------------------------------------------------------------------------------- /src/py/pyadaptor.c: -------------------------------------------------------------------------------- 1 | #include "pyconfig.h" 2 | #include "Python.h" 3 | #include "adaptor.h" 4 | #include "ch.h" 5 | #include 6 | 7 | /* 8 | Provide the readline functionality provided in the Python function 9 | _readline.readline 10 | 11 | This function ignores sys_stdin and sys_stdout, they are assumed to be 12 | the default values. 13 | */ 14 | static PyObject *readlinecallback = NULL; 15 | char *PyOS_StdioReadline(FILE *sys_stdin, FILE *sys_stdout, const char *prompt); 16 | 17 | 18 | char *PiPyOS_readline(FILE *sys_stdin, FILE *sys_stdout, const char *prompt) { 19 | PyObject *module = NULL, *function = NULL, *line = NULL, *linebytes = NULL, *err; 20 | char *line_cstr = NULL, *ret = NULL; 21 | Py_ssize_t len; 22 | 23 | PyGILState_STATE gstate; 24 | 25 | gstate = PyGILState_Ensure(); 26 | 27 | if (!readlinecallback) { 28 | 29 | PyObject *module = PyImport_ImportModule("_readline"); 30 | if (!module) goto error; 31 | 32 | PyObject *function = PyObject_GetAttrString(module, "readline"); 33 | if (!function) goto error; 34 | 35 | if (!PyCallable_Check(function)) { 36 | PyErr_SetString(PyExc_TypeError, "_readline.readline must be callable"); 37 | goto error; 38 | } 39 | Py_INCREF(function); 40 | readlinecallback = function; 41 | } 42 | 43 | line = PyObject_CallFunction(readlinecallback, "s", prompt); 44 | if (!line) { 45 | // Check if it is a KeyboardInterrupt, propagate that and keep the 46 | // current readline handler as-is 47 | err = PyErr_Occurred(); 48 | if (err && PyErr_GivenExceptionMatches(err, PyExc_KeyboardInterrupt)) { 49 | ret = NULL; 50 | goto out; 51 | } 52 | 53 | goto error; 54 | } 55 | 56 | linebytes = PyUnicode_AsEncodedString(line, "latin-1", "ignore"); 57 | if (!linebytes) goto error; 58 | 59 | line_cstr = PyBytes_AsString(linebytes); 60 | if (!line_cstr) goto error; 61 | 62 | len = PyBytes_Size(linebytes); 63 | ret = PyMem_Malloc(len+1); 64 | if (!ret) { 65 | PyErr_NoMemory(); 66 | goto error; 67 | } 68 | memcpy(ret, line_cstr, len+1); 69 | 70 | goto out; 71 | 72 | error: 73 | ret = NULL; 74 | printf("readline error\n"); 75 | // Fall back to default ReadLine function for subsequent calls 76 | PyOS_ReadlineFunctionPointer = PyOS_StdioReadline; 77 | 78 | out: 79 | Py_XDECREF(linebytes); 80 | Py_XDECREF(line); 81 | Py_XDECREF(function); 82 | Py_XDECREF(module); 83 | 84 | PyGILState_Release(gstate); 85 | return ret; 86 | 87 | } 88 | 89 | void PiPyOS_initreadline(void) { 90 | PyOS_ReadlineFunctionPointer = PiPyOS_readline; 91 | } 92 | 93 | 94 | extern CondVar PiPyOS_serial_interrupt_cv; 95 | static volatile int interrupt_state = 0; 96 | 97 | static WORKING_AREA(waHandleInterruptThread, 4096); 98 | 99 | static int 100 | checksignals_witharg(void * arg) 101 | { 102 | return PyErr_CheckSignals(); 103 | } 104 | 105 | static msg_t HandleInterruptThread(void *p) { 106 | Mutex mtx; 107 | 108 | chRegSetThreadName("interrupt_catcher"); 109 | 110 | chMtxInit(&mtx); 111 | 112 | for(;;) { 113 | chMtxLock(&mtx); 114 | chCondWait (&PiPyOS_serial_interrupt_cv); 115 | chMtxUnlock(); 116 | 117 | interrupt_state = 1; 118 | Py_AddPendingCall(checksignals_witharg, NULL); 119 | } 120 | return RDY_OK; 121 | } 122 | 123 | int PyOS_InterruptOccurred(void) { 124 | int ret = interrupt_state; 125 | if (ret) interrupt_state = 0; 126 | return ret; 127 | } 128 | 129 | void PyOS_InitInterrupts(void) { 130 | /* 131 | * Create a thread to wait for the PiPyOS_serial_interrupt_cv condition variable 132 | * 133 | * It has a priority just above the priority of the Python thread(s) to ensure 134 | * it is activated when an interrupt occurs 135 | */ 136 | chThdCreateStatic(waHandleInterruptThread, sizeof(waHandleInterruptThread), NORMALPRIO+1, HandleInterruptThread, NULL); 137 | } 138 | 139 | void PyOS_FiniInterrupts(void) { } 140 | 141 | void PyErr_SetInterrupt(void) { 142 | interrupt_state = 1; 143 | } 144 | 145 | void PyOS_AfterFork() {} // Fork not supported 146 | 147 | void _fini(void) {} 148 | 149 | 150 | /* _tracemalloc.c cannot be built since it requires native thread-local storage, 151 | * which is not implemented. We don't need _tracemalloc anyway, but we need to 152 | * implement some stubs 153 | */ 154 | void _PyTraceMalloc_Init(void) { } 155 | void _PyTraceMalloc_Fini(void) { } 156 | void _PyMem_DumpTraceback(int fd, const void *ptr) { } 157 | 158 | -------------------------------------------------------------------------------- /src/py/spimodule.c: -------------------------------------------------------------------------------- 1 | #include "Python.h" 2 | #include "hal.h" 3 | 4 | 5 | #define SPI_START_DOC "start(channel, chipselect, frequency, cspol, cpol, cpha)" 6 | 7 | static SPIConfig cfg; //TODO: the low level driver should copy the settings, or we should manage them 8 | 9 | static PyObject * 10 | spi_start(PyObject *self, PyObject *args) { 11 | char *error = NULL; 12 | int channel, cs, freq, cspol, cpol, cpha; 13 | int divider; 14 | if (!PyArg_ParseTuple(args, "iiippp", &channel, &cs, &freq, &cspol, &cpol, &cpha)) { 15 | return NULL; 16 | } 17 | 18 | memset(&cfg, 0, sizeof(cfg)); 19 | 20 | if (channel != 0) error = "Only channel==0 is supported"; 21 | if (cs<0 || cs>=1) error = "cs should be 0 or 1"; 22 | if (freq <= 0) error = "frequency should be > 0"; 23 | 24 | if (error) { 25 | PyErr_SetString(PyExc_ValueError, error); 26 | return NULL; 27 | } 28 | 29 | divider = 250000000 / freq; 30 | if (divider == 0) divider = 1; 31 | if (divider & 1) divider++; // Ensure even; round up 32 | 33 | //cfg.lossiEnabled = 0; 34 | cfg.chip_select = cs; 35 | cfg.clock_polarity = cpol; 36 | cfg.clock_phase = cpha; 37 | //cfg.clock_divider = divider; 38 | cfg.clock_frequency = freq; 39 | spiStart(&SPI0, &cfg); 40 | 41 | Py_RETURN_NONE; 42 | } 43 | 44 | 45 | 46 | static PyObject * 47 | spi_select_unselect(PyObject *self, PyObject *args, int select) { 48 | int channel; 49 | if (!PyArg_ParseTuple(args, "i", &channel)) { 50 | return NULL; 51 | } 52 | if (channel != 0) { 53 | PyErr_SetString(PyExc_ValueError, "Only channel==0 is supported"); 54 | return NULL; 55 | } 56 | 57 | if (select) spiSelect(&SPI0); else spiUnselect(&SPI0); 58 | 59 | Py_RETURN_NONE; 60 | } 61 | 62 | #define SPI_SELECT_DOC "select(channel)" 63 | 64 | static PyObject * 65 | spi_select(PyObject *self, PyObject *args) { 66 | return spi_select_unselect(self, args, 1); 67 | } 68 | 69 | 70 | 71 | #define SPI_UNSELECT_DOC "unselect(channel)" 72 | 73 | static PyObject * 74 | spi_unselect(PyObject *self, PyObject *args) { 75 | return spi_select_unselect(self, args, 0); 76 | } 77 | 78 | 79 | 80 | #define SPI_EXCHANGE_DOC \ 81 | "exchange(channel, txdata, rx)\n" \ 82 | "\n" \ 83 | "txdata: bytes buffer or None, in which case no data is transmitted ('\0' bytes)\n" \ 84 | "rx: when txdata is None: number of bytes to be received\n" \ 85 | " when txdata is not None: boolean whether or not to receive data\n" 86 | 87 | static PyObject * 88 | spi_exchange(PyObject *self, PyObject *args) { 89 | int channel, rx, txdatasize, size; 90 | char *txdata; 91 | PyObject *rxbytes = NULL; 92 | 93 | if (!PyArg_ParseTuple(args, "iz#i", &channel, &txdata, &txdatasize, &rx)) { 94 | return NULL; 95 | } 96 | 97 | if (channel != 0) { 98 | PyErr_SetString(PyExc_ValueError, "Only channel==0 is supported"); 99 | return NULL; 100 | } 101 | 102 | // Determine transaction size = len(txdata) if txdata is not None else rx 103 | 104 | if (txdata) { 105 | size = txdatasize; 106 | } else { 107 | if (rx<=0) { 108 | PyErr_SetString(PyExc_ValueError, "rx should be > 0 if txdata is None"); 109 | return NULL; 110 | } 111 | size = rx; 112 | } 113 | 114 | if (rx) { 115 | rxbytes = PyBytes_FromStringAndSize(NULL, size); 116 | } 117 | 118 | // Now use: rxbytes as boolean to check whether to receive, txdata as boolean wether to transmit, size as size 119 | 120 | if (txdata) { 121 | if (rxbytes) { 122 | // transmit and receive 123 | spiExchange(&SPI0, size, txdata, PyBytes_AS_STRING(rxbytes)); 124 | } else { 125 | // only transmit 126 | spiSend(&SPI0, size, txdata); 127 | } 128 | } else { 129 | assert(rxbytes); 130 | // only receive 131 | spiReceive(&SPI0, size, PyBytes_AS_STRING(rxbytes)); 132 | } 133 | 134 | if (rxbytes) { 135 | return rxbytes; 136 | } else { 137 | Py_RETURN_NONE; 138 | } 139 | } 140 | 141 | static PyMethodDef SpiMethods[] = { 142 | {"start", spi_start, METH_VARARGS, SPI_START_DOC}, 143 | {"select", spi_select, METH_VARARGS, SPI_SELECT_DOC}, 144 | {"unselect", spi_unselect, METH_VARARGS, SPI_UNSELECT_DOC}, 145 | {"exchange", spi_exchange, METH_VARARGS, SPI_EXCHANGE_DOC}, 146 | 147 | {NULL, NULL, 0, NULL} /* Sentinel */ 148 | }; 149 | 150 | static struct PyModuleDef spimodule = { 151 | PyModuleDef_HEAD_INIT, 152 | "spi", /* name of module */ 153 | NULL, /* module documentation, may be NULL */ 154 | -1, /* size of per-interpreter state of the module, 155 | or -1 if the module keeps state in global variables. */ 156 | SpiMethods 157 | }; 158 | 159 | 160 | PyMODINIT_FUNC 161 | PyInit_spi(void) { 162 | 163 | return PyModule_Create(&spimodule); // could be NULL in case of error 164 | 165 | } 166 | -------------------------------------------------------------------------------- /deps/ff13a/ffsystem.c: -------------------------------------------------------------------------------- 1 | /*------------------------------------------------------------------------*/ 2 | /* Sample Code of OS Dependent Functions for FatFs */ 3 | /* (C)ChaN, 2017 */ 4 | /*------------------------------------------------------------------------*/ 5 | 6 | 7 | #include "ff.h" 8 | 9 | 10 | 11 | #if FF_USE_LFN == 3 /* Dynamic memory allocation */ 12 | 13 | /*------------------------------------------------------------------------*/ 14 | /* Allocate a memory block */ 15 | /*------------------------------------------------------------------------*/ 16 | 17 | void* ff_memalloc ( /* Returns pointer to the allocated memory block (null on not enough core) */ 18 | UINT msize /* Number of bytes to allocate */ 19 | ) 20 | { 21 | return malloc(msize); /* Allocate a new memory block with POSIX API */ 22 | } 23 | 24 | 25 | /*------------------------------------------------------------------------*/ 26 | /* Free a memory block */ 27 | /*------------------------------------------------------------------------*/ 28 | 29 | void ff_memfree ( 30 | void* mblock /* Pointer to the memory block to free (nothing to do for null) */ 31 | ) 32 | { 33 | free(mblock); /* Free the memory block with POSIX API */ 34 | } 35 | 36 | #endif 37 | 38 | 39 | 40 | #if FF_FS_REENTRANT /* Mutal exclusion */ 41 | 42 | /*------------------------------------------------------------------------*/ 43 | /* Create a Synchronization Object */ 44 | /*------------------------------------------------------------------------*/ 45 | /* This function is called in f_mount() function to create a new 46 | / synchronization object for the volume, such as semaphore and mutex. 47 | / When a 0 is returned, the f_mount() function fails with FR_INT_ERR. 48 | */ 49 | 50 | //const osMutexDef_t Mutex[FF_VOLUMES]; /* CMSIS-RTOS */ 51 | 52 | 53 | int ff_cre_syncobj ( /* 1:Function succeeded, 0:Could not create the sync object */ 54 | BYTE vol, /* Corresponding volume (logical drive number) */ 55 | FF_SYNC_t *sobj /* Pointer to return the created sync object */ 56 | ) 57 | { 58 | /* Win32 */ 59 | *sobj = CreateMutex(NULL, FALSE, NULL); 60 | return (int)(*sobj != INVALID_HANDLE_VALUE); 61 | 62 | /* uITRON */ 63 | // T_CSEM csem = {TA_TPRI,1,1}; 64 | // *sobj = acre_sem(&csem); 65 | // return (int)(*sobj > 0); 66 | 67 | /* uC/OS-II */ 68 | // OS_ERR err; 69 | // *sobj = OSMutexCreate(0, &err); 70 | // return (int)(err == OS_NO_ERR); 71 | 72 | /* FreeRTOS */ 73 | // *sobj = xSemaphoreCreateMutex(); 74 | // return (int)(*sobj != NULL); 75 | 76 | /* CMSIS-RTOS */ 77 | // *sobj = osMutexCreate(Mutex + vol); 78 | // return (int)(*sobj != NULL); 79 | } 80 | 81 | 82 | /*------------------------------------------------------------------------*/ 83 | /* Delete a Synchronization Object */ 84 | /*------------------------------------------------------------------------*/ 85 | /* This function is called in f_mount() function to delete a synchronization 86 | / object that created with ff_cre_syncobj() function. When a 0 is returned, 87 | / the f_mount() function fails with FR_INT_ERR. 88 | */ 89 | 90 | int ff_del_syncobj ( /* 1:Function succeeded, 0:Could not delete due to an error */ 91 | FF_SYNC_t sobj /* Sync object tied to the logical drive to be deleted */ 92 | ) 93 | { 94 | /* Win32 */ 95 | return (int)CloseHandle(sobj); 96 | 97 | /* uITRON */ 98 | // return (int)(del_sem(sobj) == E_OK); 99 | 100 | /* uC/OS-II */ 101 | // OS_ERR err; 102 | // OSMutexDel(sobj, OS_DEL_ALWAYS, &err); 103 | // return (int)(err == OS_NO_ERR); 104 | 105 | /* FreeRTOS */ 106 | // vSemaphoreDelete(sobj); 107 | // return 1; 108 | 109 | /* CMSIS-RTOS */ 110 | // return (int)(osMutexDelete(sobj) == osOK); 111 | } 112 | 113 | 114 | /*------------------------------------------------------------------------*/ 115 | /* Request Grant to Access the Volume */ 116 | /*------------------------------------------------------------------------*/ 117 | /* This function is called on entering file functions to lock the volume. 118 | / When a 0 is returned, the file function fails with FR_TIMEOUT. 119 | */ 120 | 121 | int ff_req_grant ( /* 1:Got a grant to access the volume, 0:Could not get a grant */ 122 | FF_SYNC_t sobj /* Sync object to wait */ 123 | ) 124 | { 125 | /* Win32 */ 126 | return (int)(WaitForSingleObject(sobj, FF_FS_TIMEOUT) == WAIT_OBJECT_0); 127 | 128 | /* uITRON */ 129 | // return (int)(wai_sem(sobj) == E_OK); 130 | 131 | /* uC/OS-II */ 132 | // OS_ERR err; 133 | // OSMutexPend(sobj, FF_FS_TIMEOUT, &err)); 134 | // return (int)(err == OS_NO_ERR); 135 | 136 | /* FreeRTOS */ 137 | // return (int)(xSemaphoreTake(sobj, FF_FS_TIMEOUT) == pdTRUE); 138 | 139 | /* CMSIS-RTOS */ 140 | // return (int)(osMutexWait(sobj, FF_FS_TIMEOUT) == osOK); 141 | } 142 | 143 | 144 | /*------------------------------------------------------------------------*/ 145 | /* Release Grant to Access the Volume */ 146 | /*------------------------------------------------------------------------*/ 147 | /* This function is called on leaving file functions to unlock the volume. 148 | */ 149 | 150 | void ff_rel_grant ( 151 | FF_SYNC_t sobj /* Sync object to be signaled */ 152 | ) 153 | { 154 | /* Win32 */ 155 | ReleaseMutex(sobj); 156 | 157 | /* uITRON */ 158 | // sig_sem(sobj); 159 | 160 | /* uC/OS-II */ 161 | // OSMutexPost(sobj); 162 | 163 | /* FreeRTOS */ 164 | // xSemaphoreGive(sobj); 165 | 166 | /* CMSIS-RTOS */ 167 | // osMutexRelease(sobj); 168 | } 169 | 170 | #endif 171 | 172 | -------------------------------------------------------------------------------- /src/py/_rpimodule.c: -------------------------------------------------------------------------------- 1 | 2 | #include "Python.h" 3 | #include "pi/bcmmailbox.h" 4 | 5 | /* 6 | Expose the RPi peripherals map to Python 7 | */ 8 | 9 | 10 | static PyObject * 11 | _rpi_peek(PyObject *self, PyObject *args) 12 | { 13 | unsigned long address; 14 | unsigned long value; 15 | 16 | if (!PyArg_ParseTuple(args, "k", &address)) 17 | return NULL; 18 | 19 | if ((address & 3) !=0) { 20 | PyErr_SetString(PyExc_ValueError, "address must be word-aligned"); 21 | return NULL; 22 | } 23 | 24 | DataMemBarrier(); 25 | value = *((unsigned long *)address); 26 | DataMemBarrier(); 27 | 28 | return PyLong_FromLong(value); 29 | } 30 | 31 | static PyObject * 32 | _rpi_poke(PyObject *self, PyObject *args) 33 | { 34 | unsigned long address; 35 | unsigned long value; 36 | 37 | if (!PyArg_ParseTuple(args, "kk", &address, &value)) 38 | return NULL; 39 | 40 | if ((address & 3) !=0) { 41 | PyErr_SetString(PyExc_ValueError, "address must be word-aligned"); 42 | return NULL; 43 | } 44 | 45 | DataMemBarrier(); 46 | *((long *)address) = value; 47 | DataMemBarrier(); 48 | 49 | Py_RETURN_NONE; 50 | } 51 | 52 | 53 | 54 | static PyObject * 55 | _rpi_get_property(PyObject *self, PyObject *args) 56 | { 57 | PyObject *reply = NULL; 58 | int tagid, requestsize, responsesize; 59 | char *buffer; 60 | 61 | if (!PyArg_ParseTuple(args, "ii", &tagid, &requestsize)) { 62 | return NULL; 63 | } 64 | 65 | buffer = malloc(requestsize); 66 | if (!buffer) return PyErr_NoMemory(); 67 | 68 | responsesize = PiPyOS_bcm_get_property_tag(tagid, buffer, requestsize); 69 | 70 | if (responsesize<0) { 71 | free(buffer); 72 | PyErr_SetString(PyExc_IOError, "failed to get property from VC"); 73 | return NULL; 74 | } 75 | 76 | reply = PyBytes_FromStringAndSize(buffer, responsesize); 77 | 78 | // The following works in both cases: error or no error 79 | Py_XINCREF(reply); 80 | free(buffer); 81 | return reply; 82 | } 83 | 84 | static PyObject * 85 | _rpi_writereadmailbox(PyObject *self, PyObject *args) 86 | { 87 | PyObject *reply = NULL; 88 | int channel; 89 | const char *data; 90 | char *buffer; 91 | char *buffer_aligned; 92 | int size; 93 | if (!PyArg_ParseTuple(args, "iy#", &channel, &data, &size)) { 94 | return NULL; 95 | } 96 | 97 | if (size & 0x3) { 98 | PyErr_SetString(PyExc_ValueError, "Data should be multiple of 4 bytes"); 99 | return NULL; 100 | } 101 | 102 | if (channel<0 || channel>15) { 103 | PyErr_SetString(PyExc_ValueError, "Channel should be 0<=channel<15"); 104 | return NULL; 105 | } 106 | 107 | // get 16-byte aligned buffer 108 | buffer = malloc(size + 15); 109 | if (!buffer) return PyErr_NoMemory(); 110 | 111 | buffer_aligned = (void*)((((unsigned int)buffer)+15) & ~0xf); 112 | memcpy(buffer_aligned, data, size); 113 | 114 | PiPyOS_bcm_mailbox_write_read(channel, buffer_aligned); 115 | 116 | reply = PyBytes_FromStringAndSize(buffer_aligned, size); 117 | 118 | // The following works in both cases: error or no error 119 | Py_XINCREF(reply); 120 | free(buffer); 121 | return reply; 122 | 123 | 124 | } 125 | 126 | extern void PiPyOS_bcm_framebuffer_putstring(char*, int); 127 | 128 | static PyObject * 129 | _rpi_fbwrite(PyObject *self, PyObject *args) { 130 | char *data; 131 | int size; 132 | if (!PyArg_ParseTuple(args, "y#", &data, &size)) { 133 | return NULL; 134 | } 135 | PiPyOS_bcm_framebuffer_putstring(data, size); 136 | 137 | Py_RETURN_NONE; 138 | } 139 | 140 | 141 | static PyObject * 142 | _rpi_createbuffer(PyObject *self, PyObject *args) { 143 | unsigned int size, alignment; 144 | unsigned int data; 145 | PyObject *memview; 146 | if (!PyArg_ParseTuple(args, "II", &size, &alignment)) { 147 | return NULL; 148 | } 149 | 150 | data = (unsigned int )malloc(size+(alignment - 1)); 151 | data = data + (alignment - 1) - ((data+(alignment-1)) % alignment); 152 | 153 | memview = PyMemoryView_FromMemory((char *) data, size, PyBUF_WRITE); 154 | if (!memview) return NULL; 155 | 156 | return Py_BuildValue("OI", memview, data); 157 | 158 | } 159 | 160 | static PyObject * 161 | _rpi_flushcache(PyObject *self, PyObject *args){ 162 | 163 | int cr = 0; 164 | __asm volatile ("mcr p15, 0, %0, c7, c14, 0" :: "r" (cr)); 165 | 166 | Py_RETURN_NONE; 167 | } 168 | 169 | 170 | 171 | 172 | static PyMethodDef _RpiMethods[] = { 173 | {"peek", _rpi_peek, METH_VARARGS, "Read a memory address."}, 174 | {"poke", _rpi_poke, METH_VARARGS, "Write a memory address."}, 175 | {"writereadmailbox", _rpi_writereadmailbox, METH_VARARGS, "Write to mailbox and read reply."}, 176 | {"getproperty", _rpi_get_property, METH_VARARGS, "Get VideoCore property."}, 177 | {"fb_write", _rpi_fbwrite, METH_VARARGS, "Write bytes to the framebuffer"}, 178 | {"createbuffer", _rpi_createbuffer, METH_VARARGS, "Get an aligned buffer"}, 179 | {"flushcache", _rpi_flushcache, METH_NOARGS, "Flush the processor data cache"}, 180 | 181 | {NULL, NULL, 0, NULL} /* Sentinel */ 182 | }; 183 | 184 | static struct PyModuleDef _rpimodule = { 185 | PyModuleDef_HEAD_INIT, 186 | "_rpi", /* name of module */ 187 | NULL, /* module documentation, may be NULL */ 188 | -1, /* size of per-interpreter state of the module, 189 | or -1 if the module keeps state in global variables. */ 190 | _RpiMethods 191 | }; 192 | 193 | 194 | PyMODINIT_FUNC 195 | PyInit__rpi(void) { 196 | 197 | PyObject *module = NULL; 198 | 199 | module = PyModule_Create(&_rpimodule); 200 | if (!module) goto error; 201 | 202 | return module; 203 | 204 | error: 205 | Py_XDECREF(module); 206 | return NULL; 207 | } 208 | -------------------------------------------------------------------------------- /src/pi/spi_lld.h: -------------------------------------------------------------------------------- 1 | /* 2 | ChibiOS/RT - Copyright (C) 2006,2007,2008,2009,2010, 3 | 2011,2012 Giovanni Di Sirio. 4 | 5 | This file is part of ChibiOS/RT. 6 | 7 | ChibiOS/RT is free software; you can redistribute it and/or modify 8 | it under the terms of the GNU General Public License as published by 9 | the Free Software Foundation; either version 3 of the License, or 10 | (at your option) any later version. 11 | 12 | ChibiOS/RT is distributed in the hope that it will be useful, 13 | but WITHOUT ANY WARRANTY; without even the implied warranty of 14 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 15 | GNU General Public License for more details. 16 | 17 | You should have received a copy of the GNU General Public License 18 | along with this program. If not, see . 19 | */ 20 | 21 | /** 22 | * @file templates/spi_lld.h 23 | * @brief SPI Driver subsystem low level driver header template. 24 | * 25 | * @addtogroup SPI 26 | * @{ 27 | */ 28 | 29 | #ifndef _SPI_LLD_H_ 30 | #define _SPI_LLD_H_ 31 | 32 | #if HAL_USE_SPI || defined(__DOXYGEN__) 33 | 34 | /*===========================================================================*/ 35 | /* Driver constants. */ 36 | /*===========================================================================*/ 37 | 38 | /*===========================================================================*/ 39 | /* Driver pre-compile time settings. */ 40 | /*===========================================================================*/ 41 | 42 | /*===========================================================================*/ 43 | /* Derived constants and error checks. */ 44 | /*===========================================================================*/ 45 | 46 | /*===========================================================================*/ 47 | /* Driver data structures and types. */ 48 | /*===========================================================================*/ 49 | 50 | /** 51 | * @brief Type of a structure representing an SPI driver. 52 | */ 53 | typedef struct SPIDriver SPIDriver; 54 | 55 | /** 56 | * @brief SPI notification callback type. 57 | * 58 | * @param[in] spip pointer to the @p SPIDriver object triggering the 59 | * callback 60 | */ 61 | typedef void (*spicallback_t)(SPIDriver *spip); 62 | 63 | /** 64 | * @brief Driver configuration structure. 65 | * @note Implementations may extend this structure to contain more, 66 | * architecture dependent, fields. 67 | */ 68 | typedef struct { 69 | /** 70 | * @brief Operation complete callback. 71 | */ 72 | spicallback_t end_cb; 73 | /* End of the mandatory fields.*/ 74 | 75 | /* @brief 00=Chip select 0, 01=Chip select 1 */ 76 | uint8_t chip_select; 77 | uint8_t clock_polarity; 78 | uint8_t clock_phase; 79 | uint32_t clock_frequency; 80 | 81 | } SPIConfig; 82 | 83 | /** 84 | * @brief Structure representing an SPI driver. 85 | * @note Implementations may extend this structure to contain more, 86 | * architecture dependent, fields. 87 | */ 88 | struct SPIDriver { 89 | /** 90 | * @brief Driver state. 91 | */ 92 | spistate_t state; 93 | /** 94 | * @brief Current configuration data. 95 | */ 96 | const SPIConfig *config; 97 | #if SPI_USE_WAIT || defined(__DOXYGEN__) 98 | /** 99 | * @brief Waiting thread. 100 | */ 101 | Thread *thread; 102 | #endif /* SPI_USE_WAIT */ 103 | #if SPI_USE_MUTUAL_EXCLUSION || defined(__DOXYGEN__) 104 | #if CH_USE_MUTEXES || defined(__DOXYGEN__) 105 | /** 106 | * @brief Mutex protecting the bus. 107 | */ 108 | Mutex mutex; 109 | #elif CH_USE_SEMAPHORES 110 | Semaphore semaphore; 111 | #endif 112 | 113 | /** 114 | * @brief Receive buffer 115 | */ 116 | void *rxbuf; 117 | 118 | /** 119 | * @brief Transmit buffer 120 | */ 121 | const void *txbuf; 122 | 123 | /** 124 | * @brief Pending transfer count 125 | */ 126 | size_t rxcnt; 127 | 128 | #endif /* SPI_USE_MUTUAL_EXCLUSION */ 129 | #if defined(SPI_DRIVER_EXT_FIELDS) 130 | SPI_DRIVER_EXT_FIELDS 131 | #endif 132 | /* End of the mandatory fields.*/ 133 | 134 | }; 135 | 136 | /*===========================================================================*/ 137 | /* Driver macros. */ 138 | /*===========================================================================*/ 139 | 140 | /*===========================================================================*/ 141 | /* External declarations. */ 142 | /*===========================================================================*/ 143 | 144 | #ifdef __cplusplus 145 | extern "C" { 146 | #endif 147 | extern SPIDriver SPI0; 148 | 149 | void spi_lld_init(void); 150 | void spi_lld_start(SPIDriver *spip); 151 | void spi_lld_stop(SPIDriver *spip); 152 | void spi_lld_select(SPIDriver *spip); 153 | void spi_lld_unselect(SPIDriver *spip); 154 | void spi_lld_ignore(SPIDriver *spip, size_t n); 155 | void spi_lld_exchange(SPIDriver *spip, size_t n, 156 | const void *txbuf, void *rxbuf); 157 | void spi_lld_send(SPIDriver *spip, size_t n, const void *txbuf); 158 | void spi_lld_receive(SPIDriver *spip, size_t n, void *rxbuf); 159 | uint16_t spi_lld_polled_exchange(SPIDriver *spip, uint16_t frame); 160 | 161 | void spi_lld_get_dma_channels(void *rx, void *tx); 162 | #ifdef __cplusplus 163 | } 164 | #endif 165 | 166 | #endif /* HAL_USE_SPI */ 167 | 168 | #endif /* _SPI_LLD_H_ */ 169 | 170 | /** @} */ 171 | -------------------------------------------------------------------------------- /src/os/initfs.c: -------------------------------------------------------------------------------- 1 | #include "dirent_os.h" 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include "initfs.h" 8 | 9 | typedef struct { 10 | unsigned int name_offs; 11 | unsigned int data_offs; 12 | unsigned int size; 13 | 14 | } initfs_rec_t; 15 | 16 | extern char _binary_initfs_bin_start; 17 | 18 | int PiPyOS_initfs_open(initfs_openfile_t *file, const char *pathname, int flags) { 19 | initfs_rec_t *r = (initfs_rec_t *)&_binary_initfs_bin_start; 20 | char *s = &_binary_initfs_bin_start; 21 | 22 | for(int i=0;r[i].data_offs;i++) { 23 | if (strcmp(&s[r[i].name_offs], pathname)==0) { 24 | if (r[i].size==0xffffffff) { 25 | return -1; // Trying to open a directory 26 | } else { 27 | file->data = &s[r[i].data_offs]; 28 | file->pos = 0; 29 | file->size = r[i].size; 30 | return 0; 31 | } 32 | 33 | } 34 | } 35 | 36 | errno = ENOENT; 37 | return -1; 38 | 39 | } 40 | 41 | int PiPyOS_initfs_read(initfs_openfile_t *file, void *buf, size_t count) { 42 | int n = file->size - file->pos; 43 | 44 | if (n>((int)count)) n = count; 45 | 46 | memcpy(buf, file->data + file->pos, n); 47 | file->pos += n; 48 | 49 | return n; 50 | } 51 | 52 | 53 | int PiPyOS_initfs_opendir(const char *pathname, DIR *dir) { 54 | initfs_rec_t *r = (initfs_rec_t *)&_binary_initfs_bin_start; 55 | char *s = &_binary_initfs_bin_start; 56 | 57 | int length; 58 | 59 | // strip trailing slashes 60 | length = strlen(pathname); 61 | while(length && pathname[length-1] == '/') length--; 62 | 63 | // find the directory 64 | for(int i=0; r[i].data_offs; i++) { 65 | if (strncmp(&s[r[i].name_offs], pathname, length)==0) { 66 | if (r[i].size==0xffffffff) { 67 | dir->initfs.idx_parent = i; 68 | dir->initfs.idx_cur = i+1; 69 | return 0; 70 | } 71 | } 72 | } 73 | errno = ENOENT; 74 | return -1; 75 | 76 | } 77 | 78 | /* Find the next item in the directory listing 79 | * 80 | * Returns 0 on succes, 1 on end-of-directory 81 | * On failure, -1 is returned and errno is set appropiately 82 | */ 83 | 84 | int PiPyOS_initfs_readdir(DIR *dirp) { 85 | initfs_rec_t *r = (initfs_rec_t *)&_binary_initfs_bin_start; 86 | char *s = &_binary_initfs_bin_start; 87 | char *parent_name = &s[r[dirp->initfs.idx_parent].name_offs]; 88 | 89 | int l = strlen(parent_name); 90 | 91 | // Loop over all remaining directory entries 92 | for (; r[dirp->initfs.idx_cur].data_offs; dirp->initfs.idx_cur++) { 93 | 94 | char *current_name = &s[r[dirp->initfs.idx_cur].name_offs]; 95 | 96 | // if this dir or file is not a subdir of the parent, we are done 97 | if (strncmp(current_name, parent_name, l)!=0) { 98 | break; 99 | } 100 | 101 | char *subpath = current_name + l; // the part below the parent 102 | if (*subpath=='/') { // should always be true, but check to be sure 103 | subpath++; // strip leading / 104 | if (!strchr(subpath, '/')) { 105 | // No / in subpath, so it is a direct child (no file in a sub-dir) 106 | 107 | l = strlen(subpath); 108 | if (l >= NAME_MAX) { 109 | errno = ENAMETOOLONG; 110 | return -1; //filename too long 111 | } 112 | 113 | // Copy info of the current listing into dirp->dirent 114 | memcpy(dirp->dirent.d_name, subpath, l+1); 115 | dirp->dirent.d_ino = dirp->initfs.idx_cur; 116 | dirp->initfs.idx_cur++; 117 | return 0; 118 | 119 | } 120 | } 121 | 122 | } 123 | 124 | return 1; 125 | } 126 | 127 | 128 | int PiPyOS_initfs_stat(const char *pathname, struct stat *buf) { 129 | 130 | initfs_rec_t *r = (initfs_rec_t *)&_binary_initfs_bin_start; 131 | char *s = &_binary_initfs_bin_start; 132 | int i=0; 133 | 134 | while(r[i].data_offs) { 135 | if (strcmp(&s[r[i].name_offs], pathname)==0) { 136 | if (r[i].size==0xffffffff) { 137 | buf->st_size = 0; 138 | buf->st_blocks = 0; 139 | buf->st_mode = S_IFDIR | S_IRUSR | S_IXUSR; 140 | goto found; 141 | } else { 142 | buf->st_size = r[i].size; 143 | buf->st_blocks = (r[i].size+511)/512; 144 | buf->st_mode = S_IFREG | S_IRUSR; 145 | goto found; 146 | } 147 | 148 | } 149 | i++; 150 | } 151 | errno = ENOENT; 152 | return -1; 153 | found: 154 | 155 | buf->st_dev = 0; 156 | buf->st_ino = i; 157 | 158 | buf->st_nlink = 1; 159 | buf->st_uid = 0; 160 | buf->st_gid = 0; 161 | buf->st_rdev = 0; 162 | buf->st_atime = 0; 163 | buf->st_mtime = 0; 164 | buf->st_ctime = 0; 165 | buf->st_blksize = 512; 166 | 167 | 168 | return 0; 169 | } 170 | 171 | int PiPyOS_initfs_lseek(initfs_openfile_t *file, int offset, int whence) { 172 | int ret = 0; 173 | int base; 174 | 175 | switch (whence) { 176 | case SEEK_SET: 177 | base = 0; 178 | break; 179 | case SEEK_CUR: 180 | base = file->pos; 181 | break; 182 | case SEEK_END: 183 | base = file->size; 184 | break; 185 | default: 186 | errno = EINVAL; 187 | ret = -1; 188 | } 189 | 190 | if (ret == 0) { // no error so far 191 | offset = offset + base; 192 | if ((offset >= 0) && (offset < file->size)) { 193 | file->pos = offset; 194 | ret = offset; 195 | } else { 196 | errno = EINVAL; 197 | ret = -1; 198 | } 199 | } 200 | 201 | return ret; 202 | } 203 | -------------------------------------------------------------------------------- /src/pi/hal_lld.c: -------------------------------------------------------------------------------- 1 | /* 2 | ChibiOS/RT - Copyright (C) 2006,2007,2008,2009,2010, 3 | 2011,2012 Giovanni Di Sirio. 4 | 5 | This file is part of ChibiOS/RT. 6 | 7 | ChibiOS/RT is free software; you can redistribute it and/or modify 8 | it under the terms of the GNU General Public License as published by 9 | the Free Software Foundation; either version 3 of the License, or 10 | (at your option) any later version. 11 | 12 | ChibiOS/RT is distributed in the hope that it will be useful, 13 | but WITHOUT ANY WARRANTY; without even the implied warranty of 14 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 15 | GNU General Public License for more details. 16 | 17 | You should have received a copy of the GNU General Public License 18 | along with this program. If not, see . 19 | */ 20 | 21 | /** 22 | * @file templates/hal_lld.c 23 | * @brief HAL Driver subsystem low level driver source template. 24 | * 25 | * @addtogroup HAL 26 | * @{ 27 | */ 28 | 29 | #include "ch.h" 30 | #include "hal.h" 31 | 32 | /*===========================================================================*/ 33 | /* Driver local definitions. */ 34 | /*===========================================================================*/ 35 | 36 | 37 | /*===========================================================================*/ 38 | /* Driver exported variables. */ 39 | /*===========================================================================*/ 40 | 41 | /*===========================================================================*/ 42 | /* Driver local variables. */ 43 | /*===========================================================================*/ 44 | 45 | #define NUM_INTERRUPTS 72 // 64 GPU interrupts + 8 BASIC IRQs 46 | static void (*interrupt_handler[NUM_INTERRUPTS]) (void *); 47 | static void *interrupt_handler_closure[NUM_INTERRUPTS]; 48 | 49 | 50 | 51 | /*===========================================================================*/ 52 | /* Driver local functions. */ 53 | /*===========================================================================*/ 54 | 55 | 56 | // Use ARM timer 57 | static void systimer_serve_interrupt( void * dummy ) 58 | { 59 | // Update the system time 60 | chSysLockFromIsr(); 61 | chSysTimerHandlerI(); 62 | chSysUnlockFromIsr(); 63 | 64 | app_systick(); 65 | 66 | ARM_TIMER_CLI = 0; 67 | 68 | } 69 | 70 | static void systimer_init( void ) 71 | { 72 | // Configure 1MHz clock with 1kHz reload cycle 73 | ARM_TIMER_CTL = 0x003E0000; 74 | ARM_TIMER_LOD = 1000-1; 75 | ARM_TIMER_RLD = 1000-1; 76 | ARM_TIMER_DIV = 0x000000F9; //divide by 250 77 | ARM_TIMER_CLI = 0; 78 | ARM_TIMER_CTL = 0x003E00A2; 79 | 80 | 81 | IRQ_ENABLE_BASIC = (1<<0); 82 | hal_register_interrupt(64, systimer_serve_interrupt, NULL); 83 | } 84 | 85 | 86 | 87 | /*===========================================================================*/ 88 | /* Driver interrupt handlers. */ 89 | /*===========================================================================*/ 90 | 91 | /** 92 | * @brief Interrupt handler 93 | * 94 | */ 95 | 96 | CH_IRQ_HANDLER(IrqHandler) 97 | { 98 | CH_IRQ_PROLOGUE(); 99 | asm volatile ("stmfd sp!, {r4-r11}" : : : "memory"); // These are not saved by the IRQ PROLOGUE 100 | 101 | uint64_t pending; 102 | uint32_t basic; 103 | do { 104 | pending = IRQ_PEND1 | ((uint64_t) IRQ_PEND2) << 32; // check GPU interrupts 105 | 106 | if (pending) { 107 | 108 | for (int i = 63; i>=0; i--, pending<<=1) { 109 | if (pending & (1LL<<63)) { 110 | interrupt_handler[i](interrupt_handler_closure[i]); 111 | break; 112 | } 113 | } 114 | continue; // check for more interrupts in IRQ_PEND1 or IRQ_PEND2 115 | } 116 | 117 | basic = IRQ_BASIC & 0xff; 118 | if (basic) { 119 | for (int i = 7; i>=0; i--, basic<<=1) { 120 | if (basic & (1<<7)) { 121 | interrupt_handler[i+64](interrupt_handler_closure[i+64]); 122 | break; 123 | } 124 | } 125 | continue; // check for more interrupts in IRQ_PEND1 or IRQ_PEND2 126 | } 127 | 128 | break; // No GPU and no BASIC interrupts; we are done 129 | 130 | 131 | } while (1); 132 | 133 | asm volatile ("ldmfd sp!, {r4-r11}" : : : "memory"); // These are not saved by the IRQ PROLOGUE 134 | 135 | CH_IRQ_EPILOGUE(); 136 | } 137 | 138 | /*===========================================================================*/ 139 | /* Driver exported functions. */ 140 | /*===========================================================================*/ 141 | 142 | /** 143 | * @brief Synchronize function for short delays. 144 | * 145 | */ 146 | void delayMicroseconds(uint32_t n) 147 | { 148 | uint32_t compare = SYSTIMER_CLO + n; 149 | while (SYSTIMER_CLO < compare); 150 | } 151 | 152 | static void unused_interrupt(int interrupt) { 153 | // TODO: log / panic? 154 | PiPyOS_bcm_framebuffer_putstring("FATAL: an unused interrupt was triggered", -1); 155 | for(;;); 156 | } 157 | 158 | /** 159 | * @brief Low level HAL driver initialization. 160 | * 161 | * @notapi 162 | */ 163 | void hal_lld_init(void) { 164 | for(int i=0;i 8 | #include 9 | #include 10 | #include 11 | #include "pi/bcmmailbox.h" 12 | #include "pi/bcmframebuffer.h" 13 | 14 | #include "os/os.h" 15 | #include "ff.h" 16 | #include "bcm2835.h" 17 | 18 | 19 | 20 | static WORKING_AREA(waThread1, 1024); 21 | static msg_t Thread1(void *p) { 22 | (void)p; 23 | chRegSetThreadName("blinker"); 24 | while (TRUE) { 25 | palClearPad(GPIO47_PORT, GPIO47_PAD); 26 | chThdSleepMilliseconds(100); 27 | palSetPad(GPIO47_PORT, GPIO47_PAD); 28 | chThdSleepMilliseconds(900); 29 | } 30 | return 0; 31 | } 32 | 33 | 34 | 35 | int Py_Main(int argc, wchar_t **argv); 36 | void PiPyOS_initreadline(void); 37 | void Py_SetPath(const wchar_t *); 38 | 39 | 40 | static inline void dmb(void) { 41 | __asm__ __volatile__ ("mcr p15, 0, %0, c7, c10, 5" : : "r" (0) : "memory"); 42 | } 43 | 44 | 45 | 46 | void initcache(void) 47 | { 48 | /* Set up page tables so that data caches work. */ 49 | static volatile __attribute__ ((aligned(0x4000))) unsigned PageTable[4096]; 50 | 51 | unsigned base; 52 | for (base = 0; base < 512; base++) 53 | { 54 | // outer and inner write back, write allocate, shareable 55 | PageTable[base] = (base << 20) | 0x1140E; 56 | } 57 | for (; base < 4096; base++) 58 | { 59 | // shared device, never execute 60 | PageTable[base] = (base << 20) | 0x10416; 61 | } 62 | 63 | // restrict cache size to 16K (no page coloring) 64 | unsigned auxctrl; 65 | asm volatile ("mrc p15, 0, %0, c1, c0, 1" : "=r" (auxctrl)); 66 | auxctrl |= 1 << 6; 67 | asm volatile ("mcr p15, 0, %0, c1, c0, 1" ::"r" (auxctrl)); 68 | 69 | // set domain 0 to client (use 3 for Manager) 70 | // asm volatile ("mcr p15, 0, %0, c3, c0, 0" ::"r" (3)); 71 | asm volatile ("mcr p15, 0, %0, c3, c0, 0" ::"r" (1)); 72 | 73 | // always use TTBR0 74 | asm volatile ("mcr p15, 0, %0, c2, c0, 2" ::"r" (0)); 75 | 76 | // set TTBR0 (page table walk inner cacheable, outer non-cacheable, shareable memory) 77 | asm volatile ("mcr p15, 0, %0, c2, c0, 0" ::"r" (3 | (unsigned) &PageTable));//Use this to isolate L2 cache when using GPU. 78 | 79 | // invalidate data cache and flush prefetch buffer 80 | asm volatile ("mcr p15, 0, %0, c7, c5, 4" ::"r" (0) : "memory"); 81 | asm volatile ("mcr p15, 0, %0, c7, c6, 0" ::"r" (0) : "memory"); 82 | // invalidate L2 instruction cache 83 | // asm volatile ("mcr p15, 1, %0, c7, c5, 0" ::"r" (0) : "memory"); 84 | 85 | // enable MMU, L1 cache and instruction cache, L2 cache, write buffer, 86 | // branch prediction and extended page table on 87 | unsigned mode; 88 | asm volatile ("mrc p15,0,%0,c1,c0,0" : "=r" (mode)); 89 | mode |= 0x0005187D; //This gives 4 ns loop times. 90 | //vector processors enabled// 91 | asm volatile ("mcr p15,0,%0,c1,c0,0" ::"r" (mode) : "memory"); 92 | asm volatile ("mrc p15,0,%0,c1,c0,2" : "=r" (mode));//Coprocessor control 93 | mode |= 0x00F00000; 94 | asm volatile ("mcr p15,0,%0,c1,c0,2" :: "r" (mode));//Full access to VFP processors. 95 | 96 | /* 97 | asm volatile ("vmrs %0,FPEXC":"=r" (mode));//Get current status 98 | mode |= 0x40000000; 99 | asm volatile ("vmsr FPEXC,%0"::"r" (mode));//Enable VFP coprocessors. 100 | 101 | asm volatile ("vmrs %0,FPSCR":"=r" (mode));//Get VFP current status register. 102 | mode |= (BIT(9)|BIT(24)|BIT(25)); 103 | asm volatile ("vmsr FPSCR,%0"::"r" (mode));//Enable divide by zero exceptions. 104 | */ 105 | } 106 | 107 | 108 | void jtag_init(void) { 109 | for (int pin = 22; pin<=27;pin++) { 110 | if (pin != 25) bcm2835_gpio_fnsel(pin, GPFN_ALT4); 111 | } 112 | bcm2835_gpio_fnsel(13, GPFN_ALT5); 113 | 114 | } 115 | 116 | void PiPyOS_panic(void) { 117 | PiPyOS_bcm_framebuffer_putstring("\nPANIC:", -1); 118 | PiPyOS_bcm_framebuffer_putstring(dbg_panic_msg, -1); 119 | } 120 | 121 | /* 122 | * Application entry point. 123 | */ 124 | extern const char *Py_FileSystemDefaultEncoding; 125 | 126 | int main(void) { 127 | const SerialConfig serialConfig ={1000000}; 128 | const SDCConfig sdccfg = { 0 }; 129 | char cmdline[1025]; 130 | 131 | 132 | AUX_MU_CNTL_REG = 0; // disable uart RX during setup of HAL. This prevents a random char to appear in the input buffer 133 | 134 | PiPyOS_bcm_framebuffer_init(0, 0); 135 | PiPyOS_bcm_framebuffer_putstring("init\n", -1); 136 | 137 | halInit(); 138 | 139 | jtag_init(); 140 | 141 | /* wait for debugger 142 | int i = 1; 143 | while(i) { 144 | 145 | }*/ 146 | 147 | /* 148 | * Set mode of onboard LED 149 | */ 150 | palSetPadMode(GPIO47_PORT, GPIO47_PAD, PAL_MODE_OUTPUT); 151 | 152 | chSysInit(); 153 | 154 | 155 | app_init(); 156 | 157 | 158 | 159 | /* 160 | * Serial port initialization. 161 | */ 162 | 163 | sdStart(&SD1, &serialConfig); 164 | 165 | chprintf((BaseSequentialStream *)&SD1, "Main (SD1 started)\r\n"); 166 | os_init_stdio(); 167 | 168 | 169 | initcache(); 170 | 171 | int cmdline_length = PiPyOS_bcm_get_property_tag(0x50001, cmdline, sizeof(cmdline)-1); 172 | if (cmdline_length <0) { 173 | *cmdline = '\0'; 174 | } else { 175 | cmdline[cmdline_length] = '\0'; // Add trailing null 176 | } 177 | 178 | chprintf((BaseSequentialStream *)&SD1, "cmdline='%s'\r\n", cmdline); 179 | 180 | 181 | sdcStart(&SDCD1, &sdccfg); 182 | 183 | 184 | /* 185 | * Creates the blinker thread. 186 | */ 187 | chThdCreateStatic(waThread1, sizeof(waThread1), NORMALPRIO+10, Thread1, NULL); 188 | 189 | /* Start Python */ 190 | wchar_t *argv[] = { L"python", L"-S", L"-B", L"-i", L"/sd/autoexec.py" }; 191 | 192 | setenv("PYTHONHASHSEED", "0", 1); // No random numbers available 193 | setenv("HOME", "/", 1); // prevent import of pwdmodule in posixpath.expanduser 194 | 195 | Py_FileSystemDefaultEncoding = "latin-1"; 196 | Py_SetPath(L"/boot:/boot/app:/sd/python36z.zip"); 197 | 198 | printf("GOGOGO!\n"); 199 | 200 | FATFS fs; 201 | f_mount(&fs, "", 0); 202 | 203 | 204 | PiPyOS_initreadline(); 205 | 206 | Py_Main(3, argv); 207 | 208 | 209 | for(;;); 210 | 211 | 212 | return 0; 213 | } 214 | -------------------------------------------------------------------------------- /src/pi/bcm2835_dma.c: -------------------------------------------------------------------------------- 1 | #include "bcm2835.h" 2 | #include "bcm2835_dma.h" 3 | 4 | 5 | static unsigned int dma_channels_alloced = 0; //Bitmask of dma channels in use 6 | 7 | /* Allocate a DMA channel 8 | * 9 | * lite: if != 0, signal that this may be a lite channel 10 | * TODO: use the lite flag. Currently only returns full channels 11 | * 12 | * returns: 0 if failure (no channel available); channel if succes 13 | * 14 | * Thread-safety: this function is not thread-safe 15 | */ 16 | bcm2835_dma_channel_t bcm2835_dma_alloc(unsigned int lite) { 17 | for (int i = 1, mask = 2; i<=7; i++, mask<<=1) { 18 | if ((dma_channels_alloced & mask) == 0) { 19 | dma_channels_alloced |= mask; // mark channel in use 20 | BCM2835_DMA_ENABLE |= mask; // enable channel 21 | return i; 22 | } 23 | } 24 | 25 | return 0; // No free channel 26 | } 27 | 28 | 29 | /* Fill a conblk 30 | * 31 | * 32 | * destination, source: 33 | * address in ARM memory or ARM I/O space. If given in I/O space (0x20xx_xxxx), 34 | * this is remapped to 0x7Exx_xxxx (the address in VC memory space as used by 35 | * the DMA controller. If given in memory space (other cases), this is remapped 36 | * to 0x4xxx_xxxx (L2 cached) 37 | * 38 | * This method defines the ti (transfer information) field according to the 39 | * following rules: 40 | * 41 | * if destination / source is NULL; data is not written resp. read 42 | * 43 | * if destination / source is in I/O space, the address is not increased 44 | * for each transfer; if it is in memory it is increased. Additionally, 45 | * if permap != 0, DREQ is used to gate writes resp. reads 46 | * 47 | * if destination / source is in memory, 128-bit destination resp. source 48 | * transfer width is used; 32 bits otherwise 49 | * 50 | * if destination is I/O, WAIT_RESP is set 51 | * 52 | * permap: peripheral DREQ that gates writes / reads 53 | */ 54 | 55 | void bcm2835_dma_fill_conblk(bcm2835_dma_conblk *conblk, 56 | volatile void *destination, volatile const void *source, unsigned long length, 57 | unsigned long permap) { 58 | 59 | unsigned long ti = 0; 60 | 61 | if (!destination) { 62 | ti |= BCM2835_DMA_TI_DEST_IGNORE; 63 | } else if (((uint32_t)destination & 0xFF000000) == 0x20000000) { 64 | // To I/O 65 | if (permap != 0) ti |= BCM2835_DMA_TI_DEST_DREQ | BCM2835_DMA_TI_WAIT_RESP; 66 | destination = (void*) ((uint32_t) destination | 0x7E000000); 67 | } else { 68 | // To memory 69 | ti |= BCM2835_DMA_TI_DEST_INC | BCM2835_DMA_TI_DEST_WIDTH; 70 | destination = (void*) ((uint32_t) destination | 0x40000000); 71 | } 72 | 73 | if (!source) { 74 | ti |= BCM2835_DMA_TI_SRC_IGNORE; 75 | } else if (((uint32_t)source & 0xFF000000) == 0x20000000) { 76 | // To I/O 77 | if (permap != 0) ti |= BCM2835_DMA_TI_SRC_DREQ; 78 | source = (void*) ((uint32_t) source | 0x7E000000); 79 | } else { 80 | // To memory 81 | ti |= BCM2835_DMA_TI_SRC_INC | BCM2835_DMA_TI_SRC_WIDTH; 82 | source = (void*) ((uint32_t) source | 0x40000000); 83 | } 84 | 85 | 86 | ti |= BCM2835_DMA_TI_PERMAP(permap); 87 | 88 | conblk->ti = ti; 89 | conblk->source_ad = (uint32_t) source; 90 | conblk->dest_ad = (uint32_t) destination; 91 | conblk->txfr_len = length; 92 | conblk->stride = 0; 93 | conblk->nextconblk = 0; 94 | conblk->reserved[0] = 0; 95 | conblk->reserved[1] = 0; 96 | 97 | } 98 | 99 | /* Fill a conblk for a 2D-mode transfer 100 | * 101 | * conblk, destination, source, permap: see bcm2835_dma_fill_conblk 102 | * ylength: how many xlength-transfers are transferred 103 | * xlength: the length of one x-transfer, in bytes 104 | * destination_stride: offset to add to the destination address after each x-transfer 105 | * source_stride: offset to add to the source address after each x-transfer 106 | */ 107 | void bcm2835_dma_fill_conblk_2d(bcm2835_dma_conblk *conblk, 108 | volatile void *destination, volatile const void *source, 109 | long destination_stride, long source_stride, 110 | unsigned long xlength, unsigned long ylength, 111 | unsigned long permap) { 112 | 113 | bcm2835_dma_fill_conblk(conblk, destination, source, 0, permap); 114 | 115 | // Bug in the BCM2835 documentation: in 2D mode, it performs 116 | // YLENGTH+1 xlength transfers so we need ylength-1 117 | conblk->txfr_len = (((ylength-1) << 16) & 0x3fff0000) | (xlength & 0xffff); 118 | conblk->stride = ((destination_stride << 16) & 0xffff0000) | (source_stride & 0xffff); 119 | conblk->ti |= BCM2835_DMA_TI_TDMODE; 120 | } 121 | 122 | 123 | void bcm2835_dma_reset(bcm2835_dma_channel_t channel) { 124 | bcm2835_dma_regs_t *regs = BCM2835_DMA(channel); 125 | regs->cs = (1<<31); 126 | } 127 | 128 | /* 129 | * Start DMA transfer 130 | * returns 0 on success, !0 on failure 131 | */ 132 | int bcm2835_dma_start(bcm2835_dma_channel_t channel, bcm2835_dma_conblk *conblk) { 133 | bcm2835_dma_regs_t *regs = BCM2835_DMA(channel); 134 | if (regs->cs & BCM2835_DMA_CS_ACTIVE) { 135 | return -1; // Error: channel is already active 136 | } 137 | 138 | // Flush cache 139 | int cr = 0; 140 | __asm volatile ("mcr p15, 0, %0, c7, c14, 0" :: "r" (cr)); 141 | 142 | // Start transfer 143 | regs->conblk_ad = ((unsigned long) conblk) | 0x40000000; // L1 cached alias 144 | regs->cs = BCM2835_DMA_CS_ACTIVE; 145 | 146 | return 0; // Succes 147 | } 148 | 149 | 150 | 151 | /* 152 | * Poll whether DMA channel is ready 153 | * returns 1 when it is ready, 0 when it is busy 154 | */ 155 | 156 | int bcm2835_dma_isready(bcm2835_dma_channel_t channel) { 157 | bcm2835_dma_regs_t *regs = BCM2835_DMA(channel); 158 | 159 | return (!(regs->cs & BCM2835_DMA_CS_ACTIVE)); 160 | } 161 | 162 | 163 | /* 164 | * Register DMA complete interrupt handler for the given channel 165 | * 166 | * handler( ) is called with the provided closure as its argument 167 | */ 168 | 169 | void bcm2835_dma_register_interrupt(bcm2835_dma_channel_t channel, void (*handler) (void *), void *closure) { 170 | if (channel<=12) { 171 | hal_register_interrupt(channel+16, handler, closure); 172 | } 173 | } 174 | 175 | void bcm2835_dma_acknowledge_interrupt(bcm2835_dma_channel_t channel) { 176 | bcm2835_dma_regs_t *regs = BCM2835_DMA(channel); 177 | regs->cs = (regs->cs & ~BCM2835_DMA_CS_ACTIVE) | BCM2835_DMA_CS_INT; // clear ACTIVE, write 1 to clear INT 178 | } 179 | -------------------------------------------------------------------------------- /SConstruct: -------------------------------------------------------------------------------- 1 | import sys 2 | sys.path.append('tools') 3 | import mkinitfs 4 | import mkzloader 5 | 6 | import os 7 | 8 | # PiPyOS provides a replacement condvar.h in src/, which handles ChibiOS 9 | # mutexes and condition variables, but we need to remove the original from the 10 | # cpython source tree to ensure our condvar.h is used 11 | try: 12 | os.remove('deps/cpython/Python/condvar.h') 13 | except OSError: 14 | pass 15 | 16 | def skip(files, toskip): 17 | return [f for f in files if not f.name in toskip] 18 | 19 | env_base = Environment( 20 | CC='arm-none-eabi-gcc', 21 | CCFLAGS= 22 | '-march=armv6zk -mtune=arm1176jzf-s -mfloat-abi=soft -mno-unaligned-access -mno-thumb-interwork ' 23 | '-Wall -ffunction-sections -fdata-sections -g ' 24 | '-D_XOPEN_SOURCE=600 ' 25 | '-O2'.split() 26 | 27 | , 28 | LIBS=['m'], 29 | 30 | LINKFLAGS= 31 | '-march=armv6zk -mtune=arm1176jzf-s ' 32 | '-nostartfiles ' 33 | '-Wl,--no-warn-mismatch,--gc-sections -mno-thumb-interwork -Wl,-Map,${TARGET}.map '.split() 34 | , 35 | CPPPATH=['adaptors', 'src', 'src/pi'] 36 | , 37 | LINKCOM='$CC -o $TARGET $LINKFLAGS $_LIBDIRFLAGS $_LIBFLAGS $SOURCES', 38 | ASCOM='$CC $ASFLAGS $_CPPINCFLAGS -o $TARGET $SOURCES', 39 | ASFLAGS="-c -x assembler-with-cpp $CCFLAGS", 40 | 41 | ASCOMSTR = "Assembling $TARGET", 42 | #CCCOMSTR = "Compiling $TARGET", 43 | LINKCOMSTR = "Linking $TARGET", 44 | 45 | 46 | ) 47 | env_base.PrependENVPath('PATH', '/opt/local/bin') 48 | 49 | ###################### 50 | # ChibiOS # 51 | ###################### 52 | 53 | 54 | chibios_path = 'deps/ChibiOS-RPi/' 55 | 56 | # Add include path to the base environment 57 | env_base.Append( 58 | CPPPATH=['deps/ff13a'] + [chibios_path + x for x in [ 59 | '', 60 | 'os/ports/GCC/ARM', 'os/ports/GCC/ARM/BCM2835', 'os/kernel/include', 'test', 61 | 'os/hal/include', 'os/hal/platforms/BCM2835', 'os/various', 62 | 'boards/RASPBERRYPI_MODB' 63 | ]] 64 | ) 65 | 66 | # Add custom compile flags to a dedicated ChibiOS environment 67 | 68 | env_chibios = env_base.Clone() 69 | env_chibios.Append( 70 | CCFLAGS= 71 | '-fomit-frame-pointer -Wall -Wextra -Wstrict-prototypes -Wno-unused-parameter'.split(), 72 | 73 | LINKFLAGS = '-TBCM2835.ld' 74 | ) 75 | 76 | chibios = env_chibios.Object( 77 | [ 78 | Glob(chibios_path + 'os/ports/GCC/ARM/*.s'), 79 | Glob(chibios_path + 'os/ports/GCC/ARM/*.c'), 80 | Glob(chibios_path + 'os/ports/GCC/ARM/BCM2835/*.s'), 81 | Glob(chibios_path + 'os/kernel/src/*.c'), 82 | Glob(chibios_path + 'os/hal/src/*.c'), 83 | Glob(chibios_path + 'test/*.c'), 84 | skip(Glob(chibios_path + 'os/hal/platforms/BCM2835/*.c'),['hal_lld.c', 'serial_lld.c', 'sdc_lld.c', 'spi_lld.c', 'i2c_lld.c']), 85 | chibios_path + 'os/various/shell.c', 86 | chibios_path + 'os/various/chprintf.c', 87 | chibios_path + 'boards/RASPBERRYPI_MODB/board.c', 88 | Glob('src/os/*.c'), 89 | Glob('src/pi/*.c'), 90 | skip(Glob('deps/ff13a/*.c'), ['diskio.c']), 91 | ]) 92 | 93 | ###################### 94 | # Python # 95 | ###################### 96 | 97 | env_py=env_base.Clone() 98 | 99 | env_py.Append( 100 | CPPPATH=['.', 'adaptors', 'src', 'deps/cpython/Include', 'deps/cpython/Modules/zlib'], 101 | CCFLAGS=['-std=gnu99', '-DPy_BUILD_CORE', '-Wno-unused-function', '-Wno-unused-variable', '-Wno-unused-parameter'] 102 | ) 103 | 104 | # This allows us to use the Python environment also for building zloader 105 | # This simplifies things since they share some zlib source files 106 | env_py.Append(LINKFLAGS = ['-Tsrc/zloader/zloader.ld']) 107 | 108 | python = env_py.Object( 109 | [ 110 | skip(Glob('deps/cpython/Python/*.c'), 111 | ['dynload_aix.c', 'dynload_dl.c', 'dynload_hpux.c', 'dynload_next.c', 112 | 'dynload_shlib.c', 'dynload_win.c']) 113 | , 114 | skip(Glob('deps/cpython/Parser/*.c'), 115 | ['parsetok_pgen.c', 'pgen.c', 'pgenmain.c', 'tokenizer_pgen.c']) 116 | , 117 | Glob('deps/cpython/Objects/*.c') 118 | , 119 | ['deps/cpython/Modules/gcmodule.c', 'deps/cpython/Modules/hashtable.c', 120 | 'deps/cpython/Modules/main.c', 'deps/cpython/Modules/getpath.c', 121 | 'deps/cpython/Modules/faulthandler.c', 122 | 'deps/cpython/Modules/getbuildinfo.c', 'deps/cpython/Modules/_weakref.c', 123 | 'deps/cpython/Modules/posixmodule.c', 'deps/cpython/Modules/zipimport.c', 124 | 'deps/cpython/Modules/_codecsmodule.c', 'deps/cpython/Modules/errnomodule.c', 125 | 'deps/cpython/Modules/_struct.c', 'deps/cpython/Modules/mathmodule.c', 126 | 'deps/cpython/Modules/_math.c', 'deps/cpython/Modules/timemodule.c', 127 | 'deps/cpython/Modules/itertoolsmodule.c', 'deps/cpython/Modules/_functoolsmodule.c', 128 | 'deps/cpython/Modules/atexitmodule.c', 'deps/cpython/Modules/arraymodule.c', 129 | 'deps/cpython/Modules/zlibmodule.c', 'deps/cpython/Modules/_threadmodule.c', 130 | 'deps/cpython/Modules/_sre.c', 'deps/cpython/Modules/_collectionsmodule.c', 131 | ] 132 | , 133 | skip(Glob('deps/cpython/Modules/zlib/*.c'), ['example.c', 'minigzip.c']) 134 | , 135 | Glob('deps/cpython/Modules/_io/*.c') 136 | , 137 | Glob('src/py/*.c'), 138 | Glob('src/ext/*.c'), 139 | 140 | Glob('deps/pylvgl/lvgl/lv_core/*.c'), 141 | Glob('deps/pylvgl/lvgl/lv_draw/*.c'), 142 | Glob('deps/pylvgl/lvgl/lv_hal/*.c'), 143 | Glob('deps/pylvgl/lvgl/lv_misc/*.c'), 144 | Glob('deps/pylvgl/lvgl/lv_objx/*.c'), 145 | Glob('deps/pylvgl/lvgl/lv_themes/*.c'), 146 | Glob('deps/pylvgl/lvgl/lv_misc/lv_fonts/*.c'), 147 | Glob('deps/pylvgl/lvglmodule.c'), 148 | 149 | 150 | ] 151 | ) 152 | 153 | ###################### 154 | # User app # 155 | ###################### 156 | 157 | app = env_py.Object([Glob('app/*.c'), Glob('app/*.S')]) 158 | 159 | 160 | 161 | ###################### 162 | # Filesystem & rest # 163 | ###################### 164 | 165 | mkinitfs = Command('initfs.bin', '', mkinitfs.main) 166 | AlwaysBuild(mkinitfs) 167 | 168 | initfs = env_chibios.Object('initfs.S') 169 | env_chibios.Depends(initfs, 'initfs.bin') # The include dependency for assembly is not found by scons, add it manually 170 | 171 | pipyos = env_chibios.Program('pipyos.elf', [ 172 | chibios, 173 | python, 174 | app, 175 | 'main_pipyos.c', 176 | 'libm.a', 177 | initfs, 178 | ] 179 | ) 180 | 181 | z = 'deps/cpython/Modules/zlib/' 182 | 183 | zloader = env_py.Program('zloader.elf', [ 184 | z+ 'inflate.c', z + 'adler32.c', z+ 'crc32.c', z + 'inffast.c', z + 'inftrees.c', 185 | 'src/zloader/zloader.c', 'src/zloader/zloader_asm.s' 186 | ] 187 | ) 188 | 189 | 190 | 191 | env_base.Command('pipyos.img', 'pipyos.elf', 'arm-none-eabi-objcopy -O binary $SOURCE $TARGET') 192 | env_base.Command('zloader.img', 'zloader.elf', 'arm-none-eabi-objcopy -O binary $SOURCE $TARGET') 193 | env_base.Command('pipyosz.img', ['zloader.img', 'pipyos.img'], mkzloader.main) 194 | -------------------------------------------------------------------------------- /src/pi/i2c_lld.h: -------------------------------------------------------------------------------- 1 | /* 2 | ChibiOS/RT - Copyright (C) 2006,2007,2008,2009,2010, 3 | 2011,2012 Giovanni Di Sirio. 4 | 5 | This file is part of ChibiOS/RT. 6 | 7 | ChibiOS/RT is free software; you can redistribute it and/or modify 8 | it under the terms of the GNU General Public License as published by 9 | the Free Software Foundation; either version 3 of the License, or 10 | (at your option) any later version. 11 | 12 | ChibiOS/RT is distributed in the hope that it will be useful, 13 | but WITHOUT ANY WARRANTY; without even the implied warranty of 14 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 15 | GNU General Public License for more details. 16 | 17 | You should have received a copy of the GNU General Public License 18 | along with this program. If not, see . 19 | */ 20 | 21 | /** 22 | * @file templates/i2c_lld.h 23 | * @brief I2C Driver subsystem low level driver header template. 24 | * 25 | * @addtogroup I2C 26 | * @{ 27 | */ 28 | 29 | #ifndef _I2C_LLD_H_ 30 | #define _I2C_LLD_H_ 31 | 32 | #if HAL_USE_I2C || defined(__DOXYGEN__) 33 | 34 | #include "bcm2835.h" 35 | 36 | /*===========================================================================*/ 37 | /* Driver constants. */ 38 | /*===========================================================================*/ 39 | 40 | /*===========================================================================*/ 41 | /* Driver pre-compile time settings. */ 42 | /*===========================================================================*/ 43 | 44 | /*===========================================================================*/ 45 | /* Derived constants and error checks. */ 46 | /*===========================================================================*/ 47 | 48 | /*===========================================================================*/ 49 | /* Driver data structures and types. */ 50 | /*===========================================================================*/ 51 | 52 | 53 | /** 54 | * @brief Type of a structure representing an I2C driver. 55 | */ 56 | typedef struct I2CDriver I2CDriver; 57 | 58 | /** 59 | * @brief I2C status type 60 | */ 61 | typedef uint32_t i2cstatus_t; 62 | 63 | /** 64 | * @brief I2C flags type 65 | */ 66 | typedef uint32_t i2cflags_t; 67 | 68 | /** 69 | * @brief I2C address type 70 | * @details I2C address type. May support 10 bit addressing in the future. 71 | */ 72 | typedef uint16_t i2caddr_t; 73 | 74 | /** 75 | * @brief I2C completion callback type. 76 | * 77 | * @param[in] i2cp pointer to the @p I2CDriver object 78 | * @param[in] sts operation status 79 | */ 80 | typedef void (*i2ccallback_t)(I2CDriver *i2cp, i2cstatus_t sts); 81 | 82 | /** 83 | * @brief Driver configuration structure. 84 | * @note Implementations may extend this structure to contain more, 85 | * architecture dependent, fields. 86 | */ 87 | typedef struct { 88 | /** @brief I2C bus bit rate.*/ 89 | uint32_t ic_speed; 90 | /* End of the mandatory fields.*/ 91 | } I2CConfig; 92 | 93 | /** 94 | * @brief Structure representing an I2C driver. 95 | * @note Implementations may extend this structure to contain more, 96 | * architecture dependent, fields. 97 | */ 98 | struct I2CDriver { 99 | /** @brief Driver state.*/ 100 | i2cstate_t state; 101 | /** @brief Current configuration data.*/ 102 | const I2CConfig *config; 103 | /** @brief Error flags.*/ 104 | i2cflags_t errors; 105 | /** @brief BSC device registers.*/ 106 | bscdevice_t *device; 107 | #if I2C_USE_MUTUAL_EXCLUSION 108 | #if CH_USE_MUTEXES 109 | Mutex mutex; 110 | #endif /* CH_USE_MUTEXES */ 111 | #endif /* I2C_USE_MUTUAL_EXCLUSION */ 112 | #if defined(I2C_DRIVER_EXT_FIELDS) 113 | I2C_DRIVER_EXT_FIELDS 114 | #endif 115 | /* End of the mandatory fields.*/ 116 | /** 117 | * @brief Thread waiting for I/O completion. 118 | */ 119 | Thread *thread; 120 | /** 121 | * @brief Address of slave device. 122 | */ 123 | i2caddr_t addr; 124 | 125 | uint32_t sda_pin; 126 | uint32_t scl_pin; 127 | uint32_t alt_function; 128 | 129 | /** 130 | * @brief Pointer to the buffer with data to send. 131 | */ 132 | const uint8_t *txbuf; 133 | /** 134 | * @brief Number of bytes of data to send. 135 | */ 136 | size_t txbytes; 137 | /** 138 | * @brief Current index in buffer when sending data. 139 | */ 140 | size_t txidx; 141 | /** 142 | * @brief Pointer to the buffer to put received data. 143 | */ 144 | uint8_t *rxbuf; 145 | /** 146 | * @brief Number of bytes of data to receive. 147 | */ 148 | size_t rxbytes; 149 | /** 150 | * @brief Current index in buffer when receiving data. 151 | */ 152 | size_t rxidx; 153 | }; 154 | 155 | /*===========================================================================*/ 156 | /* Driver macros. */ 157 | /*===========================================================================*/ 158 | 159 | #define i2c_lld_master_start(i2cp, header) 160 | 161 | #define i2c_lld_master_stop(i2cp) 162 | 163 | #define i2c_lld_master_restart(i2cp) 164 | 165 | #define i2c_lld_get_errors(i2cp) ((i2cp)->errors) 166 | 167 | /*===========================================================================*/ 168 | /* External declarations. */ 169 | /*===========================================================================*/ 170 | 171 | extern I2CDriver I2C0; 172 | extern I2CDriver I2C1; 173 | 174 | #ifdef __cplusplus 175 | extern "C" { 176 | #endif 177 | void i2c_lld_init(void); 178 | void i2c_lld_start(I2CDriver *i2cp); 179 | void i2c_lld_stop(I2CDriver *i2cp); 180 | 181 | msg_t i2c_lld_master_transmit_timeout(I2CDriver *i2cp, i2caddr_t addr, 182 | const uint8_t *txbuf, size_t txbytes, 183 | uint8_t *rxbuf, const uint8_t rxbytes, 184 | systime_t timeout); 185 | 186 | msg_t i2c_lld_master_receive_timeout(I2CDriver *i2cp, i2caddr_t addr, 187 | uint8_t *rxbuf, size_t rxbytes, 188 | systime_t timeout); 189 | 190 | void i2c_lld_serve_interrupt(I2CDriver *i2cp); 191 | 192 | #ifdef __cplusplus 193 | } 194 | #endif 195 | 196 | #endif /* HAL_USE_I2C */ 197 | 198 | #endif /* _I2C_LLD_H_ */ 199 | 200 | /** @} */ 201 | -------------------------------------------------------------------------------- /src/pi/serial_lld.c: -------------------------------------------------------------------------------- 1 | /* 2 | Raspberry Pi UART low level driver 3 | (C) Rob Reilink, 2018 4 | */ 5 | 6 | 7 | #include "ch.h" 8 | #include "hal.h" 9 | #include "bcmmailbox.h" 10 | 11 | #if HAL_USE_SERIAL || defined(__DOXYGEN__) 12 | 13 | #define UART_DR REG(0x20201000) 14 | #define UART_RSRECR REG(0x20201004) 15 | #define UART_FR REG(0x20201018) 16 | #define UART_ILPR REG(0x20201020) 17 | #define UART_IBRD REG(0x20201024) 18 | #define UART_FBRD REG(0x20201028) 19 | #define UART_LCRH REG(0x2020102C) 20 | #define UART_CR REG(0x20201030) 21 | #define UART_IFLS REG(0x20201034) 22 | #define UART_IMSC REG(0x20201038) 23 | #define UART_RIS REG(0x2020103C) 24 | #define UART_MIS REG(0x20201040) 25 | #define UART_ICR REG(0x20201044) 26 | #define UART_DMACR REG(0x20201048) 27 | #define UART_ITCR REG(0x20201080) 28 | #define UART_ITIP REG(0x20201084) 29 | #define UART_ITOP REG(0x20201088) 30 | #define UART_TDR REG(0x2020108C) 31 | 32 | 33 | #define UART_INT_RT BIT(6) 34 | #define UART_INT_TX BIT(5) 35 | #define UART_INT_RX BIT(4) 36 | #define UART_INT_ALL 0x7F2; 37 | 38 | 39 | #define UART_FR_RXFE BIT(4) 40 | #define UART_FR_TXFF BIT(5) 41 | 42 | #define UART_LCRH_WLEN_8 (BIT(6) | BIT(5)) 43 | #define UART_LCRH_FEN BIT(4) 44 | 45 | #define UART_CR_RXE BIT(9) 46 | #define UART_CR_TXE BIT(8) 47 | #define UART_CR_UARTEN BIT(0) 48 | 49 | #define UART_IFLS_RXIFLSEL_1_8 (0<<3) 50 | #define UART_IFLS_RXIFLSEL_1_4 (1<<3) 51 | #define UART_IFLS_RXIFLSEL_1_2 (2<<3) 52 | #define UART_IFLS_RXIFLSEL_3_4 (3<<3) 53 | #define UART_IFLS_RXIFLSEL_7_8 (4<<3) 54 | 55 | #define UART_IFLS_TXIFLSEL_1_8 (0) 56 | #define UART_IFLS_TXIFLSEL_1_4 (1) 57 | #define UART_IFLS_TXIFLSEL_1_2 (2) 58 | #define UART_IFLS_TXIFLSEL_3_4 (3) 59 | #define UART_IFLS_TXIFLSEL_7_8 (4) 60 | 61 | 62 | //#define TRACE(msg) PiPyOS_bcm_framebuffer_putstring(msg, -1) 63 | #define TRACE(msg) 64 | 65 | 66 | /*===========================================================================*/ 67 | /* Driver local definitions. */ 68 | /*===========================================================================*/ 69 | 70 | void uart_send ( uint32_t c ); 71 | void uart_sendstr (const char *s); 72 | 73 | /*===========================================================================*/ 74 | /* Driver exported variables. */ 75 | /*===========================================================================*/ 76 | 77 | SerialDriver SD1; 78 | CondVar PiPyOS_serial_interrupt_cv; 79 | 80 | /*===========================================================================*/ 81 | /* Driver local variables. */ 82 | /*===========================================================================*/ 83 | 84 | /** 85 | * @brief Driver default configuration. 86 | */ 87 | static const SerialConfig default_config = { 88 | 115200 /* default baud rate */ 89 | }; 90 | 91 | /*===========================================================================*/ 92 | /* Driver local functions. */ 93 | /*===========================================================================*/ 94 | 95 | static void output_notify(GenericQueue *qp) { 96 | (void)(qp); 97 | /* Enable tx interrupts.*/ 98 | UART_IMSC |= UART_INT_TX; 99 | } 100 | 101 | /*===========================================================================*/ 102 | /* Driver interrupt handlers. */ 103 | /*===========================================================================*/ 104 | 105 | 106 | void sd_lld_serve_interrupt( SerialDriver *sdp ) { // TODO: could also be static 107 | 108 | if (UART_MIS & (UART_INT_RX | UART_INT_RT)) { // RX or RX timeout interrupt 109 | chSysLockFromIsr(); 110 | while(!(UART_FR & UART_FR_RXFE)) { 111 | unsigned int data; 112 | data = UART_DR; 113 | if ((data & 0xf00)==0) { 114 | // No errors 115 | if ((data & 0xff) == 3) { 116 | chCondBroadcastI(&PiPyOS_serial_interrupt_cv); // catch ctrl+c 117 | } 118 | 119 | sdIncomingDataI(sdp, data & 0xFF); 120 | } 121 | }; 122 | chSysUnlockFromIsr(); 123 | } 124 | 125 | if (UART_MIS & UART_INT_TX) { 126 | TRACE("TX"); 127 | chSysLockFromIsr(); 128 | while(!(UART_FR & UART_FR_TXFF)) { 129 | msg_t data = sdRequestDataI(sdp); 130 | if (data < Q_OK) { 131 | TRACE("!"); 132 | 133 | /* Disable tx interrupts.*/ 134 | UART_IMSC &= ~UART_INT_TX; 135 | break; 136 | } 137 | else { 138 | UART_DR = data; 139 | TRACE("."); 140 | 141 | } 142 | } 143 | chSysUnlockFromIsr(); 144 | } 145 | } 146 | 147 | /*===========================================================================*/ 148 | /* Driver exported functions. */ 149 | /*===========================================================================*/ 150 | 151 | /** 152 | * @brief Low level serial driver initialization. 153 | * 154 | * @notapi 155 | */ 156 | void sd_lld_init(void) { 157 | chCondInit(&PiPyOS_serial_interrupt_cv); 158 | sdObjectInit(&SD1, NULL, output_notify); 159 | } 160 | 161 | /** 162 | * @brief Low level serial driver configuration and (re)start. 163 | * 164 | * @param[in] sdp pointer to a @p SerialDriver object 165 | * @param[in] config the architecture-dependent serial driver configuration. 166 | * If this parameter is set to @p NULL then a default 167 | * configuration is used. 168 | * 169 | * @notapi 170 | */ 171 | void sd_lld_start(SerialDriver *sdp, const SerialConfig *config) { 172 | (void)(sdp); 173 | 174 | unsigned int base_clock_rate, divider; 175 | 176 | if (config == NULL) 177 | config = &default_config; 178 | 179 | base_clock_rate = 48000000; 180 | 181 | DataMemBarrier(); 182 | 183 | IRQ_DISABLE2 = BIT(57-32); 184 | 185 | DataMemBarrier(); 186 | 187 | UART_CR = 0; 188 | UART_IMSC = 0; 189 | UART_LCRH = 0; 190 | 191 | DataMemBarrier(); 192 | 193 | bcm2835_gpio_fnsel(14, GPFN_ALT0); 194 | bcm2835_gpio_fnsel(15, GPFN_ALT0); 195 | 196 | GPPUD = 0; 197 | bcm2835_delay(150); 198 | GPPUDCLK0 = (1<<14)|(1<<15); 199 | bcm2835_delay(150); 200 | GPPUDCLK0 = 0; 201 | 202 | DataMemBarrier(); 203 | 204 | 205 | // Calculate divider using 6 fractional bits 206 | divider = (base_clock_rate << 6) / (16*1000000); //TODO: use config baud rate 207 | 208 | UART_IBRD = divider >> 6; 209 | UART_FBRD = divider & 0x3F; 210 | 211 | UART_LCRH = UART_LCRH_WLEN_8 | UART_LCRH_FEN; 212 | 213 | // TODO: select appropriate FIFO interrupt levels 214 | UART_IFLS = UART_IFLS_RXIFLSEL_1_2 | UART_IFLS_TXIFLSEL_1_2; 215 | 216 | UART_ICR = UART_INT_ALL; 217 | 218 | UART_CR = UART_CR_RXE | UART_CR_TXE | UART_CR_UARTEN; 219 | 220 | UART_IMSC = UART_INT_RT | UART_INT_RX; 221 | 222 | // The UART needs its TX FIFO above threshold once to work 223 | // This is a work-around, TODO: fix 224 | uart_sendstr("TEST123456\n"); 225 | 226 | hal_register_interrupt(57, (void (*)(void *))sd_lld_serve_interrupt, &SD1); 227 | 228 | 229 | IRQ_ENABLE2 = BIT(57-32); 230 | } 231 | 232 | /** 233 | * @brief Low level serial driver stop. 234 | * @details De-initializes the USART, stops the associated clock, resets the 235 | * interrupt vector. 236 | * 237 | * @param[in] sdp pointer to a @p SerialDriver object 238 | * 239 | * @notapi 240 | */ 241 | void sd_lld_stop(SerialDriver *sdp) { 242 | (void)(sdp); 243 | 244 | IRQ_DISABLE2 = BIT(57-32); 245 | bcm2835_gpio_fnsel(14, GPFN_IN); 246 | bcm2835_gpio_fnsel(15, GPFN_IN); 247 | } 248 | 249 | 250 | uint32_t uart_recv ( void ) 251 | { 252 | while((UART_FR & UART_FR_RXFE)); 253 | return(UART_DR & 0xFF); 254 | } 255 | 256 | void uart_send ( uint32_t c ) 257 | { 258 | while((UART_FR & UART_FR_TXFF)); 259 | UART_DR = c; 260 | } 261 | 262 | void uart_sendstr (const char *s) 263 | { 264 | char c; 265 | while((c = *s++)) uart_send(c); 266 | } 267 | 268 | 269 | #endif /* HAL_USE_SERIAL */ 270 | 271 | /** @} */ 272 | -------------------------------------------------------------------------------- /src/pi/spi_lld.c: -------------------------------------------------------------------------------- 1 | #include "ch.h" 2 | #include "hal.h" 3 | #include "bcm2835_dma.h" 4 | #include "bcm2835_spi.h" 5 | 6 | 7 | #if HAL_USE_SPI || defined(__DOXYGEN__) 8 | 9 | 10 | /*===========================================================================*/ 11 | /* Driver exported variables. */ 12 | /*===========================================================================*/ 13 | 14 | SPIDriver SPI0; 15 | 16 | /*===========================================================================*/ 17 | /* Driver local variables. */ 18 | /*===========================================================================*/ 19 | 20 | static bcm2835_dma_channel_t rx_dma_channel; 21 | static bcm2835_dma_channel_t tx_dma_channel; 22 | 23 | static bcm2835_dma_conblk rx_conblk; 24 | static bcm2835_dma_conblk tx_conblk; 25 | 26 | /*===========================================================================*/ 27 | /* Driver local functions. */ 28 | /*===========================================================================*/ 29 | 30 | /* 31 | * DMA-based transfer ready 32 | */ 33 | static void spi_lld_serve_dma_interrupt(SPIDriver *spip) { 34 | bcm2835_dma_acknowledge_interrupt(rx_dma_channel); 35 | 36 | _spi_isr_code(spip); 37 | } 38 | 39 | /* 40 | * Non-DMA based transfer ready. Read data from FIFO 41 | */ 42 | static void spi_lld_serve_spi_interrupt(SPIDriver *spip) { 43 | 44 | uint8_t *rxbuf = spip->rxbuf; 45 | uint8_t data = 0; 46 | 47 | while(spip->rxcnt--) { 48 | data = BCM2835_SPI->fifo; 49 | if (rxbuf) *rxbuf++ = data; 50 | } 51 | 52 | BCM2835_SPI->cs = (BCM2835_SPI->cs & ~(BCM2835_SPI_CS_TA | BCM2835_SPI_CS_INTD)); 53 | 54 | _spi_isr_code(spip); 55 | } 56 | 57 | /*===========================================================================*/ 58 | /* Driver interrupt handlers. */ 59 | /*===========================================================================*/ 60 | 61 | /*===========================================================================*/ 62 | /* Driver exported functions. */ 63 | /*===========================================================================*/ 64 | 65 | /** 66 | * @brief Low level SPI driver initialization. 67 | * 68 | * @notapi 69 | */ 70 | void spi_lld_init(void) { 71 | spiObjectInit(&SPI0); 72 | 73 | //allocate DMA 74 | rx_dma_channel = bcm2835_dma_alloc(0); 75 | tx_dma_channel = bcm2835_dma_alloc(0); 76 | } 77 | 78 | /* Give other code (e.g. pitft display driver) read-access to our DMA channels 79 | * 80 | * The signature uses void* to prevent requiring inclusion of bcm2835_dma.h in 81 | * all code (since spi_lld.h is included via hal.h) 82 | */ 83 | 84 | void spi_lld_get_dma_channels(void *rx, void *tx) { 85 | *((bcm2835_dma_channel_t *)rx) = rx_dma_channel; 86 | *((bcm2835_dma_channel_t *)tx) = tx_dma_channel; 87 | } 88 | 89 | 90 | void spi_lld_start(SPIDriver *spip) { 91 | unsigned int divider; 92 | const SPIConfig *cfg = spip->config; 93 | 94 | bcm2835_dma_disable_interrupt(rx_dma_channel); 95 | 96 | if (cfg->chip_select == 1) bcm2835_gpio_fnsel(7, GPFN_ALT0); /* SPI0_CE1_N.*/ 97 | if (cfg->chip_select == 0) bcm2835_gpio_fnsel(8, GPFN_ALT0); /* SPI0_CE0_N.*/ 98 | bcm2835_gpio_fnsel(9, GPFN_ALT0); /* SPI0_MOSI.*/ 99 | bcm2835_gpio_fnsel(10, GPFN_ALT0); /* SPI0_MISO.*/ 100 | bcm2835_gpio_fnsel(11, GPFN_ALT0); /* SPIO_SCLK.*/ 101 | 102 | 103 | // Chip select polarity is rather vague in the BCM2835 datasheet 104 | // So only negative CS polarity is implemented 105 | 106 | BCM2835_SPI->cs = BCM2835_SPI_CS_CS(cfg->chip_select) 107 | | (cfg->clock_phase ? BCM2835_SPI_CS_CPHA : 0) 108 | | (cfg->clock_polarity ? BCM2835_SPI_CS_CPOL : 0); 109 | 110 | 111 | divider = 250000000L / cfg->clock_frequency; 112 | if (divider == 0) divider = 2; // ensure >0 113 | if (divider & 1) divider++; // ensure even; round up 114 | 115 | BCM2835_SPI->clk = divider; 116 | 117 | bcm2835_dma_register_interrupt(rx_dma_channel, (void (*)(void *))spi_lld_serve_dma_interrupt, spip); 118 | 119 | bcm2835_dma_enable_interrupt(rx_dma_channel); 120 | 121 | hal_register_interrupt(54, (void (*)(void *))spi_lld_serve_spi_interrupt, spip); 122 | 123 | IRQ_ENABLE2 = BIT(54-32); 124 | } 125 | 126 | /** 127 | * @brief Deactivates the SPI peripheral. 128 | * 129 | * @param[in] spip pointer to the @p SPIDriver object 130 | * 131 | * @notapi 132 | */ 133 | void spi_lld_stop(SPIDriver *spip) { 134 | bcm2835_gpio_fnsel(7, GPFN_IN); 135 | bcm2835_gpio_fnsel(8, GPFN_IN); 136 | bcm2835_gpio_fnsel(9, GPFN_IN); 137 | bcm2835_gpio_fnsel(10, GPFN_IN); 138 | bcm2835_gpio_fnsel(11, GPFN_IN); 139 | } 140 | 141 | void spi_lld_select(SPIDriver *spip) { 142 | // Done automatically in hardware 143 | } 144 | 145 | 146 | void spi_lld_unselect(SPIDriver *spip) { 147 | // Done automatically in hardware 148 | } 149 | 150 | 151 | 152 | /** 153 | * @brief Exchanges data on the SPI bus. 154 | * @details This asynchronous function starts a simultaneous transmit/receive 155 | * operation. 156 | * @post At the end of the operation the configured callback is invoked. 157 | * @note The buffers are organized as uint8_t arrays for data sizes below or 158 | * equal to 8 bits else it is organized as uint16_t arrays. 159 | * 160 | * @param[in] spip pointer to the @p SPIDriver object 161 | * @param[in] n number of words to be exchanged 162 | * @param[in] txbuf the pointer to the transmit buffer 163 | * @param[out] rxbuf the pointer to the receive buffer 164 | * 165 | * @notapi 166 | */ 167 | void spi_lld_exchange(SPIDriver *spip, size_t n, 168 | const void *txbuf, void *rxbuf) { 169 | 170 | // Beyond the max supported by the peripheral. TODO: work around it 171 | if (n>65532) n = 65532; 172 | 173 | if (n<=16) { 174 | // Small transfer: do not use DMA. Load the data into the FIFO and use the 175 | // SPI interrupt to read the data from the FIFO when completed 176 | BCM2835_SPI->cs = (BCM2835_SPI->cs & ~BCM2835_SPI_CS_DMAEN) 177 | | BCM2835_SPI_CS_CLEAR_TX | BCM2835_SPI_CS_CLEAR_RX | BCM2835_SPI_CS_TA; 178 | 179 | const uint8_t *txbuf_b = txbuf; 180 | spip->rxbuf = rxbuf; 181 | spip->rxcnt = n; 182 | uint8_t data = 0; 183 | 184 | for(unsigned int i=0;ififo = data; 189 | } 190 | 191 | BCM2835_SPI->cs |= BCM2835_SPI_CS_INTD; 192 | 193 | return; 194 | } 195 | 196 | bcm2835_dma_reset(rx_dma_channel); 197 | bcm2835_dma_reset(tx_dma_channel); 198 | 199 | bcm2835_dma_fill_conblk(&tx_conblk, &BCM2835_SPI->fifo, txbuf, n, 6); 200 | bcm2835_dma_fill_conblk(&rx_conblk, rxbuf, &BCM2835_SPI->fifo, n, 7); 201 | 202 | BCM2835_SPI->cs = (BCM2835_SPI->cs & ~BCM2835_SPI_CS_TA) | BCM2835_SPI_CS_DMAEN | BCM2835_SPI_CS_ADCS; 203 | 204 | // Write DLEN and CS low byte via FIFO register (copy current config from CS) 205 | BCM2835_SPI->fifo = (n<<16) 206 | | BCM2835_SPI_CS_CLEAR_TX | BCM2835_SPI_CS_CLEAR_RX | BCM2835_SPI_CS_TA 207 | | (BCM2835_SPI->cs & ( BCM2835_SPI_CS_CS(3)| BCM2835_SPI_CS_CPHA | BCM2835_SPI_CS_CPOL )); 208 | 209 | rx_conblk.ti |= 0x1; // INTEN 210 | 211 | bcm2835_dma_start(rx_dma_channel, &rx_conblk); 212 | bcm2835_dma_start(tx_dma_channel, &tx_conblk); 213 | 214 | 215 | } 216 | 217 | 218 | void spi_lld_ignore(SPIDriver *spip, size_t n) { 219 | spi_lld_exchange(spip, n, NULL, NULL); 220 | } 221 | void spi_lld_send(SPIDriver *spip, size_t n, const void *txbuf) { 222 | spi_lld_exchange(spip, n, txbuf, NULL); 223 | } 224 | 225 | void spi_lld_receive(SPIDriver *spip, size_t n, void *rxbuf) { 226 | spi_lld_exchange(spip, n, NULL, rxbuf); 227 | } 228 | 229 | 230 | uint16_t spi_lld_polled_exchange(SPIDriver *spip, uint16_t frame) { 231 | // Not implemented 232 | return 0; 233 | } 234 | 235 | #endif /* HAL_USE_SPI */ 236 | 237 | /** @} */ 238 | -------------------------------------------------------------------------------- /src/pi/bcmframebuffer.c: -------------------------------------------------------------------------------- 1 | /* Framebuffer and terminal emulator 2 | * 3 | * Only supports fixed font size (8x16) and 8-bit color 4 | * These were chosen for speed 5 | */ 6 | 7 | 8 | #include 9 | #include 10 | #include 11 | 12 | #include "bcmmailbox.h" 13 | #include "assert.h" 14 | #include "../deps/font.h" 15 | 16 | static struct { 17 | uint32_t phys_width; 18 | uint32_t phys_height; 19 | uint32_t virt_width; 20 | uint32_t virt_height; 21 | uint32_t pitch; 22 | uint32_t depth; 23 | uint32_t offset_x; 24 | uint32_t offset_y; 25 | void* buffer; 26 | uint32_t size; 27 | uint16_t palette[256]; 28 | 29 | } __attribute__ ((aligned (16))) fb_info; 30 | 31 | 32 | static unsigned int _posx, _posy; 33 | static uint8_t _cursorcopy[2*CHARWIDTH]; // copy of the data under the cursor 34 | static int _fgcolor, _bgcolor, _cursorcolor; 35 | 36 | 37 | static inline uint8_t *_ptr_for_char(int x, int y) { 38 | return fb_info.buffer + _posx * CHARWIDTH + _posy * CHARHEIGHT * fb_info.pitch; 39 | } 40 | 41 | /* Write a cursor to the screen, save the pixels that were overwritten to 42 | * _cursorcopy so these can be restored by _erasecursor() when required 43 | */ 44 | static void _writecursor(void) { 45 | uint8_t *p = _ptr_for_char(_posx, _posy); 46 | 47 | p+=fb_info.pitch*(CHARHEIGHT-4); 48 | memcpy(_cursorcopy, p, CHARWIDTH); 49 | memcpy(_cursorcopy+CHARWIDTH, p+fb_info.pitch, CHARWIDTH); 50 | 51 | memset(p, _cursorcolor, CHARWIDTH); 52 | memset(p+fb_info.pitch, _cursorcolor, CHARWIDTH); 53 | } 54 | 55 | /* Erase the cursor to the screen, restore the pixels that were saved to 56 | * _cursorcopy. 57 | */ 58 | static void _erasecursor(void) { 59 | uint8_t *p = _ptr_for_char(_posx, _posy); 60 | 61 | p+=fb_info.pitch*(CHARHEIGHT-4); 62 | memcpy(p, _cursorcopy, CHARWIDTH); 63 | memcpy(p+fb_info.pitch, _cursorcopy+CHARWIDTH, CHARWIDTH); 64 | } 65 | 66 | 67 | 68 | /* Initialize framebuffer 69 | * 70 | * width, height: dimensions of the framebuffer. If both are 0, these are 71 | * aquired from the VideoCore 72 | */ 73 | 74 | void PiPyOS_bcm_framebuffer_init(int width, int height) { 75 | int size[2]; 76 | int i; 77 | 78 | if (width == 0 || height == 0) { 79 | memset(&fb_info, 0, sizeof(fb_info)); 80 | PiPyOS_bcm_get_property_tag(0x40003, &size, 8); 81 | fb_info.phys_width = fb_info.virt_width = size[0]; 82 | fb_info.phys_height = fb_info.virt_height = size[1]; 83 | 84 | } else { 85 | fb_info.phys_width = fb_info.virt_width = width; 86 | fb_info.phys_height = fb_info.virt_height = height; 87 | } 88 | 89 | fb_info.phys_width = fb_info.virt_width = size[0]; 90 | fb_info.phys_height = fb_info.virt_height = size[1]; 91 | 92 | fb_info.depth = 8; 93 | 94 | for(i=0;i<8;i++) { // initialize a 4-bit palette 95 | fb_info.palette[i]= ((i&4) ? 0xa800 : 0 ) | ((i&2) ? 0x580 : 0) | ((i&1) ? 0x15 : 0); // normal color 96 | fb_info.palette[i+8]= ((i&4) ? 0xf800 : 0 ) | ((i&2) ? 0x7e0 : 0) | ((i&1) ? 0x1f : 0); // extra bright color 97 | } 98 | 99 | 100 | PiPyOS_bcm_mailbox_write_read(1, &fb_info); 101 | 102 | assert(fb_info.buffer); 103 | 104 | _bgcolor = 1; 105 | _cursorcolor = 7; 106 | _fgcolor = 7; 107 | 108 | memset(fb_info.buffer, _bgcolor, fb_info.size); // test: blue screen 109 | 110 | _posx = 0; 111 | _posy = 0; 112 | _writecursor(); 113 | } 114 | 115 | 116 | /* count = -1: write upto \0 117 | * count >=0: write count chars 118 | */ 119 | 120 | void PiPyOS_bcm_framebuffer_putstring(const char *s, int count) { 121 | char c; 122 | uint8_t color; 123 | uint8_t *p, *p2; 124 | 125 | unsigned int escapestate = 0, escapeparam = 0; 126 | 127 | 128 | /* Some optimization: we only write the cursor when we are done writing 129 | * the string. When the first char is written, it overwrites the cursor. 130 | * So we only need to erase any previous cursor, when the cursor is moved 131 | * (e.g. \r, \n) before any char is written. cursorvisible keeps track of 132 | * wether or not we need to remove the cursor in those cases. 133 | */ 134 | int cursorvisible = 1; 135 | 136 | while(1) { 137 | c = *s++; 138 | 139 | if (count==-1) { 140 | if (!c) break; // count == -1: write until \0 141 | } else { 142 | if (count == 0) break; 143 | count--; 144 | } 145 | 146 | p = _ptr_for_char(_posx, _posy); 147 | 148 | // minimal terminal emulator to support the codes emitted by _readline.py 149 | if (c=='\x1b') { 150 | escapestate = 1; 151 | continue; 152 | } 153 | 154 | switch (escapestate) { 155 | case 1: 156 | if (c == '[') { 157 | escapestate++; 158 | escapeparam = 0; 159 | continue; 160 | } 161 | break; 162 | case 2: 163 | if (c>='0' && c<='9') { 164 | escapeparam = escapeparam * 10 + (c-'0'); 165 | continue; 166 | } 167 | if (c=='K') { // clear till end of line 168 | // no need to erase cursor, we will clear the entire line 169 | for (int i=0; i escapeparam) _posx-=escapeparam; else _posx = 0; 177 | } else if (c=='C') { // forward x positions 178 | if (cursorvisible) _erasecursor(); 179 | if (escapeparam == 0) escapeparam = 1; 180 | _posx += escapeparam; 181 | goto fixcursorpos; // correct passing end-of-line / end-of-screen 182 | } 183 | 184 | escapestate = 0; 185 | continue; 186 | } 187 | 188 | 189 | if (c>=0x20) { 190 | // 'Normal' char for which we have an image; font table starts at 0x20 191 | c-=0x20; 192 | 193 | // Loop over rows and columns, write character bitmap to framebuffer 194 | for(int y=0;y>=1) { 197 | color = _bgcolor; 198 | if (font_data[(int)c][y] & mask) { 199 | color = _fgcolor; 200 | } 201 | *p2++ = color; 202 | } 203 | p += fb_info.pitch; 204 | } 205 | 206 | _posx+=1; 207 | cursorvisible = 0; 208 | 209 | } else { 210 | // 'Special' char handling 211 | switch(c) { 212 | case '\n': 213 | if (cursorvisible) _erasecursor(); 214 | _posy += 1; 215 | _posx = 0; 216 | break; 217 | case '\r': 218 | if (cursorvisible) _erasecursor(); 219 | _posx = 0; 220 | break; 221 | case '\t': 222 | if (cursorvisible) _erasecursor(); 223 | _posx = (_posx+8) & ~7; 224 | break; 225 | default: 226 | continue; //ignore char 227 | } 228 | } 229 | 230 | fixcursorpos: 231 | // check end-of-line 232 | if ((_posx+1)*CHARWIDTH>fb_info.virt_width) { 233 | _posx=0; 234 | _posy+=1; 235 | } 236 | // check end-of-screen 237 | if ((_posy+1)*CHARHEIGHT>fb_info.virt_height) { 238 | // scroll screen 239 | _posy-=1; 240 | memcpy(fb_info.buffer, fb_info.buffer + fb_info.pitch * CHARHEIGHT, fb_info.pitch * _posy * CHARHEIGHT); 241 | memset(fb_info.buffer + fb_info.pitch * _posy * CHARHEIGHT, _bgcolor, fb_info.pitch*CHARHEIGHT); 242 | } 243 | } 244 | // Only write cursor to screen when we are done 245 | _writecursor(); 246 | } 247 | 248 | 249 | 250 | -------------------------------------------------------------------------------- /deps/ff13a/00history.txt: -------------------------------------------------------------------------------- 1 | ---------------------------------------------------------------------------- 2 | Revision history of FatFs module 3 | ---------------------------------------------------------------------------- 4 | 5 | R0.00 (February 26, 2006) 6 | 7 | Prototype. 8 | 9 | 10 | 11 | R0.01 (April 29, 2006) 12 | 13 | The first release. 14 | 15 | 16 | 17 | R0.02 (June 01, 2006) 18 | 19 | Added FAT12 support. 20 | Removed unbuffered mode. 21 | Fixed a problem on small (<32M) partition. 22 | 23 | 24 | 25 | R0.02a (June 10, 2006) 26 | 27 | Added a configuration option (_FS_MINIMUM). 28 | 29 | 30 | 31 | R0.03 (September 22, 2006) 32 | 33 | Added f_rename(). 34 | Changed option _FS_MINIMUM to _FS_MINIMIZE. 35 | 36 | 37 | 38 | R0.03a (December 11, 2006) 39 | 40 | Improved cluster scan algorithm to write files fast. 41 | Fixed f_mkdir() creates incorrect directory on FAT32. 42 | 43 | 44 | 45 | R0.04 (February 04, 2007) 46 | 47 | Added f_mkfs(). 48 | Supported multiple drive system. 49 | Changed some interfaces for multiple drive system. 50 | Changed f_mountdrv() to f_mount(). 51 | 52 | 53 | 54 | R0.04a (April 01, 2007) 55 | 56 | Supported multiple partitions on a physical drive. 57 | Added a capability of extending file size to f_lseek(). 58 | Added minimization level 3. 59 | Fixed an endian sensitive code in f_mkfs(). 60 | 61 | 62 | 63 | R0.04b (May 05, 2007) 64 | 65 | Added a configuration option _USE_NTFLAG. 66 | Added FSINFO support. 67 | Fixed DBCS name can result FR_INVALID_NAME. 68 | Fixed short seek (<= csize) collapses the file object. 69 | 70 | 71 | 72 | R0.05 (August 25, 2007) 73 | 74 | Changed arguments of f_read(), f_write() and f_mkfs(). 75 | Fixed f_mkfs() on FAT32 creates incorrect FSINFO. 76 | Fixed f_mkdir() on FAT32 creates incorrect directory. 77 | 78 | 79 | 80 | R0.05a (February 03, 2008) 81 | 82 | Added f_truncate() and f_utime(). 83 | Fixed off by one error at FAT sub-type determination. 84 | Fixed btr in f_read() can be mistruncated. 85 | Fixed cached sector is not flushed when create and close without write. 86 | 87 | 88 | 89 | R0.06 (April 01, 2008) 90 | 91 | Added fputc(), fputs(), fprintf() and fgets(). 92 | Improved performance of f_lseek() on moving to the same or following cluster. 93 | 94 | 95 | 96 | R0.07 (April 01, 2009) 97 | 98 | Merged Tiny-FatFs as a configuration option. (_FS_TINY) 99 | Added long file name feature. (_USE_LFN) 100 | Added multiple code page feature. (_CODE_PAGE) 101 | Added re-entrancy for multitask operation. (_FS_REENTRANT) 102 | Added auto cluster size selection to f_mkfs(). 103 | Added rewind option to f_readdir(). 104 | Changed result code of critical errors. 105 | Renamed string functions to avoid name collision. 106 | 107 | 108 | 109 | R0.07a (April 14, 2009) 110 | 111 | Septemberarated out OS dependent code on reentrant cfg. 112 | Added multiple sector size feature. 113 | 114 | 115 | 116 | R0.07c (June 21, 2009) 117 | 118 | Fixed f_unlink() can return FR_OK on error. 119 | Fixed wrong cache control in f_lseek(). 120 | Added relative path feature. 121 | Added f_chdir() and f_chdrive(). 122 | Added proper case conversion to extended character. 123 | 124 | 125 | 126 | R0.07e (November 03, 2009) 127 | 128 | Septemberarated out configuration options from ff.h to ffconf.h. 129 | Fixed f_unlink() fails to remove a sub-directory on _FS_RPATH. 130 | Fixed name matching error on the 13 character boundary. 131 | Added a configuration option, _LFN_UNICODE. 132 | Changed f_readdir() to return the SFN with always upper case on non-LFN cfg. 133 | 134 | 135 | 136 | R0.08 (May 15, 2010) 137 | 138 | Added a memory configuration option. (_USE_LFN = 3) 139 | Added file lock feature. (_FS_SHARE) 140 | Added fast seek feature. (_USE_FASTSEEK) 141 | Changed some types on the API, XCHAR->TCHAR. 142 | Changed .fname in the FILINFO structure on Unicode cfg. 143 | String functions support UTF-8 encoding files on Unicode cfg. 144 | 145 | 146 | 147 | R0.08a (August 16, 2010) 148 | 149 | Added f_getcwd(). (_FS_RPATH = 2) 150 | Added sector erase feature. (_USE_ERASE) 151 | Moved file lock semaphore table from fs object to the bss. 152 | Fixed f_mkfs() creates wrong FAT32 volume. 153 | 154 | 155 | 156 | R0.08b (January 15, 2011) 157 | 158 | Fast seek feature is also applied to f_read() and f_write(). 159 | f_lseek() reports required table size on creating CLMP. 160 | Extended format syntax of f_printf(). 161 | Ignores duplicated directory separators in given path name. 162 | 163 | 164 | 165 | R0.09 (September 06, 2011) 166 | 167 | f_mkfs() supports multiple partition to complete the multiple partition feature. 168 | Added f_fdisk(). 169 | 170 | 171 | 172 | R0.09a (August 27, 2012) 173 | 174 | Changed f_open() and f_opendir() reject null object pointer to avoid crash. 175 | Changed option name _FS_SHARE to _FS_LOCK. 176 | Fixed assertion failure due to OS/2 EA on FAT12/16 volume. 177 | 178 | 179 | 180 | R0.09b (January 24, 2013) 181 | 182 | Added f_setlabel() and f_getlabel(). 183 | 184 | 185 | 186 | R0.10 (October 02, 2013) 187 | 188 | Added selection of character encoding on the file. (_STRF_ENCODE) 189 | Added f_closedir(). 190 | Added forced full FAT scan for f_getfree(). (_FS_NOFSINFO) 191 | Added forced mount feature with changes of f_mount(). 192 | Improved behavior of volume auto detection. 193 | Improved write throughput of f_puts() and f_printf(). 194 | Changed argument of f_chdrive(), f_mkfs(), disk_read() and disk_write(). 195 | Fixed f_write() can be truncated when the file size is close to 4GB. 196 | Fixed f_open(), f_mkdir() and f_setlabel() can return incorrect value on error. 197 | 198 | 199 | 200 | R0.10a (January 15, 2014) 201 | 202 | Added arbitrary strings as drive number in the path name. (_STR_VOLUME_ID) 203 | Added a configuration option of minimum sector size. (_MIN_SS) 204 | 2nd argument of f_rename() can have a drive number and it will be ignored. 205 | Fixed f_mount() with forced mount fails when drive number is >= 1. (appeared at R0.10) 206 | Fixed f_close() invalidates the file object without volume lock. 207 | Fixed f_closedir() returns but the volume lock is left acquired. (appeared at R0.10) 208 | Fixed creation of an entry with LFN fails on too many SFN collisions. (appeared at R0.07) 209 | 210 | 211 | 212 | R0.10b (May 19, 2014) 213 | 214 | Fixed a hard error in the disk I/O layer can collapse the directory entry. 215 | Fixed LFN entry is not deleted when delete/rename an object with lossy converted SFN. (appeared at R0.07) 216 | 217 | 218 | 219 | R0.10c (November 09, 2014) 220 | 221 | Added a configuration option for the platforms without RTC. (_FS_NORTC) 222 | Changed option name _USE_ERASE to _USE_TRIM. 223 | Fixed volume label created by Mac OS X cannot be retrieved with f_getlabel(). (appeared at R0.09b) 224 | Fixed a potential problem of FAT access that can appear on disk error. 225 | Fixed null pointer dereference on attempting to delete the root direcotry. (appeared at R0.08) 226 | 227 | 228 | 229 | R0.11 (February 09, 2015) 230 | 231 | Added f_findfirst(), f_findnext() and f_findclose(). (_USE_FIND) 232 | Fixed f_unlink() does not remove cluster chain of the file. (appeared at R0.10c) 233 | Fixed _FS_NORTC option does not work properly. (appeared at R0.10c) 234 | 235 | 236 | 237 | R0.11a (September 05, 2015) 238 | 239 | Fixed wrong media change can lead a deadlock at thread-safe configuration. 240 | Added code page 771, 860, 861, 863, 864, 865 and 869. (_CODE_PAGE) 241 | Removed some code pages actually not exist on the standard systems. (_CODE_PAGE) 242 | Fixed errors in the case conversion teble of code page 437 and 850 (ff.c). 243 | Fixed errors in the case conversion teble of Unicode (cc*.c). 244 | 245 | 246 | 247 | R0.12 (April 12, 2016) 248 | 249 | Added support for exFAT file system. (_FS_EXFAT) 250 | Added f_expand(). (_USE_EXPAND) 251 | Changed some members in FINFO structure and behavior of f_readdir(). 252 | Added an option _USE_CHMOD. 253 | Removed an option _WORD_ACCESS. 254 | Fixed errors in the case conversion table of Unicode (cc*.c). 255 | 256 | 257 | 258 | R0.12a (July 10, 2016) 259 | 260 | Added support for creating exFAT volume with some changes of f_mkfs(). 261 | Added a file open method FA_OPEN_APPEND. An f_lseek() following f_open() is no longer needed. 262 | f_forward() is available regardless of _FS_TINY. 263 | Fixed f_mkfs() creates wrong volume. (appeared at R0.12) 264 | Fixed wrong memory read in create_name(). (appeared at R0.12) 265 | Fixed compilation fails at some configurations, _USE_FASTSEEK and _USE_FORWARD. 266 | 267 | 268 | 269 | R0.12b (September 04, 2016) 270 | 271 | Made f_rename() be able to rename objects with the same name but case. 272 | Fixed an error in the case conversion teble of code page 866. (ff.c) 273 | Fixed writing data is truncated at the file offset 4GiB on the exFAT volume. (appeared at R0.12) 274 | Fixed creating a file in the root directory of exFAT volume can fail. (appeared at R0.12) 275 | Fixed f_mkfs() creating exFAT volume with too small cluster size can collapse unallocated memory. (appeared at R0.12) 276 | Fixed wrong object name can be returned when read directory at Unicode cfg. (appeared at R0.12) 277 | Fixed large file allocation/removing on the exFAT volume collapses allocation bitmap. (appeared at R0.12) 278 | Fixed some internal errors in f_expand() and f_lseek(). (appeared at R0.12) 279 | 280 | 281 | 282 | R0.12c (March 04, 2017) 283 | 284 | Improved write throughput at the fragmented file on the exFAT volume. 285 | Made memory usage for exFAT be able to be reduced as decreasing _MAX_LFN. 286 | Fixed successive f_getfree() can return wrong count on the FAT12/16 volume. (appeared at R0.12) 287 | Fixed configuration option _VOLUMES cannot be set 10. (appeared at R0.10c) 288 | 289 | 290 | 291 | R0.13 (May 21, 2017) 292 | 293 | Changed heading character of configuration keywords "_" to "FF_". 294 | Removed ASCII-only configuration, FF_CODE_PAGE = 1. Use FF_CODE_PAGE = 437 instead. 295 | Added f_setcp(), run-time code page configuration. (FF_CODE_PAGE = 0) 296 | Improved cluster allocation time on stretch a deep buried cluster chain. 297 | Improved processing time of f_mkdir() with large cluster size by using FF_USE_LFN = 3. 298 | Improved NoFatChain flag of the fragmented file to be set after it is truncated and got contiguous. 299 | Fixed archive attribute is left not set when a file on the exFAT volume is renamed. (appeared at R0.12) 300 | Fixed exFAT FAT entry can be collapsed when write or lseek operation to the existing file is done. (appeared at R0.12c) 301 | Fixed creating a file can fail when a new cluster allocation to the exFAT directory occures. (appeared at R0.12c) 302 | 303 | 304 | 305 | R0.13a (October 14, 2017) 306 | 307 | Added support for UTF-8 encoding on the API. (FF_LFN_UNICODE = 2) 308 | Added options for file name output buffer. (FF_LFN_BUF, FF_SFN_BUF). 309 | Added dynamic memory allocation option for working buffer of f_mkfs() and f_fdisk(). 310 | Fixed f_fdisk() and f_mkfs() create the partition table with wrong CHS parameters. (appeared at R0.09) 311 | Fixed f_unlink() can cause lost clusters at fragmented file on the exFAT volume. (appeared at R0.12c) 312 | Fixed f_setlabel() rejects some valid characters for exFAT volume. (appeared at R0.12) 313 | 314 | 315 | -------------------------------------------------------------------------------- /src/halconf.h: -------------------------------------------------------------------------------- 1 | /* 2 | ChibiOS/RT - Copyright (C) 2006,2007,2008,2009,2010, 3 | 2011,2012 Giovanni Di Sirio. 4 | 5 | This file is part of ChibiOS/RT. 6 | 7 | ChibiOS/RT is free software; you can redistribute it and/or modify 8 | it under the terms of the GNU General Public License as published by 9 | the Free Software Foundation; either version 3 of the License, or 10 | (at your option) any later version. 11 | 12 | ChibiOS/RT is distributed in the hope that it will be useful, 13 | but WITHOUT ANY WARRANTY; without even the implied warranty of 14 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 15 | GNU General Public License for more details. 16 | 17 | You should have received a copy of the GNU General Public License 18 | along with this program. If not, see . 19 | */ 20 | 21 | /** 22 | * @file ARM11-BCM2835-GCC/halconf.h 23 | * @brief HAL configuration header. 24 | * @details HAL configuration file, this file allows to enable or disable the 25 | * various device drivers from your application. You may also use 26 | * this file in order to override the device drivers default settings. 27 | * 28 | * @addtogroup HAL_CONF 29 | * @{ 30 | */ 31 | 32 | #ifndef _HALCONF_H_ 33 | #define _HALCONF_H_ 34 | 35 | #include "mcuconf.h" 36 | 37 | /** 38 | * @brief Enables the TM subsystem. 39 | */ 40 | #if !defined(HAL_USE_TM) || defined(__DOXYGEN__) 41 | #define HAL_USE_TM TRUE 42 | #endif 43 | 44 | /** 45 | * @brief Enables the PAL subsystem. 46 | */ 47 | #if !defined(HAL_USE_PAL) || defined(__DOXYGEN__) 48 | #define HAL_USE_PAL TRUE 49 | #endif 50 | 51 | /** 52 | * @brief Enables the ADC subsystem. 53 | */ 54 | #if !defined(HAL_USE_ADC) || defined(__DOXYGEN__) 55 | #define HAL_USE_ADC FALSE 56 | #endif 57 | 58 | /** 59 | * @brief Enables the CAN subsystem. 60 | */ 61 | #if !defined(HAL_USE_CAN) || defined(__DOXYGEN__) 62 | #define HAL_USE_CAN FALSE 63 | #endif 64 | 65 | /** 66 | * @brief Enables the EXT subsystem. 67 | */ 68 | #if !defined(HAL_USE_EXT) || defined(__DOXYGEN__) 69 | #define HAL_USE_EXT FALSE 70 | #endif 71 | 72 | /** 73 | * @brief Enables the GPT subsystem. 74 | */ 75 | #if !defined(HAL_USE_GPT) || defined(__DOXYGEN__) 76 | #define HAL_USE_GPT FALSE 77 | #endif 78 | 79 | /** 80 | * @brief Enables the I2C subsystem. 81 | */ 82 | #if !defined(HAL_USE_I2C) || defined(__DOXYGEN__) 83 | #define HAL_USE_I2C TRUE 84 | #endif 85 | 86 | /** 87 | * @brief Enables the ICU subsystem. 88 | */ 89 | #if !defined(HAL_USE_ICU) || defined(__DOXYGEN__) 90 | #define HAL_USE_ICU FALSE 91 | #endif 92 | 93 | /** 94 | * @brief Enables the MAC subsystem. 95 | */ 96 | #if !defined(HAL_USE_MAC) || defined(__DOXYGEN__) 97 | #define HAL_USE_MAC FALSE 98 | #endif 99 | 100 | /** 101 | * @brief Enables the MMC_SPI subsystem. 102 | */ 103 | #if !defined(HAL_USE_MMC_SPI) || defined(__DOXYGEN__) 104 | #define HAL_USE_MMC_SPI FALSE 105 | #endif 106 | 107 | /** 108 | * @brief Enables the PWM subsystem. 109 | */ 110 | #if !defined(HAL_USE_PWM) || defined(__DOXYGEN__) 111 | #define HAL_USE_PWM FALSE 112 | #endif 113 | 114 | /** 115 | * @brief Enables the RTC subsystem. 116 | */ 117 | #if !defined(HAL_USE_RTC) || defined(__DOXYGEN__) 118 | #define HAL_USE_RTC FALSE 119 | #endif 120 | 121 | /** 122 | * @brief Enables the SDC subsystem. 123 | */ 124 | #if !defined(HAL_USE_SDC) || defined(__DOXYGEN__) 125 | #define HAL_USE_SDC TRUE 126 | #endif 127 | 128 | /** 129 | * @brief Enables the SERIAL subsystem. 130 | */ 131 | #if !defined(HAL_USE_SERIAL) || defined(__DOXYGEN__) 132 | #define HAL_USE_SERIAL TRUE 133 | #endif 134 | 135 | /** 136 | * @brief Enables the SERIAL over USB subsystem. 137 | */ 138 | #if !defined(HAL_USE_SERIAL_USB) || defined(__DOXYGEN__) 139 | #define HAL_USE_SERIAL_USB FALSE 140 | #endif 141 | 142 | /** 143 | * @brief Enables the SPI subsystem. 144 | */ 145 | #if !defined(HAL_USE_SPI) || defined(__DOXYGEN__) 146 | #define HAL_USE_SPI TRUE 147 | #endif 148 | 149 | /** 150 | * @brief Enables the UART subsystem. 151 | */ 152 | #if !defined(HAL_USE_UART) || defined(__DOXYGEN__) 153 | #define HAL_USE_UART FALSE 154 | #endif 155 | 156 | /** 157 | * @brief Enables the USB subsystem. 158 | */ 159 | #if !defined(HAL_USE_USB) || defined(__DOXYGEN__) 160 | #define HAL_USE_USB FALSE 161 | #endif 162 | 163 | /*===========================================================================*/ 164 | /* ADC driver related settings. */ 165 | /*===========================================================================*/ 166 | 167 | /** 168 | * @brief Enables synchronous APIs. 169 | * @note Disabling this option saves both code and data space. 170 | */ 171 | #if !defined(ADC_USE_WAIT) || defined(__DOXYGEN__) 172 | #define ADC_USE_WAIT TRUE 173 | #endif 174 | 175 | /** 176 | * @brief Enables the @p adcAcquireBus() and @p adcReleaseBus() APIs. 177 | * @note Disabling this option saves both code and data space. 178 | */ 179 | #if !defined(ADC_USE_MUTUAL_EXCLUSION) || defined(__DOXYGEN__) 180 | #define ADC_USE_MUTUAL_EXCLUSION TRUE 181 | #endif 182 | 183 | /*===========================================================================*/ 184 | /* CAN driver related settings. */ 185 | /*===========================================================================*/ 186 | 187 | /** 188 | * @brief Sleep mode related APIs inclusion switch. 189 | */ 190 | #if !defined(CAN_USE_SLEEP_MODE) || defined(__DOXYGEN__) 191 | #define CAN_USE_SLEEP_MODE TRUE 192 | #endif 193 | 194 | /*===========================================================================*/ 195 | /* I2C driver related settings. */ 196 | /*===========================================================================*/ 197 | 198 | /** 199 | * @brief Enables the mutual exclusion APIs on the I2C bus. 200 | */ 201 | #if !defined(I2C_USE_MUTUAL_EXCLUSION) || defined(__DOXYGEN__) 202 | #define I2C_USE_MUTUAL_EXCLUSION TRUE 203 | #endif 204 | 205 | /*===========================================================================*/ 206 | /* MAC driver related settings. */ 207 | /*===========================================================================*/ 208 | 209 | /** 210 | * @brief Enables an event sources for incoming packets. 211 | */ 212 | #if !defined(MAC_USE_EVENTS) || defined(__DOXYGEN__) 213 | #define MAC_USE_EVENTS TRUE 214 | #endif 215 | 216 | /*===========================================================================*/ 217 | /* MMC_SPI driver related settings. */ 218 | /*===========================================================================*/ 219 | 220 | /** 221 | * @brief Block size for MMC transfers. 222 | */ 223 | #if !defined(MMC_SECTOR_SIZE) || defined(__DOXYGEN__) 224 | #define MMC_SECTOR_SIZE 512 225 | #endif 226 | 227 | /** 228 | * @brief Delays insertions. 229 | * @details If enabled this options inserts delays into the MMC waiting 230 | * routines releasing some extra CPU time for the threads with 231 | * lower priority, this may slow down the driver a bit however. 232 | * This option is recommended also if the SPI driver does not 233 | * use a DMA channel and heavily loads the CPU. 234 | */ 235 | #if !defined(MMC_NICE_WAITING) || defined(__DOXYGEN__) 236 | #define MMC_NICE_WAITING TRUE 237 | #endif 238 | 239 | /** 240 | * @brief Number of positive insertion queries before generating the 241 | * insertion event. 242 | */ 243 | #if !defined(MMC_POLLING_INTERVAL) || defined(__DOXYGEN__) 244 | #define MMC_POLLING_INTERVAL 10 245 | #endif 246 | 247 | /** 248 | * @brief Interval, in milliseconds, between insertion queries. 249 | */ 250 | #if !defined(MMC_POLLING_DELAY) || defined(__DOXYGEN__) 251 | #define MMC_POLLING_DELAY 10 252 | #endif 253 | 254 | /** 255 | * @brief Uses the SPI polled API for small data transfers. 256 | * @details Polled transfers usually improve performance because it 257 | * saves two context switches and interrupt servicing. Note 258 | * that this option has no effect on large transfers which 259 | * are always performed using DMAs/IRQs. 260 | */ 261 | #if !defined(MMC_USE_SPI_POLLING) || defined(__DOXYGEN__) 262 | #define MMC_USE_SPI_POLLING TRUE 263 | #endif 264 | 265 | /*===========================================================================*/ 266 | /* SDC driver related settings. */ 267 | /*===========================================================================*/ 268 | 269 | /** 270 | * @brief Number of initialization attempts before rejecting the card. 271 | * @note Attempts are performed at 10mS intervals. 272 | */ 273 | #if !defined(SDC_INIT_RETRY) || defined(__DOXYGEN__) 274 | #define SDC_INIT_RETRY 100 275 | #endif 276 | 277 | /** 278 | * @brief Include support for MMC cards. 279 | * @note MMC support is not yet implemented so this option must be kept 280 | * at @p FALSE. 281 | */ 282 | #if !defined(SDC_MMC_SUPPORT) || defined(__DOXYGEN__) 283 | #define SDC_MMC_SUPPORT FALSE 284 | #endif 285 | 286 | /** 287 | * @brief Delays insertions. 288 | * @details If enabled this options inserts delays into the MMC waiting 289 | * routines releasing some extra CPU time for the threads with 290 | * lower priority, this may slow down the driver a bit however. 291 | */ 292 | #if !defined(SDC_NICE_WAITING) || defined(__DOXYGEN__) 293 | #define SDC_NICE_WAITING TRUE 294 | #endif 295 | 296 | /*===========================================================================*/ 297 | /* SERIAL driver related settings. */ 298 | /*===========================================================================*/ 299 | 300 | /** 301 | * @brief Default bit rate. 302 | * @details Configuration parameter, this is the baud rate selected for the 303 | * default configuration. 304 | */ 305 | #if !defined(SERIAL_DEFAULT_BITRATE) || defined(__DOXYGEN__) 306 | #define SERIAL_DEFAULT_BITRATE 38400 307 | #endif 308 | 309 | /** 310 | * @brief Serial buffers size. 311 | * @details Configuration parameter, you can change the depth of the queue 312 | * buffers depending on the requirements of your application. 313 | * @note The default is 64 bytes for both the transmission and receive 314 | * buffers. 315 | */ 316 | #if !defined(SERIAL_BUFFERS_SIZE) || defined(__DOXYGEN__) 317 | #define SERIAL_BUFFERS_SIZE 2048 318 | #endif 319 | 320 | /*===========================================================================*/ 321 | /* SPI driver related settings. */ 322 | /*===========================================================================*/ 323 | 324 | /** 325 | * @brief Enables synchronous APIs. 326 | * @note Disabling this option saves both code and data space. 327 | */ 328 | #if !defined(SPI_USE_WAIT) || defined(__DOXYGEN__) 329 | #define SPI_USE_WAIT TRUE 330 | #endif 331 | 332 | /** 333 | * @brief Enables the @p spiAcquireBus() and @p spiReleaseBus() APIs. 334 | * @note Disabling this option saves both code and data space. 335 | */ 336 | #if !defined(SPI_USE_MUTUAL_EXCLUSION) || defined(__DOXYGEN__) 337 | #define SPI_USE_MUTUAL_EXCLUSION TRUE 338 | #endif 339 | 340 | #endif /* _HALCONF_H_ */ 341 | 342 | /** @} */ 343 | -------------------------------------------------------------------------------- /src/pi/i2c_lld.c: -------------------------------------------------------------------------------- 1 | /* 2 | ChibiOS/RT - Copyright (C) 2006,2007,2008,2009,2010, 3 | 2011,2012 Giovanni Di Sirio. 4 | 5 | This file is part of ChibiOS/RT. 6 | 7 | ChibiOS/RT is free software; you can redistribute it and/or modify 8 | it under the terms of the GNU General Public License as published by 9 | the Free Software Foundation; either version 3 of the License, or 10 | (at your option) any later version. 11 | 12 | ChibiOS/RT is distributed in the hope that it will be useful, 13 | but WITHOUT ANY WARRANTY; without even the implied warranty of 14 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 15 | GNU General Public License for more details. 16 | 17 | You should have received a copy of the GNU General Public License 18 | along with this program. If not, see . 19 | 20 | 2018, Rob Reilink: 21 | - fixed: hang for transfers with read > ~30 bytes 22 | - enable interrupts on lld_init 23 | - support multiple I2C peripherals 24 | 25 | */ 26 | 27 | /** 28 | * @file BCM2835/i2c_lld.c 29 | * @brief I2C Driver subsystem low level driver source template. 30 | * 31 | * @addtogroup I2C 32 | * @{ 33 | */ 34 | 35 | #include "ch.h" 36 | #include "hal.h" 37 | 38 | #if HAL_USE_I2C || defined(__DOXYGEN__) 39 | 40 | /*===========================================================================*/ 41 | /* Driver local definitions. */ 42 | /*===========================================================================*/ 43 | 44 | /*===========================================================================*/ 45 | /* Driver exported variables. */ 46 | /*===========================================================================*/ 47 | 48 | I2CDriver I2C0; 49 | I2CDriver I2C1; 50 | 51 | /*===========================================================================*/ 52 | /* Driver local variables. */ 53 | /*===========================================================================*/ 54 | 55 | /*===========================================================================*/ 56 | /* Driver local functions. */ 57 | /*===========================================================================*/ 58 | 59 | /** 60 | * @brief Wakes up the waiting thread. 61 | * 62 | * @param[in] i2cp pointer to the @p I2CDriver object 63 | * @param[in] msg wakeup message 64 | * 65 | * @notapi 66 | */ 67 | #define wakeup_isr(i2cp, msg) { \ 68 | chSysLockFromIsr(); \ 69 | if ((i2cp)->thread != NULL) { \ 70 | Thread *tp = (i2cp)->thread; \ 71 | (i2cp)->thread = NULL; \ 72 | tp->p_u.rdymsg = (msg); \ 73 | chSchReadyI(tp); \ 74 | } \ 75 | chSysUnlockFromIsr(); \ 76 | } 77 | 78 | /** 79 | * @brief Handling of stalled I2C transactions. 80 | * 81 | * @param[in] i2cp pointer to the @p I2CDriver object 82 | * 83 | * @notapi 84 | */ 85 | static void i2c_lld_safety_timeout(void *p) { 86 | I2CDriver *i2cp = (I2CDriver *)p; 87 | 88 | chSysLockFromIsr(); 89 | if (i2cp->thread) { 90 | bscdevice_t *device = i2cp->device; 91 | 92 | i2cp->errors |= I2CD_TIMEOUT; 93 | if (device->status & BSC_CLKT) 94 | i2cp->errors |= I2CD_BUS_ERROR; 95 | if (device->status & BSC_ERR) 96 | i2cp->errors |= I2CD_ACK_FAILURE; 97 | 98 | device->control = 0; 99 | device->status = BSC_CLKT | BSC_ERR | BSC_DONE; 100 | 101 | Thread *tp = i2cp->thread; 102 | i2cp->thread = NULL; 103 | tp->p_u.rdymsg = RDY_TIMEOUT; 104 | chSchReadyI(tp); 105 | } 106 | chSysUnlockFromIsr(); 107 | } 108 | 109 | /*===========================================================================*/ 110 | /* Driver interrupt handlers. */ 111 | /*===========================================================================*/ 112 | 113 | #define NUM_I2C_PERIPHERALS 2 114 | 115 | static void serve_interrupt(void *dummy) { 116 | (void) dummy; 117 | 118 | I2CDriver *drivers[NUM_I2C_PERIPHERALS] = {&I2C0, &I2C1}; 119 | 120 | // All I2C peripherals share one interrupt. Iterate over all peripherals to 121 | // handle their status 122 | for (int i = 0;istate == I2C_UNINIT || i2cp->state == I2C_STOP) { 127 | continue; // short-cut: skip this peripheral since it is not active 128 | } 129 | 130 | bscdevice_t *device = i2cp->device; 131 | uint32_t status = device->status; 132 | 133 | if (status & (BSC_CLKT | BSC_ERR)) { 134 | wakeup_isr(i2cp, RDY_RESET); 135 | // Clear error flags and done bit 136 | device->status = BSC_CLKT | BSC_ERR | BSC_DONE; 137 | } 138 | else if (status & BSC_DONE) { 139 | while ((status & BSC_RXD) && (i2cp->rxidx < i2cp->rxbytes)) 140 | i2cp->rxbuf[i2cp->rxidx++] = device->dataFifo; 141 | device->control = 0; 142 | device->status = BSC_CLKT | BSC_ERR | BSC_DONE; 143 | wakeup_isr(i2cp, RDY_OK); 144 | } 145 | else { 146 | if (device->status & BSC_TXW) { 147 | while ((i2cp->txidx < i2cp->txbytes) && (device->status & BSC_TXD)) 148 | device->dataFifo = i2cp->txbuf[i2cp->txidx++]; 149 | } 150 | if (device->status & BSC_RXR) { 151 | while ((i2cp->rxidx < i2cp->rxbytes) && (device->status & BSC_RXD)) 152 | i2cp->rxbuf[i2cp->rxidx++] = device->dataFifo; 153 | } 154 | } 155 | } 156 | } 157 | 158 | /*===========================================================================*/ 159 | /* Driver exported functions. */ 160 | /*===========================================================================*/ 161 | 162 | /** 163 | * @brief Low level I2C driver initialization. 164 | * 165 | * @notapi 166 | */ 167 | void i2c_lld_init(void) { 168 | I2C0.device = BSC0_ADDR; 169 | I2C0.scl_pin = GPIO0_PAD; 170 | I2C0.sda_pin = GPIO1_PAD; 171 | I2C0.alt_function = GPFN_ALT0; 172 | i2cObjectInit(&I2C0); 173 | 174 | I2C1.device = BSC1_ADDR; 175 | I2C1.scl_pin = GPIO2_PAD; 176 | I2C1.sda_pin = GPIO3_PAD; 177 | I2C1.alt_function = GPFN_ALT0; 178 | i2cObjectInit(&I2C1); 179 | } 180 | 181 | /** 182 | * @brief Configures and activates the I2C peripheral. 183 | * 184 | * @param[in] i2cp pointer to the @p I2CDriver object 185 | * 186 | * @notapi 187 | */ 188 | void i2c_lld_start(I2CDriver *i2cp) { 189 | /* Set up GPIO pins for I2C */ 190 | bcm2835_gpio_fnsel(i2cp->scl_pin, i2cp->alt_function); 191 | bcm2835_gpio_fnsel(i2cp->sda_pin, i2cp->alt_function); 192 | 193 | uint32_t speed = i2cp->config->ic_speed; 194 | if (speed != 0) 195 | i2cp->device->clockDivider = BSC_CLOCK_FREQ / i2cp->config->ic_speed; 196 | 197 | i2cp->device->control |= BSC_I2CEN; 198 | 199 | // register interrupt handler and enable interrupt 200 | hal_register_interrupt(53, serve_interrupt, NULL); 201 | IRQ_ENABLE2 = (1<<(53-32)); 202 | } 203 | 204 | /** 205 | * @brief Deactivates the I2C peripheral. 206 | * 207 | * @param[in] i2cp pointer to the @p I2CDriver object 208 | * 209 | * @notapi 210 | */ 211 | void i2c_lld_stop(I2CDriver *i2cp) { 212 | /* Set GPIO pin function to default */ 213 | bcm2835_gpio_fnsel(i2cp->scl_pin, GPFN_IN); 214 | bcm2835_gpio_fnsel(i2cp->sda_pin, GPFN_IN); 215 | 216 | i2cp->device->control &= ~BSC_I2CEN; 217 | } 218 | 219 | /** 220 | * @brief Master transmission. 221 | * 222 | * @param[in] i2cp pointer to the @p I2CDriver object 223 | * @param[in] addr slave device address (7 bits) without R/W bit 224 | * @param[in] txbuf transmit data buffer pointer 225 | * @param[in] txbytes number of bytes to be transmitted 226 | * @param[out] rxbuf receive data buffer pointer 227 | * @param[in] rxbytes number of bytes to be received 228 | * @param[in] timeout the number of ticks before the operation timeouts, 229 | * the following special values are allowed: 230 | * - @a TIME_INFINITE no timeout. 231 | * . 232 | * 233 | * @notapi 234 | */ 235 | msg_t i2c_lld_master_transmit_timeout(I2CDriver *i2cp, i2caddr_t addr, 236 | const uint8_t *txbuf, size_t txbytes, 237 | uint8_t *rxbuf, const uint8_t rxbytes, 238 | systime_t timeout) { 239 | VirtualTimer vt; 240 | 241 | /* Global timeout for the whole operation.*/ 242 | if (timeout != TIME_INFINITE) 243 | chVTSetI(&vt, timeout, i2c_lld_safety_timeout, (void *)i2cp); 244 | 245 | i2cp->addr = addr; 246 | i2cp->txbuf = txbuf; 247 | i2cp->txbytes = txbytes; 248 | i2cp->txidx = 0; 249 | i2cp->rxbuf = rxbuf; 250 | i2cp->rxbytes = rxbytes; 251 | i2cp->rxidx = 0; 252 | 253 | bscdevice_t *device = i2cp->device; 254 | device->slaveAddress = addr; 255 | device->dataLength = txbytes; 256 | device->status = CLEAR_STATUS; 257 | 258 | /* Enable Interrupts and start transfer.*/ 259 | device->control |= (BSC_INTT | BSC_INTD | START_WRITE); 260 | 261 | 262 | i2cp->thread = chThdSelf(); 263 | chSchGoSleepS(THD_STATE_SUSPENDED); 264 | if ((timeout != TIME_INFINITE) && chVTIsArmedI(&vt)) 265 | chVTResetI(&vt); 266 | 267 | 268 | msg_t status = chThdSelf()->p_u.rdymsg; 269 | 270 | if (status == RDY_OK && rxbytes > 0) { 271 | /* The TIMEOUT_INFINITE prevents receive from setting up it's own timer.*/ 272 | status = i2c_lld_master_receive_timeout(i2cp, addr, rxbuf, 273 | rxbytes, TIME_INFINITE); 274 | if ((timeout != TIME_INFINITE) && chVTIsArmedI(&vt)) 275 | chVTResetI(&vt); 276 | } 277 | 278 | return status; 279 | } 280 | 281 | 282 | /** 283 | * @brief Master receive. 284 | * 285 | * @param[in] i2cp pointer to the @p I2CDriver object 286 | * @param[in] addr slave device address (7 bits) without R/W bit 287 | * @param[out] rxbuf receive data buffer pointer 288 | * @param[in] rxbytes number of bytes to be received 289 | * @param[in] timeout the number of ticks before the operation timeouts, 290 | * the following special values are allowed: 291 | * - @a TIME_INFINITE no timeout. 292 | * . 293 | * 294 | * @notapi 295 | */ 296 | msg_t i2c_lld_master_receive_timeout(I2CDriver *i2cp, i2caddr_t addr, 297 | uint8_t *rxbuf, size_t rxbytes, 298 | systime_t timeout) { 299 | VirtualTimer vt; 300 | 301 | /* Global timeout for the whole operation.*/ 302 | if (timeout != TIME_INFINITE) 303 | chVTSetI(&vt, timeout, i2c_lld_safety_timeout, (void *)i2cp); 304 | 305 | i2cp->addr = addr; 306 | i2cp->txbuf = NULL; 307 | i2cp->txbytes = 0; 308 | i2cp->txidx = 0; 309 | i2cp->rxbuf = rxbuf; 310 | i2cp->rxbytes = rxbytes; 311 | i2cp->rxidx = 0; 312 | 313 | /* Setup device.*/ 314 | bscdevice_t *device = i2cp->device; 315 | device->slaveAddress = addr; 316 | device->dataLength = rxbytes; 317 | device->status = CLEAR_STATUS; 318 | 319 | /* Enable Interrupts and start transfer.*/ 320 | device->control = (BSC_INTR | BSC_INTD | START_READ); 321 | 322 | i2cp->thread = chThdSelf(); 323 | chSchGoSleepS(THD_STATE_SUSPENDED); 324 | if ((timeout != TIME_INFINITE) && chVTIsArmedI(&vt)) 325 | chVTResetI(&vt); 326 | 327 | return chThdSelf()->p_u.rdymsg; 328 | } 329 | 330 | #endif /* HAL_USE_I2C */ 331 | 332 | /** @} */ 333 | -------------------------------------------------------------------------------- /src/pi/sdc_lld.c: -------------------------------------------------------------------------------- 1 | 2 | /* ChibiOS SDC low-level driver for BCM2835 eMMC peripheral 3 | * 4 | * Rob Reilink, 2017 5 | * 6 | * References: 7 | * https://github.com/raspberrypi/linux/blob/rpi-4.9.y/drivers/mmc/host/sdhci.h 8 | * https://github.com/jncronin/rpi-boot/blob/master/emmc.c 9 | * Broadcom BCM2835 Peripherals Guide 10 | */ 11 | 12 | 13 | #include "ch.h" 14 | #include "hal.h" 15 | #include "sdc.h" 16 | #include "sdc_lld.h" 17 | #include "chtypes.h" 18 | #include "bcm2835.h" 19 | #include "bcmmailbox.h" 20 | 21 | #include 22 | 23 | SDCDriver SDCD1; 24 | 25 | #define EMMC_ARG2 REG(0x20300000) 26 | #define EMMC_BLKSIZECNT REG(0x20300004) 27 | #define EMMC_ARG1 REG(0x20300008) 28 | #define EMMC_CMDTM REG(0x2030000C) 29 | #define EMMC_RESP0 REG(0x20300010) 30 | #define EMMC_RESP1 REG(0x20300014) 31 | #define EMMC_RESP2 REG(0x20300018) 32 | #define EMMC_RESP3 REG(0x2030001C) 33 | #define EMMC_DATA REG(0x20300020) 34 | #define EMMC_STATUS REG(0x20300024) 35 | #define EMMC_CONTROL0 REG(0x20300028) 36 | #define EMMC_CONTROL1 REG(0x2030002C) 37 | #define EMMC_INTERRUPT REG(0x20300030) 38 | #define EMMC_IRPT_MASK REG(0x20300034) 39 | #define EMMC_IRPT_EN REG(0x20300038) 40 | #define EMMC_CONTROL2 REG(0x2030003C) 41 | #define EMMC_FORCE_IRPT REG(0x20300050) 42 | #define EMMC_BOOT_TIMEOUT REG(0x20300070) 43 | #define EMMC_DBG_SEL REG(0x20300074) 44 | #define EMMC_EXRDFIFO_CFG REG(0x20300080) 45 | #define EMMC_EXRDFIFO_EN REG(0x20300084) 46 | #define EMMC_TUNE_STEP REG(0x20300088) 47 | #define EMMC_TUNE_STEPS_STD REG(0x2030008C) 48 | #define EMMC_TUNE_STEPS_DDR REG(0x20300090) 49 | #define EMMC_SPI_INT_SPT REG(0x203000F0) 50 | #define EMMC_SLOTISR_VER REG(0x203000FC) 51 | 52 | #define INTERRUPT_ERR BIT(15) 53 | #define INTERRUPT_READ_RDY BIT(5) 54 | #define INTERRUPT_WRITE_RDY BIT(4) 55 | #define INTERRUPT_DATA_DONE BIT(1) 56 | #define INTERRUPT_CMD_DONE BIT(0) 57 | #define INTERRUPT_ALL 0x017ff137 // all interrupts which are defined 58 | #define INTERRUPT_ALLERRORS 0x017f8000 // all error interrupts which are defined (including INTERRUPT_ERR) 59 | 60 | #define CONTROL0_HCTL_8BIT BIT(5) 61 | #define CONTROL0_HCTL_HS_EN BIT(2) 62 | #define CONTROL0_HCTL_DWIDTH BIT(1) 63 | 64 | #define CONTROL1_SRST_DATA BIT(26) 65 | #define CONTROL1_SRST_CMD BIT(25) 66 | #define CONTROL1_SRST_HC BIT(24) 67 | 68 | #define CONTROL1_DATA_TOUNIT(x) (((x)&0x0f)<<16) 69 | #define CONTROL1_CLK_FREQ_8(x) (((x)&0x03)<<8) //divider bits 7..0 70 | #define CONTROL1_CLK_FREQ_MS2(x) (((x)&0xff)<<6) //divider bits 9..8 71 | #define CONTROL1_CLK_GENSEL BIT(5) 72 | #define CONTROL1_CLK_EN BIT(2) // clock to card enable 73 | #define CONTROL1_CLK_STABLE BIT(1) 74 | #define CONTROL1_CLK_INTLEN BIT(0) // internal clock enable 75 | 76 | #define STATUS_DAT_INHIBIT BIT(1) 77 | #define STATUS_CMD_INHIBIT BIT(0) 78 | 79 | #define CMDTM_CMD_ISDATA BIT(21) 80 | #define CMDTM_CMD_CRCCHK_EN BIT(19) 81 | #define CMDTM_CMD_RSPNS_TYPE (3<<16) 82 | #define CMDTM_CMD_RSPNS_TYPE_NONE (0<<16) 83 | #define CMDTM_CMD_RSPNS_TYPE_136 (1<<16) 84 | #define CMDTM_CMD_RSPNS_TYPE_48 (2<<16) 85 | #define CMDTM_CMD_RSPNS_TYPE_48b (3<<16) 86 | #define CMDTM_TM_MULTIBLOCK BIT(5) 87 | #define CMDTM_TM_DAT_DIR BIT(4) 88 | #define CMDTM_TM_AUTO_CMD_EN_CMD12 (1<<2) 89 | #define CMDTM_TM_AUTO_CMD_EN_CMD23 (2<<2) 90 | #define CMDTM_TM_BLKCNT_EN BIT(1) 91 | 92 | 93 | 94 | #define SDC_START_CLOCKRATE 400000 95 | #define SDC_DATA_CLOCKRATE 25000000 96 | 97 | static int switch_clockrate(int rate, int baseclock) { 98 | int divider; 99 | 100 | divider = -(-baseclock / rate); // 2x - causes round-up instead of round-down 101 | if (divider == 0) divider = 1; 102 | if (divider > 0x3ff) divider = 0x3ff; 103 | 104 | // Wait for transfer complete 105 | while (EMMC_STATUS & (STATUS_DAT_INHIBIT | STATUS_CMD_INHIBIT)); 106 | 107 | EMMC_CONTROL1 &=~ CONTROL1_CLK_EN; // disable clock to SD card 108 | 109 | // divider must be multiple of 2 according to some sources (e.g. 110 | // comments in the Linux kernel); round up 111 | divider += divider & 1; 112 | 113 | // divider bits 9:8 go into 7:6; bits 7:0 go into 15:8 114 | EMMC_CONTROL1 = (EMMC_CONTROL1 & ~0xffe0) | 115 | CONTROL1_CLK_FREQ_8(divider & 0xff) | 116 | CONTROL1_CLK_FREQ_MS2((divider & 0x300) >> 8); 117 | 118 | while(!(EMMC_CONTROL1 & CONTROL1_CLK_STABLE)) ; // wait to stabilize 119 | 120 | EMMC_CONTROL1 |= CONTROL1_CLK_EN; // enable clock to SD card 121 | 122 | return baseclock / divider; 123 | } 124 | 125 | void sdc_lld_init(void) { 126 | sdcObjectInit(&SDCD1); 127 | } 128 | 129 | 130 | void sdc_lld_start(SDCDriver *sdcp) { 131 | uint32_t tag[2]; 132 | 133 | DataMemBarrier(); 134 | 135 | // Switch GPIO48-53 to ALT3 (SD card). Note: this alternate function is not 136 | // documented in the BCM2835 ARM peripherals manual 137 | 138 | for(int i=48;i<=53;i++) { 139 | bcm2835_gpio_fnsel(i, GPFN_ALT3); 140 | } 141 | 142 | DataMemBarrier(); 143 | 144 | // Switch on power to SD (probably already on from boot, but just to be sure) 145 | tag[0] = 0; //device: SD card 146 | tag[1] = 3; // power on, wait 147 | if (PiPyOS_bcm_get_set_property_tag(0x28001, tag, 8) != 8) { 148 | printf("sdc_lld_start: error powering on eMMC"); 149 | return; 150 | } 151 | 152 | // Get base clock rate (required to calculate clock divider) 153 | tag[0] = 1; //device: SD card 154 | if (PiPyOS_bcm_get_set_property_tag(0x30002, tag, 8) != 8) { 155 | printf("sdc_lld_start: error querying eMMC clock rate"); 156 | return; 157 | } 158 | sdcp->emmc_base_clock_rate = tag[1]; 159 | 160 | // reset host controller; disable clocks 161 | EMMC_CONTROL1 = CONTROL1_SRST_HC; 162 | while(EMMC_CONTROL1 & (CONTROL1_SRST_HC | CONTROL1_SRST_CMD | CONTROL1_SRST_DATA)); //wait while any reset bit is high 163 | 164 | EMMC_CONTROL2 = 0; // reset tuning 165 | 166 | //enable internal clock, set clock rate and enable command timeout 167 | EMMC_CONTROL1 = CONTROL1_CLK_INTLEN; 168 | //switch_clockrate(SDC_CLOCKRATE, emmc_clock_rate); 169 | EMMC_CONTROL1 |= CONTROL1_DATA_TOUNIT(7); // timeout = 2^(7+13) cycles 170 | 171 | EMMC_IRPT_EN = 0; // disable interrupts to ARM 172 | EMMC_IRPT_MASK = INTERRUPT_ALL; //unmask all interrupts 173 | EMMC_INTERRUPT = 0xffffffff; // reset all interrupts 174 | 175 | DataMemBarrier(); 176 | } 177 | 178 | 179 | void sdc_lld_stop(SDCDriver *sdcp) { 180 | 181 | } 182 | 183 | 184 | void sdc_lld_start_clk(SDCDriver *sdcp) { 185 | switch_clockrate(SDC_START_CLOCKRATE, sdcp->emmc_base_clock_rate); 186 | } 187 | 188 | void sdc_lld_set_data_clk(SDCDriver *sdcp) { 189 | switch_clockrate(SDC_DATA_CLOCKRATE, sdcp->emmc_base_clock_rate); 190 | } 191 | 192 | void sdc_lld_stop_clk(SDCDriver *sdcp) { 193 | 194 | } 195 | 196 | void sdc_lld_set_bus_mode(SDCDriver *sdcp, sdcbusmode_t mode) { 197 | 198 | switch (mode) { 199 | case SDC_MODE_1BIT: 200 | EMMC_CONTROL0 = EMMC_CONTROL0 & ~(CONTROL0_HCTL_8BIT | CONTROL0_HCTL_DWIDTH); 201 | break; 202 | case SDC_MODE_4BIT: 203 | EMMC_CONTROL0 = (EMMC_CONTROL0 & ~CONTROL0_HCTL_8BIT) | CONTROL0_HCTL_DWIDTH; 204 | break; 205 | case SDC_MODE_8BIT: 206 | EMMC_CONTROL0 = (EMMC_CONTROL0 & ~CONTROL0_HCTL_DWIDTH) | CONTROL0_HCTL_8BIT; 207 | break; 208 | } 209 | 210 | 211 | } 212 | 213 | /* Common code for all sdc_llc_send_cmd_xxx functions 214 | * 215 | * Returns: CH_SUCCESS on success; CH_FAILED value on error 216 | */ 217 | static uint32_t sdc_lld_send_cmd_x(uint8_t cmd, uint32_t flags, uint32_t arg, uint32_t *resp) { 218 | uint32_t emmc_interrupt; 219 | 220 | DataMemBarrier(); 221 | 222 | EMMC_ARG1 = arg; 223 | 224 | EMMC_CMDTM = flags | (cmd<<24); 225 | 226 | EMMC_INTERRUPT = INTERRUPT_ALL; 227 | 228 | // Wait for completion or for error 229 | // todo: interrupt-based using ChibiOS 230 | //printf("SDC CMD %d ARG %ld...", cmd, arg); 231 | 232 | while(!((emmc_interrupt = EMMC_INTERRUPT) & (INTERRUPT_ERR | INTERRUPT_CMD_DONE))); 233 | 234 | if ((emmc_interrupt & (INTERRUPT_ERR | INTERRUPT_CMD_DONE)) != INTERRUPT_CMD_DONE) { 235 | DataMemBarrier(); 236 | //printf("SDC COMMAND %d FAILED\n", cmd); 237 | return CH_FAILED; //ERR is clear or INTERRUPT_CMD_DONE is not set --> failiure 238 | } 239 | 240 | flags = flags & CMDTM_CMD_RSPNS_TYPE; 241 | 242 | // Read RESPx and store in *resp, depending on response size 243 | if (flags != CMDTM_CMD_RSPNS_TYPE_NONE) { 244 | *resp++ = EMMC_RESP0; 245 | } 246 | 247 | if (flags == CMDTM_CMD_RSPNS_TYPE_136) { 248 | *resp++ = EMMC_RESP1; 249 | *resp++ = EMMC_RESP2; 250 | *resp++ = EMMC_RESP3; 251 | } 252 | 253 | DataMemBarrier(); 254 | return CH_SUCCESS; 255 | } 256 | 257 | 258 | void sdc_lld_send_cmd_none(SDCDriver *sdcp, uint8_t cmd, uint32_t arg) { 259 | sdc_lld_send_cmd_x(cmd, CMDTM_CMD_RSPNS_TYPE_NONE, arg, NULL); 260 | } 261 | 262 | bool_t sdc_lld_send_cmd_short(SDCDriver *sdcp, uint8_t cmd, uint32_t arg, 263 | uint32_t *resp) 264 | { 265 | return sdc_lld_send_cmd_x(cmd, CMDTM_CMD_RSPNS_TYPE_48, arg, resp); 266 | } 267 | 268 | bool_t sdc_lld_send_cmd_short_crc(SDCDriver *sdcp, uint8_t cmd, uint32_t arg, 269 | uint32_t *resp) 270 | { 271 | return sdc_lld_send_cmd_x(cmd, CMDTM_CMD_RSPNS_TYPE_48 | CMDTM_CMD_CRCCHK_EN, arg, resp); 272 | } 273 | bool_t sdc_lld_send_cmd_long_crc(SDCDriver *sdcp, uint8_t cmd, uint32_t arg, 274 | uint32_t *resp) 275 | { 276 | return sdc_lld_send_cmd_x(cmd, CMDTM_CMD_RSPNS_TYPE_136 | CMDTM_CMD_CRCCHK_EN, arg, resp); 277 | } 278 | 279 | bool_t sdc_lld_read(SDCDriver *sdcp, uint32_t startblk, 280 | uint8_t *buf, uint32_t n) 281 | { 282 | uint32_t resp[1]; 283 | uint32_t emmc_interrupt; 284 | uint32_t data; 285 | 286 | DataMemBarrier(); 287 | 288 | 289 | // TODO: also implement multiple-block transfers 290 | while(n) { 291 | EMMC_INTERRUPT = INTERRUPT_ALL; 292 | 293 | EMMC_BLKSIZECNT = (1<<16) | 512; // 1 block of 512 bytes 294 | 295 | if (sdc_lld_send_cmd_x(MMCSD_CMD_READ_SINGLE_BLOCK, CMDTM_CMD_RSPNS_TYPE_48 | CMDTM_CMD_CRCCHK_EN | CMDTM_CMD_ISDATA | CMDTM_TM_DAT_DIR, 296 | startblk, resp) || MMCSD_R1_ERROR(resp[0])) { 297 | printf("Failed\n"); 298 | 299 | return CH_FAILED; 300 | } 301 | 302 | // Wait until READ_RDY or ERROR 303 | while(!((emmc_interrupt = EMMC_INTERRUPT) & (INTERRUPT_ERR | INTERRUPT_READ_RDY))); 304 | if ((emmc_interrupt & (INTERRUPT_ERR | INTERRUPT_READ_RDY)) != INTERRUPT_READ_RDY) { 305 | DataMemBarrier(); 306 | printf("SDC COMMAND READ FAILED\n"); 307 | return CH_FAILED; //ERR is clear or INTERRUPT_READ_RDY is not set --> failiure 308 | } 309 | 310 | for(int i=0;i<128;i++) { 311 | data = EMMC_DATA; 312 | *buf++ = data & 0xff; 313 | *buf++ = (data>>8) & 0xff; 314 | *buf++ = (data>>16) & 0xff; 315 | *buf++ = (data>>24) & 0xff; 316 | } 317 | 318 | startblk++; 319 | n--; 320 | 321 | }; 322 | DataMemBarrier(); 323 | return CH_SUCCESS; 324 | } 325 | 326 | bool_t sdc_lld_write(SDCDriver *sdcp, uint32_t startblk, 327 | const uint8_t *buf, uint32_t n) 328 | { 329 | printf("SDC WRITE not implemented\n"); 330 | 331 | return CH_FAILED; 332 | } 333 | 334 | bool_t sdc_lld_sync(SDCDriver *sdcp) { 335 | printf("SDC SYNC not implemented\n"); 336 | 337 | return CH_FAILED; 338 | } 339 | 340 | bool_t sdc_lld_is_card_inserted(SDCDriver *sdcp) { 341 | return 1; 342 | } 343 | 344 | bool_t sdc_lld_is_write_protected(SDCDriver *sdcp) { 345 | return 1; 346 | } 347 | 348 | -------------------------------------------------------------------------------- /src/ffconf.h: -------------------------------------------------------------------------------- 1 | /*---------------------------------------------------------------------------/ 2 | / FatFs - Configuration file 3 | /---------------------------------------------------------------------------*/ 4 | 5 | #define FFCONF_DEF 89352 /* Revision ID */ 6 | 7 | /*---------------------------------------------------------------------------/ 8 | / Function Configurations 9 | /---------------------------------------------------------------------------*/ 10 | 11 | #define FF_FS_READONLY 1 12 | /* This option switches read-only configuration. (0:Read/Write or 1:Read-only) 13 | / Read-only configuration removes writing API functions, f_write(), f_sync(), 14 | / f_unlink(), f_mkdir(), f_chmod(), f_rename(), f_truncate(), f_getfree() 15 | / and optional writing functions as well. */ 16 | 17 | 18 | #define FF_FS_MINIMIZE 0 19 | /* This option defines minimization level to remove some basic API functions. 20 | / 21 | / 0: Basic functions are fully enabled. 22 | / 1: f_stat(), f_getfree(), f_unlink(), f_mkdir(), f_truncate() and f_rename() 23 | / are removed. 24 | / 2: f_opendir(), f_readdir() and f_closedir() are removed in addition to 1. 25 | / 3: f_lseek() function is removed in addition to 2. */ 26 | 27 | 28 | #define FF_USE_STRFUNC 0 29 | /* This option switches string functions, f_gets(), f_putc(), f_puts() and f_printf(). 30 | / 31 | / 0: Disable string functions. 32 | / 1: Enable without LF-CRLF conversion. 33 | / 2: Enable with LF-CRLF conversion. */ 34 | 35 | 36 | #define FF_USE_FIND 0 37 | /* This option switches filtered directory read functions, f_findfirst() and 38 | / f_findnext(). (0:Disable, 1:Enable 2:Enable with matching altname[] too) */ 39 | 40 | 41 | #define FF_USE_MKFS 0 42 | /* This option switches f_mkfs() function. (0:Disable or 1:Enable) */ 43 | 44 | 45 | #define FF_USE_FASTSEEK 0 46 | /* This option switches fast seek function. (0:Disable or 1:Enable) */ 47 | 48 | 49 | #define FF_USE_EXPAND 0 50 | /* This option switches f_expand function. (0:Disable or 1:Enable) */ 51 | 52 | 53 | #define FF_USE_CHMOD 0 54 | /* This option switches attribute manipulation functions, f_chmod() and f_utime(). 55 | / (0:Disable or 1:Enable) Also FF_FS_READONLY needs to be 0 to enable this option. */ 56 | 57 | 58 | #define FF_USE_LABEL 0 59 | /* This option switches volume label functions, f_getlabel() and f_setlabel(). 60 | / (0:Disable or 1:Enable) */ 61 | 62 | 63 | #define FF_USE_FORWARD 0 64 | /* This option switches f_forward() function. (0:Disable or 1:Enable) */ 65 | 66 | 67 | /*---------------------------------------------------------------------------/ 68 | / Locale and Namespace Configurations 69 | /---------------------------------------------------------------------------*/ 70 | 71 | #define FF_CODE_PAGE 850 72 | /* This option specifies the OEM code page to be used on the target system. 73 | / Incorrect code page setting can cause a file open failure. 74 | / 75 | / 437 - U.S. 76 | / 720 - Arabic 77 | / 737 - Greek 78 | / 771 - KBL 79 | / 775 - Baltic 80 | / 850 - Latin 1 81 | / 852 - Latin 2 82 | / 855 - Cyrillic 83 | / 857 - Turkish 84 | / 860 - Portuguese 85 | / 861 - Icelandic 86 | / 862 - Hebrew 87 | / 863 - Canadian French 88 | / 864 - Arabic 89 | / 865 - Nordic 90 | / 866 - Russian 91 | / 869 - Greek 2 92 | / 932 - Japanese (DBCS) 93 | / 936 - Simplified Chinese (DBCS) 94 | / 949 - Korean (DBCS) 95 | / 950 - Traditional Chinese (DBCS) 96 | / 0 - Include all code pages above and configured by f_setcp() 97 | */ 98 | 99 | 100 | #define FF_USE_LFN 2 101 | #define FF_MAX_LFN 255 102 | /* The FF_USE_LFN switches the support for LFN (long file name). 103 | / 104 | / 0: Disable LFN. FF_MAX_LFN has no effect. 105 | / 1: Enable LFN with static working buffer on the BSS. Always NOT thread-safe. 106 | / 2: Enable LFN with dynamic working buffer on the STACK. 107 | / 3: Enable LFN with dynamic working buffer on the HEAP. 108 | / 109 | / To enable the LFN, ffunicode.c needs to be added to the project. The LFN function 110 | / requiers certain internal working buffer occupies (FF_MAX_LFN + 1) * 2 bytes and 111 | / additional (FF_MAX_LFN + 44) / 15 * 32 bytes when exFAT is enabled. 112 | / The FF_MAX_LFN defines size of the working buffer in UTF-16 code unit and it can 113 | / be in range of 12 to 255. It is recommended to be set 255 to fully support LFN 114 | / specification. 115 | / When use stack for the working buffer, take care on stack overflow. When use heap 116 | / memory for the working buffer, memory management functions, ff_memalloc() and 117 | / ff_memfree() in ffsystem.c, need to be added to the project. */ 118 | 119 | 120 | #define FF_LFN_UNICODE 0 121 | /* This option switches the character encoding on the API when LFN is enabled. 122 | / 123 | / 0: ANSI/OEM in current CP (TCHAR = char) 124 | / 1: Unicode in UTF-16 (TCHAR = WCHAR) 125 | / 2: Unicode in UTF-8 (TCHAR = char) 126 | / 127 | / Also behavior of string I/O functions will be affected by this option. 128 | / When LFN is not enabled, this option has no effect. */ 129 | 130 | 131 | #define FF_LFN_BUF 255 132 | #define FF_SFN_BUF 12 133 | /* This set of options defines size of file name members in the FILINFO structure 134 | / which is used to read out directory items. These values should be suffcient for 135 | / the file names to read. The maximum possible length of the read file name depends 136 | / on character encoding. When LFN is not enabled, these options have no effect. */ 137 | 138 | 139 | #define FF_STRF_ENCODE 0 140 | /* When FF_LFN_UNICODE >= 1 with LFN enabled, string I/O functions, f_gets(), 141 | / f_putc(), f_puts and f_printf() convert the character encoding in it. 142 | / This option selects assumption of character encoding ON THE FILE to be 143 | / read/written via those functions. 144 | / 145 | / 0: ANSI/OEM in current CP 146 | / 1: Unicode in UTF-16LE 147 | / 2: Unicode in UTF-16BE 148 | / 3: Unicode in UTF-8 149 | */ 150 | 151 | 152 | #define FF_FS_RPATH 0 153 | /* This option configures support for relative path. 154 | / 155 | / 0: Disable relative path and remove related functions. 156 | / 1: Enable relative path. f_chdir() and f_chdrive() are available. 157 | / 2: f_getcwd() function is available in addition to 1. 158 | */ 159 | 160 | 161 | /*---------------------------------------------------------------------------/ 162 | / Drive/Volume Configurations 163 | /---------------------------------------------------------------------------*/ 164 | 165 | #define FF_VOLUMES 1 166 | /* Number of volumes (logical drives) to be used. (1-10) */ 167 | 168 | 169 | #define FF_STR_VOLUME_ID 0 170 | #define FF_VOLUME_STRS "RAM","NAND","CF","SD","SD2","USB","USB2","USB3" 171 | /* FF_STR_VOLUME_ID switches string support for volume ID. 172 | / When FF_STR_VOLUME_ID is set to 1, also pre-defined strings can be used as drive 173 | / number in the path name. FF_VOLUME_STRS defines the drive ID strings for each 174 | / logical drives. Number of items must be equal to FF_VOLUMES. Valid characters for 175 | / the drive ID strings are: A-Z and 0-9. */ 176 | 177 | 178 | #define FF_MULTI_PARTITION 0 179 | /* This option switches support for multiple volumes on the physical drive. 180 | / By default (0), each logical drive number is bound to the same physical drive 181 | / number and only an FAT volume found on the physical drive will be mounted. 182 | / When this function is enabled (1), each logical drive number can be bound to 183 | / arbitrary physical drive and partition listed in the VolToPart[]. Also f_fdisk() 184 | / funciton will be available. */ 185 | 186 | 187 | #define FF_MIN_SS 512 188 | #define FF_MAX_SS 512 189 | /* This set of options configures the range of sector size to be supported. (512, 190 | / 1024, 2048 or 4096) Always set both 512 for most systems, generic memory card and 191 | / harddisk. But a larger value may be required for on-board flash memory and some 192 | / type of optical media. When FF_MAX_SS is larger than FF_MIN_SS, FatFs is configured 193 | / for variable sector size mode and disk_ioctl() function needs to implement 194 | / GET_SECTOR_SIZE command. */ 195 | 196 | 197 | #define FF_USE_TRIM 0 198 | /* This option switches support for ATA-TRIM. (0:Disable or 1:Enable) 199 | / To enable Trim function, also CTRL_TRIM command should be implemented to the 200 | / disk_ioctl() function. */ 201 | 202 | 203 | #define FF_FS_NOFSINFO 0 204 | /* If you need to know correct free space on the FAT32 volume, set bit 0 of this 205 | / option, and f_getfree() function at first time after volume mount will force 206 | / a full FAT scan. Bit 1 controls the use of last allocated cluster number. 207 | / 208 | / bit0=0: Use free cluster count in the FSINFO if available. 209 | / bit0=1: Do not trust free cluster count in the FSINFO. 210 | / bit1=0: Use last allocated cluster number in the FSINFO if available. 211 | / bit1=1: Do not trust last allocated cluster number in the FSINFO. 212 | */ 213 | 214 | 215 | 216 | /*---------------------------------------------------------------------------/ 217 | / System Configurations 218 | /---------------------------------------------------------------------------*/ 219 | 220 | #define FF_FS_TINY 1 221 | /* This option switches tiny buffer configuration. (0:Normal or 1:Tiny) 222 | / At the tiny configuration, size of file object (FIL) is shrinked FF_MAX_SS bytes. 223 | / Instead of private sector buffer eliminated from the file object, common sector 224 | / buffer in the filesystem object (FATFS) is used for the file data transfer. */ 225 | 226 | 227 | #define FF_FS_EXFAT 0 228 | /* This option switches support for exFAT filesystem. (0:Disable or 1:Enable) 229 | / When enable exFAT, also LFN needs to be enabled. 230 | / Note that enabling exFAT discards ANSI C (C89) compatibility. */ 231 | 232 | 233 | #define FF_FS_NORTC 1 234 | #define FF_NORTC_MON 1 235 | #define FF_NORTC_MDAY 1 236 | #define FF_NORTC_YEAR 2018 237 | /* The option FF_FS_NORTC switches timestamp functiton. If the system does not have 238 | / any RTC function or valid timestamp is not needed, set FF_FS_NORTC = 1 to disable 239 | / the timestamp function. All objects modified by FatFs will have a fixed timestamp 240 | / defined by FF_NORTC_MON, FF_NORTC_MDAY and FF_NORTC_YEAR in local time. 241 | / To enable timestamp function (FF_FS_NORTC = 0), get_fattime() function need to be 242 | / added to the project to read current time form real-time clock. FF_NORTC_MON, 243 | / FF_NORTC_MDAY and FF_NORTC_YEAR have no effect. 244 | / These options have no effect at read-only configuration (FF_FS_READONLY = 1). */ 245 | 246 | 247 | #define FF_FS_LOCK 0 248 | /* The option FF_FS_LOCK switches file lock function to control duplicated file open 249 | / and illegal operation to open objects. This option must be 0 when FF_FS_READONLY 250 | / is 1. 251 | / 252 | / 0: Disable file lock function. To avoid volume corruption, application program 253 | / should avoid illegal open, remove and rename to the open objects. 254 | / >0: Enable file lock function. The value defines how many files/sub-directories 255 | / can be opened simultaneously under file lock control. Note that the file 256 | / lock control is independent of re-entrancy. */ 257 | 258 | 259 | #define FF_FS_REENTRANT 0 260 | #define FF_FS_TIMEOUT 1000 261 | #define FF_SYNC_t HANDLE 262 | /* The option FF_FS_REENTRANT switches the re-entrancy (thread safe) of the FatFs 263 | / module itself. Note that regardless of this option, file access to different 264 | / volume is always re-entrant and volume control functions, f_mount(), f_mkfs() 265 | / and f_fdisk() function, are always not re-entrant. Only file/directory access 266 | / to the same volume is under control of this function. 267 | / 268 | / 0: Disable re-entrancy. FF_FS_TIMEOUT and FF_SYNC_t have no effect. 269 | / 1: Enable re-entrancy. Also user provided synchronization handlers, 270 | / ff_req_grant(), ff_rel_grant(), ff_del_syncobj() and ff_cre_syncobj() 271 | / function, must be added to the project. Samples are available in 272 | / option/syscall.c. 273 | / 274 | / The FF_FS_TIMEOUT defines timeout period in unit of time tick. 275 | / The FF_SYNC_t defines O/S dependent sync object type. e.g. HANDLE, ID, OS_EVENT*, 276 | / SemaphoreHandle_t and etc. A header file for O/S definitions needs to be 277 | / included somewhere in the scope of ff.h. */ 278 | 279 | /* #include // O/S definitions */ 280 | 281 | 282 | 283 | /*--- End of configuration options ---*/ 284 | --------------------------------------------------------------------------------