├── VectorTable.h ├── CPUFreq.h ├── Platform.h ├── README.md ├── MAINTAINERS ├── LICENSE.txt ├── mt3620 ├── clock.h ├── irq.h ├── mbox.h ├── gpt.h ├── spi.h ├── dma.h ├── adc.h ├── i2c.h ├── i2s.h └── uart.h ├── Common.h ├── linker.ld ├── NVIC.h ├── I2S.h ├── UART.h ├── GPIO.h ├── ADC.h ├── Print.h ├── MBox.h ├── GPIO.c ├── GPT.h ├── ADC.c ├── Print.c ├── I2CMaster.h ├── VectorTable.c ├── MBox.c └── SPIMaster.h /VectorTable.h: -------------------------------------------------------------------------------- 1 | #ifndef AZURE_SPHERE_VECTOR_TABLE_H_ 2 | #define AZURE_SPHERE_VECTOR_TABLE_H_ 3 | 4 | #ifdef __cplusplus 5 | extern "C" { 6 | #endif 7 | 8 | void VectorTableInit(void); 9 | 10 | #ifdef __cplusplus 11 | } 12 | #endif 13 | 14 | #endif // #ifndef AZURE_SPHERE_VECTOR_TABLE_H_ 15 | -------------------------------------------------------------------------------- /CPUFreq.h: -------------------------------------------------------------------------------- 1 | /* Copyright (c) Codethink Ltd. All rights reserved. 2 | Licensed under the MIT License. */ 3 | 4 | #ifndef AZURE_SPHERE_CPUFREQ_H_ 5 | #define AZURE_SPHERE_CPUFREQ_H_ 6 | 7 | #ifdef __cplusplus 8 | extern "C" { 9 | #endif 10 | 11 | #include 12 | 13 | bool CPUFreq_Set(unsigned freq); 14 | unsigned CPUFreq_Get(void); 15 | 16 | #ifdef __cplusplus 17 | } 18 | #endif 19 | 20 | #endif // #ifndef AZURE_SPHERE_CPUFREQ_H_ 21 | -------------------------------------------------------------------------------- /Platform.h: -------------------------------------------------------------------------------- 1 | /* Copyright (c) Codethink Ltd. All rights reserved. 2 | Licensed under the MIT License. */ 3 | 4 | #ifndef AZURE_SPHERE_PLATFORM_H_ 5 | #define AZURE_SPHERE_PLATFORM_H_ 6 | 7 | typedef enum { 8 | MT3620_UNIT_UART_DEBUG, 9 | MT3620_UNIT_ISU0, 10 | MT3620_UNIT_ISU1, 11 | MT3620_UNIT_ISU2, 12 | MT3620_UNIT_ISU3, 13 | MT3620_UNIT_ISU4, 14 | MT3620_UNIT_ISU5, 15 | MT3620_UNIT_I2S0, 16 | MT3620_UNIT_I2S1, 17 | MT3620_UNIT_ADC0, 18 | MT3620_UNIT_GPT0, 19 | MT3620_UNIT_GPT1, 20 | MT3620_UNIT_GPT2, 21 | MT3620_UNIT_GPT3, 22 | MT3620_UNIT_GPT4, 23 | MT3620_UNIT_MBOX_CA7, 24 | MT3620_UNIT_MBOX_CM4, 25 | } Platform_Unit; 26 | 27 | #define MT3620_UNIT_ISU_COUNT 6 28 | #define MT3620_UNIT_ADC_COUNT 1 29 | #define MT3620_UNIT_GPT_COUNT 5 30 | #define MT3620_UNIT_MBOX_COUNT 2 31 | 32 | #endif // #ifndef AZURE_SPHERE_PLATFORM_H_ 33 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Overview 2 | 3 | Drivers for Azure Sphere MT3620 realtime cores (CM4). These drivers support 4 | the following peripherals: 5 | 6 | - [ADC](ADC.h) 7 | - [GPIO](GPIO.h) 8 | - [I2C](I2CMaster.h) 9 | - [I2S](I2S.h) 10 | - [SPI](SPIMaster.h) 11 | - [Timers](GPT.h) 12 | - [UART](UART.h) 13 | 14 | The API should be HW agnostic; which is why the MT3620 specifics (register details) 15 | are restricted to the register headers in the `mt3620/` directory. The implementation 16 | in the `.c` files is obviously HW specific. 17 | 18 | For detail and documentation on the MT3620; consult 19 | [this Microsoft resource page](https://docs.microsoft.com/en-gb/azure-sphere/hardware/mt3620-product-status). 20 | 21 | # Usage 22 | 23 | [Here](https://github.com/CodethinkLabs/mt3620-m4-samples) are some example applications using these drivers. 24 | 25 | # Documentation 26 | 27 | The API for the drivers is documented using XMLDoc. You can use Doxygen to parse these recursively. -------------------------------------------------------------------------------- /MAINTAINERS: -------------------------------------------------------------------------------- 1 | List of developers and maintainers of this codebase: 2 | 3 | Maintainer | Subsystems worked on 4 | ============================================================|=========================================== 5 | Ben Brewer (ben.brewer@codethink.co.uk) | I2C, SPI, I2S, UART 6 | [ben-brewer-codethink] | 7 | | 8 | Connor Driscoll (connor.driscoll@codethink.co.uk) | ADC, GPIO, PWM 9 | [Cpt-Quantum] | 10 | | 11 | Aiden Jeffrey (aiden.jeffrey@codethink.co.uk) | GPT, Print, I2S 12 | [aiden-ct] | 13 | | 14 | Kostas Andrikopoulos (kostas.andrikopoulos@codethink.co.uk) | SPI 15 | [kostas-andrik] | 16 | -------------------------------------------------------------------------------- /LICENSE.txt: -------------------------------------------------------------------------------- 1 | Copyright 2019 Codethink Ltd. 2 | 3 | Permission is hereby granted, free of charge, to any person obtaining 4 | copy of this software and associated documentation files (the 5 | "Software"), to deal in the Software without restriction, including 6 | without limitation the rights to use, copy, modify, merge, publish, 7 | distribute, sublicense, and/or sell copies of the Software, and to 8 | permit persons to whom the Software is furnished to do so, subject 9 | to the following conditions: 10 | 11 | The above copyright notice and this permission notice shall be 12 | included in all copies or substantial portions of the Software. 13 | 14 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 15 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 16 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 17 | NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE 18 | LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 19 | OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION 20 | WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -------------------------------------------------------------------------------- /mt3620/clock.h: -------------------------------------------------------------------------------- 1 | #ifndef MT3620_REG_CLOCK_H__ 2 | #define MT3620_REG_CLOCK_H__ 3 | 4 | #include 5 | #include 6 | 7 | typedef enum { 8 | MT3620_CLOCK_CRYSTAL = 0, 9 | MT3620_CLOCK_32K = 1, 10 | MT3620_CLOCK_PLL_200M = 2, 11 | MT3620_CLOCK_COUNT 12 | } mt3620_clock_t; 13 | 14 | static const unsigned mt3620_clock_freq[MT3620_CLOCK_COUNT] = { 15 | [MT3620_CLOCK_CRYSTAL ] = 26000000, 16 | [MT3620_CLOCK_32K ] = 32768, 17 | [MT3620_CLOCK_PLL_200M] = 197600000, 18 | }; 19 | 20 | typedef union __attribute__((__packed__)) { 21 | struct __attribute__((__packed__)) { 22 | unsigned unknown_7_0 : 8; 23 | mt3620_clock_t hclk_clock_source : 2; 24 | unsigned unknown_31_10 : 22; 25 | }; 26 | 27 | uint32_t mask; 28 | } mt3620_io_cm4_rgu_t; 29 | 30 | static volatile mt3620_io_cm4_rgu_t * const mt3620_io_cm4_rgu 31 | = (volatile mt3620_io_cm4_rgu_t *)0x2101000c; 32 | 33 | static inline mt3620_clock_t mt3620_hclk_clock_source_get(void) 34 | { 35 | mt3620_io_cm4_rgu_t rgu = { .mask = mt3620_io_cm4_rgu->mask }; 36 | return rgu.hclk_clock_source; 37 | } 38 | 39 | static inline void mt3620_hclk_clock_source_set(mt3620_clock_t src) 40 | { 41 | mt3620_io_cm4_rgu_t rgu = { .mask = mt3620_io_cm4_rgu->mask }; 42 | rgu.hclk_clock_source = src; 43 | mt3620_io_cm4_rgu->mask = rgu.mask; 44 | } 45 | 46 | #endif 47 | -------------------------------------------------------------------------------- /Common.h: -------------------------------------------------------------------------------- 1 | /* Copyright (c) Codethink Ltd. All rights reserved. 2 | Licensed under the MIT License. */ 3 | 4 | #ifndef AZURE_SPHERE_COMMON_H_ 5 | #define AZURE_SPHERE_COMMON_H_ 6 | 7 | /// Returned when a function or operation succeeds. 8 | #define ERROR_NONE ( 0) 9 | 10 | /// Returned when an unspecified error occurs. 11 | #define ERROR ( -1) 12 | 13 | /// Returned when an operation is attempted while a resource is locked. 14 | #define ERROR_BUSY ( -2) 15 | 16 | /// Returned when an operation fails due to timeout. 17 | #define ERROR_TIMEOUT ( -3) 18 | 19 | /// Returned when use of an unsupported feature is attempted. 20 | #define ERROR_UNSUPPORTED ( -4) 21 | 22 | /// Returned when an operation is invoked with an invalid parameter. 23 | #define ERROR_PARAMETER ( -5) 24 | 25 | /// Returned when an operation requires DMA but the data is not located in 26 | /// DMA accessible memory. 27 | #define ERROR_DMA_SOURCE ( -6) 28 | 29 | /// Returned when an operation is requested on a handle that's closed. 30 | #define ERROR_HANDLE_CLOSED ( -7) 31 | 32 | /// Returned when an operation fails due to invalid or unexpected hardware state. 33 | #define ERROR_HARDWARE_STATE ( -8) 34 | 35 | /// This is not an error itself but is used by other modules as an offset for module 36 | /// or driver specific errors. 37 | #define ERROR_SPECIFIC (-255) 38 | 39 | #endif // #ifndef AZURE_SPHERE_COMMON_H_ 40 | -------------------------------------------------------------------------------- /linker.ld: -------------------------------------------------------------------------------- 1 | /* Copyright (c) Codethink Ltd. All rights reserved. 2 | Licensed under the MIT License. */ 3 | 4 | MEMORY 5 | { 6 | TCM (rwx) : ORIGIN = 0x00100000, LENGTH = 192K 7 | SYSRAM (rwx) : ORIGIN = 0x22000000, LENGTH = 64K 8 | FLASH (rx) : ORIGIN = 0x10000000, LENGTH = 1M 9 | } 10 | 11 | /* The data and BSS regions can be placed in TCM or SYSRAM. The code and read-only regions can 12 | be placed in TCM, SYSRAM, or FLASH. See 13 | https://docs.microsoft.com/en-us/azure-sphere/app-development/memory-latency for information 14 | about which types of memory which are available to real-time capable applications on the 15 | MT3620, and when they should be used. */ 16 | REGION_ALIAS("CODE_REGION", TCM); 17 | REGION_ALIAS("RODATA_REGION", TCM); 18 | REGION_ALIAS("DATA_REGION", TCM); 19 | REGION_ALIAS("BSS_REGION", TCM); 20 | 21 | ENTRY(ExceptionVectorTable) 22 | 23 | SECTIONS 24 | { 25 | /* The exception vector's virtual address must be aligned to a power of two, 26 | which is determined by its size and set via CODE_REGION. See definition of 27 | ExceptionVectorTable in main.c. 28 | 29 | When the code is run from XIP flash, it must be loaded to virtual address 30 | 0x10000000 and be aligned to a 32-byte offset within the ELF file. */ 31 | .text : ALIGN(32) { 32 | KEEP(*(.vector_table)) 33 | *(.text) 34 | } >CODE_REGION 35 | 36 | .rodata : { 37 | *(.rodata) 38 | } >RODATA_REGION 39 | 40 | .data : { 41 | *(.data) 42 | } >DATA_REGION 43 | 44 | .bss : { 45 | *(.bss) 46 | } >BSS_REGION 47 | 48 | .sysram : { 49 | *(.sysram) 50 | } >SYSRAM 51 | 52 | . = ALIGN(4); 53 | end = . ; 54 | 55 | StackTop = ORIGIN(TCM) + LENGTH(TCM); 56 | } 57 | -------------------------------------------------------------------------------- /mt3620/irq.h: -------------------------------------------------------------------------------- 1 | #ifndef MT3620_REG_IRQ_H_ 2 | #define MT3620_REG_IRQ_H_ 3 | 4 | #include 5 | #include 6 | 7 | typedef union __attribute__((__packed__)) { 8 | struct __attribute__((__packed__)) { 9 | unsigned cnt : 4; 10 | unsigned prescal : 3; 11 | bool dual : 1; 12 | bool pol : 1; 13 | bool en : 1; 14 | const unsigned res_31_9 : 22; 15 | }; 16 | 17 | uint32_t mask; 18 | } mt3620_irq_dbnc_con_t; 19 | 20 | #define MT3620_IRQ_EINT_CNT 24 21 | #define MT3620_IRQ_EINT_TEMP_CNT 8 22 | 23 | #define MT3620_IRQ_CFG_IRQ_CNT 4 24 | #define MT3620_IRQ_WIC_CNT 4 25 | #define MT3620_IRQ_TEST_CNT 4 26 | 27 | typedef struct { 28 | volatile uint32_t dbnc_con [MT3620_IRQ_EINT_CNT]; 29 | volatile uint32_t dbnc_con_temp [MT3620_IRQ_EINT_TEMP_CNT]; 30 | volatile const uint32_t res_32_128 [96]; 31 | volatile uint32_t irq_sens [MT3620_IRQ_CFG_IRQ_CNT]; 32 | volatile const uint32_t res_132_192 [61]; 33 | volatile uint32_t wic_rel_pend_val[MT3620_IRQ_WIC_CNT]; 34 | volatile const uint32_t res_197_200 [4]; 35 | volatile uint32_t wic_rel_en_val [MT3620_IRQ_WIC_CNT]; 36 | volatile const uint32_t res_205_207 [3]; 37 | volatile uint32_t wic_rel_ctrl; 38 | volatile const uint32_t res_210_216 [7]; 39 | volatile uint32_t wic_pend_stat [MT3620_IRQ_WIC_CNT]; 40 | volatile const uint32_t res_221_224 [4]; 41 | volatile uint32_t wic_en_stat [MT3620_IRQ_WIC_CNT]; 42 | volatile const uint32_t res_229_231 [3]; 43 | volatile uint32_t wic_wake_stat; 44 | volatile const uint32_t res_233_383 [151]; 45 | volatile uint32_t irq_disable [MT3620_IRQ_CFG_IRQ_CNT]; 46 | volatile const uint32_t res_388_391 [4]; 47 | volatile uint32_t wic_disable [MT3620_IRQ_WIC_CNT]; 48 | volatile const uint32_t res_396_447 [52]; 49 | volatile uint32_t irq_test [MT3620_IRQ_CFG_IRQ_CNT]; 50 | volatile const uint32_t res_452_455 [4]; 51 | volatile uint32_t irq_test_ctrl; 52 | volatile const uint32_t res_457_575 [119]; 53 | volatile uint32_t soft_rst; 54 | } mt3620_irq_t; 55 | 56 | static volatile mt3620_irq_t * const mt3620_irq 57 | = (volatile mt3620_irq_t *)0x21000000; 58 | 59 | #define MT3620_IRQ_EINT_INTERRUPT(index) (index + 20) 60 | 61 | #define MT3620_IRQ_DBNC_FIELD_READ(reg, field, index) \ 62 | ((mt3620_irq_dbnc_con_t)(mt3620_irq->reg[index])).field 63 | 64 | #define MT3620_IRQ_DBNC_FIELD_WRITE(reg, field, index, value) do { \ 65 | mt3620_irq_dbnc_con_t reg = { .mask = mt3620_irq->reg[index] }; \ 66 | reg.field = value; mt3620_irq->reg[index] = reg.mask; } while (0) 67 | 68 | #endif // #ifdef MT3620_REG_IRQ_H_ 69 | -------------------------------------------------------------------------------- /NVIC.h: -------------------------------------------------------------------------------- 1 | /* Copyright (c) Codethink Ltd. All rights reserved. 2 | Licensed under the MIT License. */ 3 | 4 | #ifndef AZURE_SPHERE_NVIC_H_ 5 | #define AZURE_SPHERE_NVIC_H_ 6 | 7 | #include 8 | #include 9 | 10 | #ifdef __cplusplus 11 | extern "C" { 12 | #endif 13 | 14 | /// NVIC Registers, ARM DDI 0403E.b S3.4.3. 15 | static const volatile uint32_t * const ICTR = (const volatile uint32_t *)0xE000E004; 16 | static volatile uint32_t * const NVIC_ISER = ( volatile uint32_t *)0xE000E100; 17 | static volatile uint32_t * const NVIC_ICER = ( volatile uint32_t *)0xE000E180; 18 | static volatile uint32_t * const NVIC_ISPR = ( volatile uint32_t *)0xE000E200; 19 | static volatile uint32_t * const NVIC_ICPR = ( volatile uint32_t *)0xE000E280; 20 | static const volatile uint32_t * const NVIC_IABR = (const volatile uint32_t *)0xE000E300; 21 | static volatile uint8_t * const NVIC_IPR = ( volatile uint8_t *)0xE000E400; 22 | 23 | /// The IOM4 cores on the MT3620 use three bits to encode interrupt priorities. 24 | #define NVIC_PRIORITY_BITS 3 25 | 26 | /// 27 | /// Blocks interrupts at priority 1 level and above. 28 | /// Pair this with a call to to unblock interrupts. 29 | /// 30 | /// Previous value of BASEPRI register. This can be treated as an opaque value 31 | /// which must be passed to . 32 | static inline uint32_t NVIC_BlockIRQs(void) 33 | { 34 | uint32_t prevBasePri; 35 | uint32_t newBasePri = 1; // block IRQs priority 1 and above 36 | 37 | __asm__("mrs %0, BASEPRI" : "=r"(prevBasePri) :); 38 | __asm__("msr BASEPRI, %0" : : "r"(newBasePri)); 39 | return prevBasePri; 40 | } 41 | 42 | /// 43 | /// Re-enables interrupts which were blocked by . 44 | /// 45 | /// Value returned from . 46 | static inline void NVIC_RestoreIRQs(uint32_t prevBasePri) 47 | { 48 | __asm__("msr BASEPRI, %0" : : "r"(prevBasePri)); 49 | } 50 | 51 | /// 52 | /// Enable NVIC interrupt. 53 | /// See DDI 0403E.d SB3.4.4, Interrupt Set-Enable Registers, NVIC_ISER0-NVIC_ISER7. 54 | /// 55 | /// Which interrupt to enable. 56 | /// Priority, which must fit into the number of supported priority bits. 57 | static inline void NVIC_EnableIRQ(unsigned irq, unsigned priority) 58 | { 59 | priority &= ((1U << NVIC_PRIORITY_BITS) - 1); 60 | priority <<= (8 - NVIC_PRIORITY_BITS); 61 | NVIC_IPR[irq] = priority; 62 | 63 | unsigned offset = irq / 32; 64 | uint32_t mask = 1U << (irq % 32); 65 | NVIC_ISER[offset] = mask; 66 | } 67 | 68 | /// 69 | /// Disable NVIC interrupt. 70 | /// See DDI 0403E.d SB3.4.4, Interrupt Set-Enable Registers, NVIC_ICER0-NVIC_ICER7. 71 | /// 72 | /// Which interrupt to disable. 73 | static inline void NVIC_DisableIRQ(unsigned irq) 74 | { 75 | unsigned offset = irq / 32; 76 | uint32_t mask = 1U << (irq % 32); 77 | NVIC_ICER[offset] = mask; 78 | } 79 | 80 | #ifdef __cplusplus 81 | } 82 | #endif 83 | 84 | #endif /* AZURE_SPHERE_NVIC_H_ */ 85 | -------------------------------------------------------------------------------- /mt3620/mbox.h: -------------------------------------------------------------------------------- 1 | #ifndef MT3620_REG_MBOX_H_ 2 | #define MT3620_REG_MBOX_H_ 3 | 4 | #include 5 | #include 6 | 7 | typedef union __attribute__((__packed__)) { 8 | struct __attribute__((__packed__)) { 9 | bool soft_rst : 1; 10 | bool soft_rst_myself : 1; 11 | const unsigned res_31_2 : 30; 12 | }; 13 | 14 | uint32_t mask; 15 | } mt3620_mbox_gen_ctrl_t; 16 | 17 | typedef union __attribute__((__packed__)) { 18 | struct __attribute__((__packed__)) { 19 | uint32_t rd_dly : 8; 20 | uint32_t rcs_dly : 2; 21 | const unsigned res_31_10 : 22; 22 | }; 23 | 24 | uint32_t mask; 25 | } mt3620_mbox_fifo_ctrl_t; 26 | 27 | typedef union __attribute__((__packed__)) { 28 | struct __attribute__((__packed__)) { 29 | bool int_fifo_rd : 1; 30 | bool int_fifo_nf : 1; 31 | bool int_fifo_wr : 1; 32 | bool int_fifo_ne : 1; 33 | const unsigned res_31_4 : 28; 34 | }; 35 | 36 | uint32_t mask; 37 | } mt3620_mbox_int_en_t; 38 | 39 | typedef mt3620_mbox_int_en_t mt3620_mbox_int_sts_t; 40 | 41 | typedef struct { 42 | volatile uint32_t mbox_ver; 43 | volatile uint32_t mbox_gen_ctrl; 44 | volatile uint32_t mbox_dbg_idx; 45 | volatile uint32_t mbox_dbg_probe; 46 | volatile const uint32_t res_4; 47 | volatile uint32_t sw_tx_int_port; 48 | volatile uint32_t sw_rx_int_en; 49 | volatile uint32_t sw_rx_int_sts; 50 | volatile uint32_t mbox_fifo_ctrl; 51 | volatile const uint32_t res_9_11[3]; 52 | volatile uint32_t mbox_nf_thrs; 53 | volatile uint32_t mbox_ne_thrs; 54 | volatile uint32_t mbox_int_en; 55 | volatile uint32_t mbox_int_sts; 56 | volatile uint32_t cmd_push; 57 | volatile uint32_t data_push; 58 | volatile uint32_t fifo_push_cnt; 59 | volatile const uint32_t res_19; 60 | volatile uint32_t cmd_pop; 61 | volatile uint32_t data_pop; 62 | volatile uint32_t fifo_pop_cnt; 63 | volatile const uint32_t res_23; 64 | volatile uint32_t semaphore_p; 65 | } mt3620_mbox_t; 66 | 67 | /* Note: MT3620_MBOX_CM4 has no semaphore */ 68 | typedef enum { 69 | MT3620_MBOX_CA7 = 0, 70 | MT3620_MBOX_CM4 = 1, 71 | MT3620_MBOX_COUNT 72 | } mt3620_mbox_unit; 73 | 74 | /* Note: Low power wakeup interrupts not yet supported */ 75 | typedef enum { 76 | MT3620_MBOX_INT_TX_CONFIRMED = 0, 77 | MT3620_MBOX_INT_TX_FIFO_NF = 1, 78 | MT3620_MBOX_INT_RX = 2, 79 | MT3620_MBOX_INT_TX_FIFO_NE = 3, 80 | 81 | MT3620_MBOX_INT_FIFO_INT = 4, 82 | 83 | MT3620_MBOX_INT_SW_INT = 5, 84 | MT3620_MBOX_INT_COUNT 85 | } mt3620_mbox_int; 86 | 87 | #define MT3620_MBOX_INTERRUPT(index, int_type) \ 88 | (6 + (index * MT3620_MBOX_INT_COUNT) + int_type) 89 | 90 | #define MT3620_MBOX_FIFO_COUNT_MAX 15 91 | 92 | static volatile mt3620_mbox_t * const mt3620_mbox[MT3620_MBOX_COUNT] = { 93 | [MT3620_MBOX_CA7] = (volatile mt3620_mbox_t *)0x21050000, 94 | [MT3620_MBOX_CM4] = (volatile mt3620_mbox_t *)0x21060000 95 | }; 96 | 97 | #define MT3620_MBOX_FIELD_READ(i, reg, field) ((mt3620_##reg##_t)mt3620_mbox[i]->reg).field 98 | #define MT3620_MBOX_FIELD_WRITE(i, reg, field, value) do { \ 99 | mt3620_##reg##_t reg = { .mask = mt3620_mbox[i]->reg }; \ 100 | reg.field = value; mt3620_mbox[i]->reg = reg.mask; } while (0) 101 | 102 | #endif // #ifndef MT3620_REG_MBOX_H_ 103 | -------------------------------------------------------------------------------- /mt3620/gpt.h: -------------------------------------------------------------------------------- 1 | #ifndef MT3620_REG_GPT_H_ 2 | #define MT3620_REG_GPT_H_ 3 | 4 | #include 5 | #include 6 | 7 | typedef union __attribute__((__packed__)) { 8 | struct __attribute__((__packed__)) { 9 | bool gpt0_int : 1; 10 | bool gpt1_int : 1; 11 | const unsigned res_31_2 : 30; 12 | }; 13 | 14 | uint32_t mask; 15 | } mt3620_gpt_isr_t; 16 | 17 | typedef union __attribute__((__packed__)) { 18 | struct __attribute__((__packed__)) { 19 | bool gpt0_int_en : 1; 20 | bool gpt1_int_en : 1; 21 | const unsigned res_31_2 : 30; 22 | }; 23 | 24 | uint32_t mask; 25 | } mt3620_gpt_ier_t; 26 | 27 | typedef union __attribute__((__packed__)) { 28 | struct __attribute__((__packed__)) { 29 | bool en : 1; 30 | bool mode : 1; 31 | bool speed : 1; 32 | bool restart : 1; 33 | const unsigned res_31_4 : 28; 34 | }; 35 | 36 | uint32_t mask; 37 | } mt3620_gpt0_ctrl_t; 38 | 39 | typedef mt3620_gpt0_ctrl_t mt3620_gpt1_ctrl_t; 40 | 41 | typedef union __attribute__((__packed__)) { 42 | struct __attribute__((__packed__)) { 43 | bool en : 1; 44 | bool speed : 1; 45 | const unsigned res_31_2 : 30; 46 | }; 47 | 48 | uint32_t mask; 49 | } mt3620_gpt2_ctrl_t; 50 | 51 | typedef union __attribute__((__packed__)) { 52 | struct __attribute__((__packed__)) { 53 | bool en : 1; 54 | const unsigned res_14_1 : 14; 55 | bool gpt3_iclr : 1; 56 | unsigned osc_cnt_1us : 6; 57 | const unsigned res_31_22 : 10; 58 | }; 59 | 60 | uint32_t mask; 61 | } mt3620_gpt3_ctrl_t; 62 | 63 | typedef mt3620_gpt2_ctrl_t mt3620_gpt4_ctrl_t; 64 | 65 | typedef struct { 66 | volatile uint32_t gpt_isr; 67 | volatile uint32_t gpt_ier; 68 | volatile const uint32_t res_2_3[2]; 69 | volatile uint32_t gpt0_ctrl; 70 | volatile uint32_t gpt0_icnt; 71 | volatile const uint32_t res_6_7[2]; 72 | volatile uint32_t gpt1_ctrl; 73 | volatile uint32_t gpt1_icnt; 74 | volatile const uint32_t res_10_11[2]; 75 | volatile uint32_t gpt2_ctrl; 76 | volatile uint32_t gpt2_cnt; 77 | volatile const uint32_t res_14_15[2]; 78 | volatile uint32_t gpt0_cnt; 79 | volatile uint32_t gpt1_cnt; 80 | volatile const uint32_t res_18_19[2]; 81 | volatile uint32_t gpt3_ctrl; 82 | volatile uint32_t gpt3_init; 83 | volatile uint32_t gpt3_cnt; 84 | volatile uint32_t gpt3_expire; 85 | volatile uint32_t gpt4_ctrl; 86 | volatile uint32_t gpt4_init; 87 | volatile uint32_t gpt4_cnt; 88 | } mt3620_gpt_t; 89 | 90 | static volatile mt3620_gpt_t * const mt3620_gpt 91 | = (volatile mt3620_gpt_t *)0x21030000; 92 | 93 | #define ROUND_DIVIDE(x, y) ((x + (y / 2)) / y) 94 | 95 | // frequencies in Hz 96 | #define MT3620_GPT_BUS_CLOCK 26000000.0f 97 | #define MT3620_GPT_012_HIGH_SPEED 32768.0f 98 | #define MT3620_GPT_012_LOW_SPEED ROUND_DIVIDE(MT3620_GPT_012_HIGH_SPEED, 33) // (should be 32/33 kHz - according to datasheet) 99 | #define MT3620_GPT_3_SRC_CLK_HZ MT3620_GPT_BUS_CLOCK 100 | #define MT3620_GPT_3_LOW_SPEED ROUND_DIVIDE(MT3620_GPT_BUS_CLOCK, 26) 101 | #define MT3620_GPT_3_HIGH_SPEED MT3620_GPT_BUS_CLOCK 102 | #define MT3620_GPT_3_SPEED_RANGE (MT3620_GPT_3_HIGH_SPEED - MT3620_GPT_3_LOW_SPEED) 103 | 104 | #define MT3620_GPT_MAX_COUNT UINT32_MAX 105 | 106 | #define MT3620_GPT_FIELD_READ(reg, field) ((mt3620_##reg##_t)mt3620_gpt->reg).field 107 | #define MT3620_GPT_FIELD_WRITE(reg, field, value) do { \ 108 | mt3620_##reg##_t reg = { .mask = mt3620_gpt->reg }; \ 109 | reg.field = value; mt3620_gpt->reg = reg.mask; } while (0) 110 | 111 | #endif // #ifdef MT3620_REG_GPT_H_ 112 | -------------------------------------------------------------------------------- /I2S.h: -------------------------------------------------------------------------------- 1 | /* Copyright (c) Codethink Ltd. All rights reserved. 2 | Licensed under the MIT License. */ 3 | 4 | #ifndef AZURE_SPHERE_I2S_H_ 5 | #define AZURE_SPHERE_I2S_H_ 6 | 7 | #include "Common.h" 8 | #include "Platform.h" 9 | #include 10 | #include 11 | #include 12 | 13 | #ifdef __cplusplus 14 | extern "C" { 15 | #endif 16 | 17 | /// Enum for audio input/output formats. 18 | typedef enum { 19 | /// This will disable input/output when passed. 20 | I2S_FORMAT_NONE = 0, 21 | /// I2S is a standard format which supports one or two channels 22 | I2S_FORMAT_I2S, 23 | /// TDM is a standard format which supports any number of channels 24 | I2S_FORMAT_TDM, 25 | } I2S_Format; 26 | 27 | /// Opaque I2S handle. 28 | typedef struct I2S I2S; 29 | 30 | /// 31 | /// Acquires a handle before using a given I2S interface. 32 | /// 33 | /// Which I2S interface to initialize and acquire a handle for. 34 | /// The desired frequency of the master clock. 35 | /// A handle to an I2S interface or NULL on failure. 36 | I2S *I2S_Open(Platform_Unit unit, unsigned mclk); 37 | 38 | /// 39 | /// Releases a handle once it's finished using a given I2S interface. 40 | /// Once released the handle is free to be opened again. 41 | /// 42 | /// The I2S handle which is to be released. 43 | void I2S_Close(I2S *handle); 44 | 45 | /// 46 | /// Enables audio output on an I2S interface. 47 | /// 48 | /// The I2S handle on which output is to be enabled 49 | /// The desired format (I2S or TDM), set to I2S_FORMAT_NONE to disable. 50 | /// The number of channels to output on (must be 1 or 2 for I2S). 51 | /// The number of bits per sample (usually 16). 52 | /// The target sample rate of the output. 53 | /// The callback which will be used to fill the output buffer: 54 | /// (data: pointer to data buffer, size: size of buffer in bytes). 55 | /// ERROR_NONE on success or an error code on failure. 56 | int32_t I2S_Output( 57 | I2S *handle, I2S_Format format, unsigned channels, unsigned bits, unsigned rate, 58 | bool (*callback)(void *data, uintptr_t size)); 59 | 60 | /// 61 | /// Enables audio output on an I2S interface. 62 | /// 63 | /// The I2S handle on which input is to be enabled 64 | /// The desired format (I2S or TDM), set to I2S_FORMAT_NONE to disable. 65 | /// The number of channels to input (must be 1 or 2 for I2S). 66 | /// The number of bits per sample (usually 16). 67 | /// The target sample rate of the input. 68 | /// The callback which will be used to process the input buffer: 69 | /// (data: pointer to data buffer, size: size of buffer in bytes) 70 | /// ERROR_NONE on success or an error code on failure. 71 | int32_t I2S_Input( 72 | I2S *handle, I2S_Format format, unsigned channels, unsigned bits, unsigned rate, 73 | bool (*callback)(void *data, uintptr_t size)); 74 | 75 | /// 76 | /// Query the output sample rate of an I2S interface. 77 | /// 78 | /// The I2S handle on which the output sample rate is queried. 79 | /// The exact sample rate in herts of the output, or zero if disabled. 80 | unsigned I2S_GetOutputSampleRate(I2S *handle); 81 | 82 | /// 83 | /// Query the input sample rate of an I2S interface. 84 | /// 85 | /// The I2S handle on which the input sample rate is queried. 86 | /// The exact sample rate in herts of the input, or zero if disabled. 87 | unsigned I2S_GetInputSampleRate(I2S *handle); 88 | 89 | #ifdef __cplusplus 90 | } 91 | #endif 92 | 93 | #endif // #ifndef AZURE_SPHERE_I2S_H_ 94 | -------------------------------------------------------------------------------- /UART.h: -------------------------------------------------------------------------------- 1 | /* Copyright (c) Codethink Ltd. All rights reserved. 2 | Licensed under the MIT License. */ 3 | 4 | #ifndef AZURE_SPHERE_UART_H_ 5 | #define AZURE_SPHERE_UART_H_ 6 | 7 | #include "Platform.h" 8 | #include "Common.h" 9 | #include 10 | #include 11 | 12 | 13 | #ifdef __cplusplus 14 | extern "C" { 15 | #endif 16 | 17 | /// Opaque UART handle. 18 | typedef volatile struct UART UART; 19 | 20 | /// UART parity modes. 21 | typedef enum { 22 | /// No parity bit transmitted. 23 | UART_PARITY_NONE = 0, 24 | /// Parity bit 1 when even parity is detected. 25 | UART_PARITY_EVEN = 1, 26 | /// Parity bit 1 when odd parity is detected. 27 | UART_PARITY_ODD = 2, 28 | /// Parity bit hardcoded to 0. 29 | UART_PARITY_STICK_ZERO = 3, 30 | /// Parity bit hardcoded to 1. 31 | UART_PARITY_STICK_ONE = 4, 32 | } UART_Parity; 33 | 34 | /// The UART interrupts (and hence callbacks) run at this priority level. 35 | static const uint32_t UART_PRIORITY = 2; 36 | 37 | /// 38 | /// The application must call this function once before using a given UART. 39 | /// 40 | /// Which UART to initialize. 41 | /// Target baud rate. 42 | /// Parity mode: . 43 | /// Number of stop bits, only 1 or 2 are valid. 44 | /// An optional callback to invoke when the UART receives data. 45 | /// This can be NULL if the application does not want to read any data from the UART. The 46 | /// application should call to retrieve the data. 47 | UART *UART_Open( 48 | Platform_Unit unit, 49 | unsigned baud, 50 | UART_Parity parity, 51 | unsigned stopBits, 52 | void (*rxCallback)(void)); 53 | 54 | /// 55 | /// Releases a handle once it's finished using a given UART interface. 56 | /// Once released the handle is free to be opened again. 57 | /// 58 | /// The UART handle which is to be released. 59 | void UART_Close(UART *handle); 60 | 61 | /// 62 | /// Buffers the supplied data and asynchronously writes it to the supplied UART. 63 | /// If there is not enough space to buffer the data, then any unbuffered data will be discarded. 64 | /// The size of the buffer is defined by the TX_BUFFER_SIZE macro in UART.c. 65 | /// To send a null-terminated string, call . 66 | /// To send an integer call or 67 | /// . 68 | /// 69 | /// Which UART to write the data to. 70 | /// Start of the data buffer. 71 | /// Size of the data in bytes. 72 | /// ERROR_NONE on success, or an error code. 73 | int32_t UART_Write(UART *handle, const void *data, uintptr_t size); 74 | 75 | /// 76 | /// This function checks if the UART's hardware TX buffer is actually empty. 77 | /// 78 | /// Which UART to read TX buffer status from. 79 | /// 'true' if the UART's hardware TX buffer is empty, 'false' otherwise. 80 | bool UART_IsWriteComplete(UART *handle); 81 | 82 | /// 83 | /// This function blocks until it has read size bytes from the UART. 84 | /// 85 | /// Which UART to read the data from. 86 | /// Start of buffer into which data should be written. 87 | /// Size of data in bytes. 88 | /// ERROR_NONE on success, or an error code. 89 | int32_t UART_Read(UART *handle, void *data, uintptr_t size); 90 | 91 | /// 92 | /// This function returns the number of bytes currently buffered for a UART. 93 | /// 94 | /// Which UART to read the read buffer size of. 95 | /// Number of bytes available to be read. 96 | uintptr_t UART_ReadAvailable(UART *handle); 97 | 98 | /// 99 | /// This function enables/disables hardware flow control. 100 | /// 101 | /// Which UART to enable flow control. 102 | /// ERROR_NONE on success, or ERROR_PARAMETER if debug UART is given. 103 | int UART_HW_FlowControl_Enable(UART *handle, bool enableFlowControl); 104 | 105 | #ifdef __cplusplus 106 | } 107 | #endif 108 | 109 | #endif // #ifndef AZURE_SPHERE_UART_H_ 110 | -------------------------------------------------------------------------------- /mt3620/spi.h: -------------------------------------------------------------------------------- 1 | #ifndef MT3620_REG_SPI_H__ 2 | #define MT3620_REG_SPI_H__ 3 | 4 | #include 5 | #include 6 | 7 | typedef union __attribute__((__packed__)) { 8 | struct __attribute__((__packed__)) { 9 | unsigned mosi_byte_cnt : 4; 10 | unsigned miso_byte_cnt : 4; 11 | bool spi_master_start : 1; 12 | const unsigned res_15_9 : 7; 13 | const bool spi_master_busy : 1; 14 | const unsigned res_18_17 : 2; 15 | unsigned spi_addr_size : 2; 16 | const unsigned res_23_21 : 3; 17 | unsigned spi_addr_ext : 8; 18 | }; 19 | 20 | uint32_t mask; 21 | } mt3620_spi_stcsr_t; 22 | 23 | typedef union __attribute__((__packed__)) { 24 | struct __attribute__((__packed__)) { 25 | unsigned spi_opcode : 8; 26 | unsigned spi_addr : 24; 27 | }; 28 | 29 | uint32_t mask; 30 | } mt3620_spi_soar_t; 31 | 32 | typedef union __attribute__((__packed__)) { 33 | struct __attribute__((__packed__)) { 34 | const unsigned res_1_0 : 2; 35 | bool more_buf_mode : 1; 36 | bool lsb_first : 1; 37 | bool cpol : 1; 38 | bool cpha : 1; 39 | const unsigned res_9_6 : 3; 40 | bool int_en : 1; 41 | bool both_directional_data_mode : 1; 42 | const unsigned res_15_11 : 5; 43 | unsigned rs_clk_sel : 12; 44 | bool clk_mode : 1; 45 | unsigned rs_slave_sel : 3; 46 | }; 47 | 48 | uint32_t mask; 49 | } mt3620_spi_smmr_t; 50 | 51 | typedef union __attribute__((__packed__)) { 52 | struct __attribute__((__packed__)) { 53 | unsigned mosi_bit_cnt : 9; 54 | const unsigned res_11_9 : 3; 55 | unsigned miso_bit_cnt : 9; 56 | const unsigned res_23_21 : 3; 57 | unsigned cmd_bit_cnt : 6; 58 | const unsigned res_31_30 : 2; 59 | }; 60 | 61 | uint32_t mask; 62 | } mt3620_spi_smbcr_t; 63 | 64 | typedef union __attribute__((__packed__)) { 65 | struct __attribute__((__packed__)) { 66 | const bool spi_ok : 1; 67 | const bool spi_write_ok : 1; 68 | const bool spi_read_ok : 1; 69 | const unsigned res_31_3 : 29; 70 | }; 71 | 72 | uint32_t mask; 73 | } mt3620_spi_scsr_t; 74 | 75 | typedef union __attribute__((__packed__)) { 76 | struct __attribute__((__packed__)) { 77 | unsigned cs_polar : 8; 78 | bool dma_mode : 1; 79 | const unsigned res_11_9 : 3; 80 | unsigned cmd_delay_sel : 4; 81 | unsigned end_delay_sel : 4; 82 | const unsigned res_31_20 : 12; 83 | }; 84 | 85 | uint32_t mask; 86 | } mt3620_spi_cspol_t; 87 | 88 | 89 | typedef struct __attribute__((__packed__)) { 90 | mt3620_spi_soar_t soar; 91 | uint32_t sdor[8]; 92 | mt3620_spi_smmr_t smmr; 93 | mt3620_spi_smbcr_t smbcr; 94 | mt3620_spi_stcsr_t stcsr; 95 | // These 4 bytes of dummy data satisfy mt3620 errata 5.1. 96 | uint32_t dummy; 97 | } mt3620_spi_dma_cfg_t; 98 | 99 | typedef struct { 100 | volatile uint32_t stcsr; 101 | volatile uint32_t soar; 102 | volatile uint32_t sdor[8]; 103 | volatile uint32_t smmr; 104 | volatile uint32_t smbcr; 105 | volatile const uint32_t rsv; 106 | volatile uint32_t scsr; 107 | volatile uint32_t cspol; 108 | volatile const uint32_t res_15; 109 | volatile uint32_t dataport; 110 | volatile const uint32_t res_17; 111 | volatile const uint32_t sdir[8]; 112 | } mt3620_spi_t; 113 | 114 | #define MT3620_SPI_BUFFER_SIZE_HALF_DUPLEX 32 115 | #define MT3620_SPI_BUFFER_SIZE_FULL_DUPLEX 16 116 | #define MT3620_SPI_OPCODE_SIZE 4 117 | 118 | #define MT3620_SPI_INTERRUPT(x) (45 + ((x) * 4)) 119 | 120 | #define MT3620_SPI_DMA_TX(x) (0 + ((x) * 2)) 121 | #define MT3620_SPI_DMA_RX(x) (1 + ((x) * 2)) 122 | 123 | #define MT3620_SPI_COUNT 6 124 | static volatile mt3620_spi_t * const mt3620_spi[MT3620_SPI_COUNT] = { 125 | (volatile mt3620_spi_t *)0x38070300, 126 | (volatile mt3620_spi_t *)0x38080300, 127 | (volatile mt3620_spi_t *)0x38090300, 128 | (volatile mt3620_spi_t *)0x380a0300, 129 | (volatile mt3620_spi_t *)0x380b0300, 130 | (volatile mt3620_spi_t *)0x380c0300, 131 | }; 132 | 133 | #define MT3620_SPI_FIELD_READ(index, reg, field) \ 134 | ((mt3620_spi_##reg##_t)mt3620_spi[index]->reg).field 135 | #define MT3620_SPI_FIELD_WRITE(index, reg, field, value) \ 136 | do { mt3620_spi_##reg##_t reg = { .mask = mt3620_spi[index]->reg }; reg.field = value; \ 137 | mt3620_spi[index]->reg = reg.mask; } while (0) 138 | 139 | // Datasheet says this is 80MHz but it's actually 79.04MHz. 140 | #define MT3620_SPI_HCLK (79040000) 141 | #define MT3620_CS_NULL (7) 142 | #define MT3620_CS_MAX (1) 143 | 144 | #endif // #ifndef MT3620_REG_SPI_H__ 145 | -------------------------------------------------------------------------------- /GPIO.h: -------------------------------------------------------------------------------- 1 | /* Copyright (c) Codethink Ltd. All rights reserved. 2 | Licensed under the MIT License. */ 3 | 4 | #ifndef AZURE_SPHERE_GPIO_H_ 5 | #define AZURE_SPHERE_GPIO_H_ 6 | 7 | #include 8 | #include 9 | 10 | #include "Common.h" 11 | 12 | #ifdef __cplusplus 13 | extern "C" { 14 | #endif 15 | 16 | #define ERROR_GPIO_NOT_A_PIN (ERROR_SPECIFIC - 1) 17 | #define ERROR_PWM_UNSUPPORTED_DUTY_CYCLE (ERROR_SPECIFIC - 2) 18 | #define ERROR_PWM_UNSUPPORTED_CLOCK_SEL (ERROR_SPECIFIC - 3) 19 | #define ERROR_PWM_NOT_A_PIN (ERROR_SPECIFIC - 4) 20 | #define ERROR_EINT_NOT_A_PIN (ERROR_SPECIFIC - 5) 21 | #define ERROR_EINT_ATTRIBUTE (ERROR_SPECIFIC - 6) 22 | 23 | /// 24 | /// Configure a pin for output. Call to set the 25 | /// state. 26 | /// 27 | /// A specific pin. 28 | /// Zero on success or an error value as defined in this file or Common.h. 29 | int32_t GPIO_ConfigurePinForOutput(uint32_t pin); 30 | 31 | /// 32 | /// Configure a pin for input. Call to read the 33 | /// state. 34 | /// This function does not control the pull-up or pull-down resistors. 35 | /// If the pin is connected to a possibly-floating input, the application may 36 | /// want to additionally enable these via the register interface. 37 | /// 38 | /// A specific pin. 39 | /// Zero on success or an error value as defined in this file or Common.h. 40 | int32_t GPIO_ConfigurePinForInput(uint32_t pin); 41 | 42 | /// 43 | /// Set the state of a pin which has been configured for output. 44 | /// must be called before this 45 | /// function. 46 | /// 47 | /// A specific pin. 48 | /// true to drive the pin high; false to drive it low. 49 | /// Zero on success or an error value as defined in this file or Common.h. 50 | int32_t GPIO_Write(uint32_t pin, bool state); 51 | 52 | /// 53 | /// Read the state of a pin which has been configured for input. 54 | /// must be called before this 55 | /// function. 56 | /// 57 | /// A specific pin. 58 | /// On return, contains true means the input is high, and false means 59 | /// low. 60 | /// Zero on success or an error value as defined in this file or Common.h. 61 | int32_t GPIO_Read(uint32_t pin, bool *state); 62 | 63 | /// 64 | /// Setup a GPIO pin for PWM output. 65 | /// 66 | /// A specific pin. 67 | /// The desired clock frequency for the PWM counter. 68 | /// The number of clock cycles the PWM signal is high for. 69 | /// The number of clock cycles the PWM signal is low for. 70 | /// Zero on success or an error value as defined in this file or Common.h. 71 | int32_t PWM_ConfigurePin(uint32_t pin, uint32_t clockFrequency, uint32_t onTime, uint32_t offTime); 72 | 73 | 74 | /* External Interrupts */ 75 | 76 | #define GPIO_EINT_PIN_COUNT 24 77 | 78 | typedef enum { 79 | GPIO_EINT_DBNC_FREQ_8KHZ = 0, 80 | GPIO_EINT_DBNC_FREQ_4KHZ = 1, 81 | GPIO_EINT_DBNC_FREQ_2KHZ = 2, 82 | GPIO_EINT_DBNC_FREQ_1KHZ = 3, 83 | GPIO_EINT_DBNC_FREQ_500HZ = 4, 84 | GPIO_EINT_DBNC_FREQ_250HZ = 5, 85 | GPIO_EINT_DBNC_FREQ_125HZ = 6, 86 | GPIO_EINT_DBNC_FREQ_62_5HZ = 7, 87 | GPIO_EINT_DBNC_FREQ_INVALID 88 | } gpio_eint_dbnc_freq_e; 89 | 90 | /// 91 | /// EINT configurations. 92 | /// 93 | /// Whether the interrupt triggers on logic high or not. 94 | /// Whether to detect both transistions. 95 | /// Frequency of debounce counter. 96 | typedef struct { 97 | bool positive; 98 | bool dualEdge; 99 | gpio_eint_dbnc_freq_e freq; 100 | } gpio_eint_attr_t; 101 | 102 | static const gpio_eint_attr_t gpioEINTAttrDefault = { 103 | .positive = true, 104 | .dualEdge = false, 105 | .freq = GPIO_EINT_DBNC_FREQ_8KHZ 106 | }; 107 | 108 | /// 109 | /// Setup a GPIO pin to trigger an external interrupt. 110 | /// 111 | /// A specific pin, only pins < GPIO_EINT_PIN_COUNT are supported. 112 | /// Attributes to set - see struct docs above. 113 | /// Zero on success or an error value as defined in this file or Common.h. 114 | int32_t EINT_ConfigurePin( 115 | uint32_t pin, 116 | gpio_eint_attr_t *attr); 117 | 118 | /// 119 | /// Remove configuration for GPIO pin as EINT source. 120 | /// 121 | /// A specific pin, only pins < GPIO_EINT_PIN_COUNT are supported. 122 | /// Zero on success or an error value as defined in this file or Common.h. 123 | int32_t EINT_DeConfigurePin(uint32_t pin); 124 | 125 | /// 126 | /// Get debounce counter value. 127 | /// 128 | /// A specific pin, only pins < GPIO_EINT_PIN_COUNT are supported. 129 | /// Debounce counter value. 130 | uint8_t EINT_GetDebounceCounter(uint32_t pin); 131 | 132 | #ifdef __cplusplus 133 | } 134 | #endif 135 | 136 | #endif // #ifndef AZURE_SPHERE_GPIO_H_ 137 | -------------------------------------------------------------------------------- /ADC.h: -------------------------------------------------------------------------------- 1 | /* Copyright (c) Codethink Ltd. All rights reserved. 2 | * Licensed under the MIT License. */ 3 | 4 | #ifndef AZURE_SPHERE_ADC_H_ 5 | #define AZURE_SPHERE_ADC_H_ 6 | 7 | #include 8 | #include 9 | 10 | #include "Common.h" 11 | #include "Platform.h" 12 | 13 | #ifdef __cplusplus 14 | extern "C" { 15 | #endif 16 | 17 | typedef struct AdcContext AdcContext; 18 | 19 | /// Returned when the user supplied FIFO is invalid for the number of channels. 20 | #define ERROR_ADC_FIFO_INVALID (ERROR_SPECIFIC - 1) 21 | 22 | /// Returned when a frequency for the ADC period is unsupported. 23 | #define ERROR_ADC_FREQUENCY_UNSUPPORTED (ERROR_SPECIFIC - 2) 24 | 25 | /// Returned when a voltage reference for the V_ref setting is unsupported. 26 | #define ERROR_ADC_VREF_UNSUPPORTED (ERROR_SPECIFIC - 3) 27 | 28 | /// A data structure for separating ADC data from the channel number. 29 | typedef struct { 30 | /// 31 | /// 12 bits of ADC register; with uint12_t range corresponding to 0->V_ref. 32 | /// 33 | uint32_t value; 34 | /// 35 | /// Channel of data (4 accessible channels in total). 36 | /// 37 | uint32_t channel; 38 | } ADC_Data; 39 | 40 | /// 41 | /// The application has to call this function to register a callback and a buffer. 42 | /// The callback will be called in the interrupt and give the user a status return. The 43 | /// data buffer needs to be sized to the number of channels being used. 44 | /// 45 | /// Which ADC block to initialise and acquire a handle for. This is defined 46 | /// in the Platform.h file. 47 | /// A handle to an ADC block or NULL on failure. 48 | AdcContext *ADC_Open(Platform_Unit unit); 49 | 50 | 51 | /// 52 | /// The application has to call this function to release a handle once finished. 53 | /// The application is then free to open it again. 54 | /// 55 | /// The ADC handle which is to be released. 56 | void ADC_Close(AdcContext *handle); 57 | 58 | /// 59 | /// Configures the appropriate ADC block to fill the data buffer 60 | /// and trigger interrupt when ADC data is ready. 61 | /// 62 | /// The ADC block to enable. 63 | /// A pointer to a function that will be called during an interrupt. 64 | /// The status parameter will be set equal to the number of values copied in to the data buffer. 65 | /// 66 | /// How many entries the DMA buffer can hold. 67 | /// A pointer to a data structure used to store formatted ADC data. 68 | /// A pointer to a data structure to contain the unformatted data. 69 | /// Which ADC channels to use, this is a bit mask, so 0111 would 70 | /// enable ADC channels 0, 1 and 2. 71 | /// The reference voltage being used, either between 1.62V and 1.92V 72 | /// or between 2.25V and 2.75V. Defaults to setting for 1.8V between 1.92V and 2.25V. This parameter 73 | /// is scaled in millivolts, so for 1.8V pass 1800 and for 2.5V pass 2500. 74 | int32_t ADC_ReadAsync( 75 | AdcContext *handle, void (*callback)(int32_t status), 76 | uint32_t dmaFifoSize, uint32_t *rawData, 77 | ADC_Data *data, uint16_t channel, 78 | uint16_t referenceVoltage); 79 | 80 | /// 81 | /// Configures the appropriate ADC block to periodically fill the data buffer 82 | /// and trigger interrupt when ADC data is ready. 83 | /// 84 | /// The ADC block to enable. 85 | /// A pointer to a function that will be called during an interrupt. 86 | /// The status parameter will be set equal to the number of values copied in to the data buffer. 87 | /// 88 | /// How many entries the DMA buffer can hold. 89 | /// A pointer to a data structure used to store ADC data. 90 | /// A pointer to a data structure to contain the unformatted data. 91 | /// Which ADC channels to use, this is a bit mask, so 0111 would 92 | /// enable ADC channels 0, 1 and 2. 93 | /// Sets the the frequency at which the ADC block is run. 94 | /// The reference voltage being used, either between 1.62V and 1.92V 95 | /// or between 2.25V and 2.75V. Defaults to setting for 1.8V between 1.92V and 2.25V. This parameter 96 | /// is scaled in millivolts, so for 1.8V pass 1800 and for 2.5V pass 2500. 97 | int32_t ADC_ReadPeriodicAsync( 98 | AdcContext *handle, void (*callback)(int32_t status), 99 | uint32_t dmaFifoSize, ADC_Data *data, uint32_t *rawData, 100 | uint16_t channel, uint32_t frequency, 101 | uint16_t referenceVoltage); 102 | 103 | /// 104 | /// Configures the appropriate ADC block and returns the requested ADC data synchronously. 105 | /// 106 | /// 107 | /// The ADC block to enable. 108 | /// How many entries the DMA buffer can hold. 109 | /// A pointer to a data structure used to store ADC data. 110 | /// A pointer to a data structure to contain the unformatted data. 111 | /// Which ADC channels to use, this is a bit mask, so 0111 would 112 | /// enable ADC channels 0, 1 and 2. 113 | /// The reference voltage being used, either between 1.62V and 1.92V 114 | /// or between 2.25V and 2.75V. Defaults to setting for 1.8V between 1.92V and 2.25V. This parameter 115 | /// is scaled in millivolts, so for 1.8V pass 1800 and for 2.5V pass 2500. 116 | int32_t ADC_ReadSync( 117 | AdcContext *handle, uint32_t dmaFifoSize, 118 | ADC_Data *data, uint32_t *rawData, 119 | uint16_t channel, uint16_t referenceVoltage); 120 | 121 | #ifdef __cplusplus 122 | } 123 | #endif 124 | 125 | #endif 126 | -------------------------------------------------------------------------------- /mt3620/dma.h: -------------------------------------------------------------------------------- 1 | #ifndef MT3620_REG_DMA_H_ 2 | #define MT3620_REG_DMA_H_ 3 | 4 | #include 5 | #include 6 | 7 | typedef union __attribute__((__packed__)) { 8 | struct __attribute__((__packed__)) { 9 | unsigned len : 16; 10 | bool rllen : 1; 11 | const unsigned res_31_17 : 15; 12 | }; 13 | 14 | uint32_t mask; 15 | } mt3620_dma_count_t; 16 | 17 | typedef union __attribute__((__packed__)) { 18 | struct __attribute__((__packed__)) { 19 | unsigned size : 2; 20 | bool sinc : 1; 21 | bool dinc : 1; 22 | bool dreq : 1; 23 | bool b2w : 1; 24 | const unsigned res_7_6 : 2; 25 | unsigned burst : 3; 26 | const unsigned res_12_11 : 2; 27 | bool hiten : 1; 28 | bool toen : 1; 29 | bool iten : 1; 30 | unsigned wpsd : 1; 31 | bool wpen : 1; 32 | unsigned dir : 1; 33 | const unsigned res_31_19 : 13; 34 | }; 35 | 36 | uint32_t mask; 37 | } mt3620_dma_con_t; 38 | 39 | typedef union __attribute__((__packed__)) { 40 | struct __attribute__((__packed__)) { 41 | const unsigned res_14_0 : 15; 42 | bool str : 1; 43 | const unsigned res_31_16 : 16; 44 | }; 45 | 46 | uint32_t mask; 47 | } mt3620_dma_start_t; 48 | 49 | typedef union __attribute__((__packed__)) { 50 | struct __attribute__((__packed__)) { 51 | const unsigned res_12_0 : 13; 52 | const bool hint : 1; 53 | const unsigned res_14 : 1; 54 | const bool _int : 1; 55 | const bool toint : 1; 56 | const unsigned res_31_17 : 15; 57 | }; 58 | 59 | uint32_t mask; 60 | } mt3620_dma_intsta_t; 61 | 62 | typedef union __attribute__((__packed__)) { 63 | struct __attribute__((__packed__)) { 64 | const unsigned res_12_0 : 13; 65 | bool hack : 1; 66 | const unsigned res_14 : 1; 67 | bool ack : 1; 68 | bool toack : 1; 69 | const unsigned res_31_17 : 15; 70 | }; 71 | 72 | uint32_t mask; 73 | } mt3620_dma_ackint_t; 74 | 75 | typedef union __attribute__((__packed__)) { 76 | struct __attribute__((__packed__)) { 77 | const bool full : 1; 78 | const bool empty : 1; 79 | const bool alt : 1; 80 | const unsigned res_31_3 : 29; 81 | }; 82 | 83 | uint32_t mask; 84 | } mt3620_dma_ffsta_t; 85 | 86 | typedef union __attribute__((__packed__)) { 87 | struct __attribute__((__packed__)) { 88 | unsigned altlen : 16; 89 | const unsigned res_30_16 : 15; 90 | bool altscm : 1; 91 | }; 92 | 93 | uint32_t mask; 94 | } mt3620_dma_altlen_t; 95 | 96 | typedef union __attribute__((__packed__)) { 97 | struct __attribute__((__packed__)) { 98 | unsigned hwptr : 16; 99 | const bool hwptr_wrap : 1; 100 | const unsigned res_31_17 : 15; 101 | }; 102 | 103 | uint32_t mask; 104 | } mt3620_dma_hwptr_t; 105 | 106 | typedef union __attribute__((__packed__)) { 107 | struct __attribute__((__packed__)) { 108 | unsigned swptr : 16; 109 | bool swptr_wrap : 1; 110 | const unsigned res_31_17 : 15; 111 | }; 112 | 113 | uint32_t mask; 114 | } mt3620_dma_swptr_t; 115 | 116 | typedef struct { 117 | void * volatile src; 118 | void * volatile dst; 119 | volatile uint32_t wppt; 120 | void * volatile wpto; 121 | volatile uint32_t count; 122 | volatile uint32_t con; 123 | volatile uint32_t start; 124 | volatile const uint32_t intsta; 125 | volatile uint32_t ackint; 126 | volatile const uint32_t rlct; 127 | volatile uint32_t limiter; 128 | void * volatile pgmaddr; 129 | volatile const uint32_t res_12_13[2]; 130 | volatile uint32_t ffcnt; 131 | volatile uint32_t ffsta; 132 | volatile uint32_t altlen; 133 | volatile uint32_t ffsize; 134 | volatile const uint32_t res_18_19[2]; 135 | volatile uint32_t to; 136 | volatile const uint32_t res_21; 137 | volatile uint32_t hwptr; 138 | volatile uint32_t swptr; 139 | void * volatile fixaddr; 140 | volatile const uint32_t res_25_63[39]; 141 | } mt3620_dma_t; 142 | 143 | typedef struct { 144 | volatile const uint32_t glbsta0; 145 | volatile const uint32_t glbsta1; 146 | volatile uint32_t ch_rst; 147 | volatile uint32_t glo_con; 148 | volatile uint32_t group0; 149 | volatile uint32_t group1; 150 | volatile uint32_t isu_vfifo; 151 | volatile uint32_t isu_vfifo_err; 152 | volatile uint32_t ch_en; 153 | volatile uint32_t ch_en_set; 154 | volatile uint32_t ch_en_clr; 155 | volatile const uint32_t res_11; 156 | volatile uint32_t glb_pause; 157 | volatile const uint32_t glb_sta_pause; 158 | volatile const uint32_t res_14_19[6]; 159 | volatile uint32_t set_dreq; 160 | volatile const uint32_t res_21; 161 | volatile uint32_t clr_dreq; 162 | } mt3620_dma_global_t; 163 | 164 | #define MT3620_DMA_COUNT 30 165 | static volatile mt3620_dma_t * const mt3620_dma 166 | = (volatile mt3620_dma_t *)0x21080000; 167 | 168 | static volatile mt3620_dma_global_t * const mt3620_dma_global 169 | = (volatile mt3620_dma_global_t *)0x21084000; 170 | 171 | #define MT3620_DMA_INTERRUPT 77 172 | 173 | #define MT3620_DMA_FIELD_READ(index, reg, field) ((mt3620_dma_##reg##_t)mt3620_dma[index].reg).field 174 | #define MT3620_DMA_FIELD_WRITE(index, reg, field, value) do { mt3620_dma_##reg##_t reg = { .mask = mt3620_dma[index].reg }; reg.field = value; mt3620_dma[index].reg = reg.mask; } while (0) 175 | 176 | #define MT3620_DMA_GLOBAL_FIELD_READ(reg, field) ((mt3620_dma_global_##reg##_t)mt3620_dma_global->reg).field 177 | #define MT3620_DMA_GLOBAL_FIELD_WRITE(reg, field, value) do { mt3620_dma_global_##reg##_t reg = { .mask = mt3620_dma_global->reg }; reg.field = value; mt3620_dma_global->reg = reg.mask; } while (0) 178 | 179 | #endif // #ifdef MT3620_REG_DMA_H_ 180 | -------------------------------------------------------------------------------- /Print.h: -------------------------------------------------------------------------------- 1 | /* Copyright (c) Codethink Ltd. All rights reserved. 2 | Licensed under the MIT License. */ 3 | 4 | #ifndef AZURE_SPHERE_PRINT_H_ 5 | #define AZURE_SPHERE_PRINT_H_ 6 | 7 | #include "UART.h" 8 | #include 9 | #include 10 | 11 | #ifdef __cplusplus 12 | extern "C" { 13 | #endif 14 | 15 | /// Returned when user tries to use printf with invalid fmt spec. 16 | #define ERROR_UART_PRINTF_INVALID (ERROR_SPECIFIC - 1) 17 | 18 | /// 19 | /// Buffers the supplied string and asynchronously writes it to the UART. Does not send 20 | /// the null terminator. If there is not enough space to buffer the entire string, then it will 21 | /// block. 22 | /// See 23 | /// for more information. 24 | /// 25 | /// Which UART to write the string to. 26 | /// Null-terminated string to write to the UART. 27 | /// ERROR_NONE on success, or an error code. 28 | int32_t UART_Print(UART *handle, const char *msg); 29 | 30 | /// 31 | /// Encodes the supplied unsigned integer as a string and asynchronously writes it to the 32 | /// UART. If there is not enough space to buffer the entire string, then it will block. 33 | /// See for more information. 34 | /// 35 | /// Which UART to print the value to. 36 | /// Value to print to the UART. 37 | /// Number base in which to print the integer (1 to 36). 38 | /// Fixed width to print, or zero for automatic. 39 | /// For bases above 10, use upper case characters. 40 | /// ERROR_NONE on success, or an error code. 41 | int32_t UART_PrintUIntBase(UART *handle, int32_t value, unsigned base, unsigned width, bool upper); 42 | 43 | /// 44 | /// Encodes the supplied signed integer as a string and asynchronously writes it to the 45 | /// UART. If there is not enough space to buffer the entire string, then it will block. 46 | /// See for more information. 47 | /// 48 | /// Which UART to print the value to. 49 | /// Value to print to the UART. 50 | /// Number base in which to print the integer (1 to 36). 51 | /// Fixed width to print, or zero for automatic. 52 | /// For bases above 10, use upper case characters. 53 | /// ERROR_NONE on success, or an error code. 54 | int32_t UART_PrintIntBase(UART *handle, int32_t value, unsigned base, unsigned width, bool upper); 55 | 56 | 57 | /// 58 | /// Encodes the supplied signed integer as a decimal string and asynchronously writes it to 59 | /// the UART. If there is not enough space to buffer the entire string, then it will block. 60 | /// See for more information. 61 | /// 62 | /// Which UART to print the value to. 63 | /// Value to print to the UART. 64 | /// ERROR_NONE on success, or an error code. 65 | static inline int32_t UART_PrintInt(UART *handle, int32_t value) 66 | { 67 | return UART_PrintIntBase(handle, value, 10, 0, false); 68 | } 69 | 70 | /// 71 | /// Encodes the supplied signed integer as a decimal string and asynchronously writes it to 72 | /// the UART. If there is not enough space to buffer the entire string, then it will block. 73 | /// See for more information. 74 | /// 75 | /// Which UART to print the value to. 76 | /// Value to print to the UART. 77 | /// ERROR_NONE on success, or an error code. 78 | static inline int32_t UART_PrintUInt(UART *handle, uint32_t value) 79 | { 80 | return UART_PrintUIntBase(handle, value, 10, 0, false); 81 | } 82 | 83 | /// 84 | /// Encodes the supplied unsigned integer as a hex string and asynchronously writes it to 85 | /// the UART. If there is not enough space to buffer the entire string, then it will block. 86 | /// See for more information. 87 | /// 88 | /// Which UART to print the value to. 89 | /// Value to print to the UART. 90 | /// ERROR_NONE on success, or an error code. 91 | static inline int32_t UART_PrintHex(UART *handle, uint32_t value) 92 | { 93 | return UART_PrintUIntBase(handle, value, 16, 8, false); 94 | } 95 | 96 | /// 97 | /// Encodes the supplied unsigned integer as a hex string and asynchronously writes it to 98 | /// the UART. If there is not enough space to buffer the entire string, then it will block. 99 | /// See for more information. 100 | /// 101 | /// Which UART to print the value to. 102 | /// Value to print to the UART. 103 | /// Fixed width to print, or zero for automatic. 104 | /// ERROR_NONE on success, or an error code. 105 | static inline int32_t UART_PrintHexWidth(UART *handle, uint32_t value, uintptr_t width) 106 | { 107 | return UART_PrintUIntBase(handle, value, 16, width, false); 108 | } 109 | 110 | /// 111 | /// Subset of printf functionality for UART, supports format specs: 112 | /// %d, %u, %f, %x, %o, %c and %s. Also supports width and significant place 113 | /// specification (i.e. %08.7f) 114 | /// 115 | /// Which UART to print the value to. 116 | /// Format string. 117 | /// Subsequent arguments are the objects to be printed. 118 | /// ERROR_NONE on success, or an error code. 119 | int32_t UART_Printf(UART *handle, const char *format, ...) 120 | __attribute__ ((format (printf, 2, 3))); 121 | 122 | /// 123 | /// Non variadic variant of printf that consumes a variable array (va_list) 124 | /// 125 | /// Which UART to print the value to. 126 | /// Format string. 127 | /// va_list managed by user code. 128 | /// ERROR_NONE on success, or an error code. 129 | int32_t UART_vPrintf(UART *handle, const char *format, va_list args); 130 | 131 | #ifdef __cplusplus 132 | } 133 | #endif 134 | 135 | #endif 136 | -------------------------------------------------------------------------------- /MBox.h: -------------------------------------------------------------------------------- 1 | /* Copyright (c) Codethink Ltd. All rights reserved. 2 | Licensed under the MIT License. */ 3 | 4 | #ifndef AZURE_SPHERE_MBOX_H_ 5 | #define AZURE_SPHERE_MBOX_H_ 6 | 7 | #include "Common.h" 8 | #include "Platform.h" 9 | 10 | #include 11 | #include 12 | 13 | 14 | #ifdef __cplusplus 15 | extern "C" { 16 | #endif 17 | 18 | /// Returned when user tries to write to FIFO and no space. 19 | #define ERROR_MBOX_FIFO_INSUFFICIENT_SPACE (ERROR_SPECIFIC - 1) 20 | 21 | /// Returned when aquire or release fail. 22 | #define ERROR_MBOX_SEMAPHORE_REQUEST_DENIED (ERROR_SPECIFIC - 2) 23 | 24 | /// Returned if user tries to use M4-M4 semaphore (non-existant). 25 | #define ERROR_MBOX_SEMAPHORE_NOT_PRESENT (ERROR_SPECIFIC - 3) 26 | 27 | /// 28 | /// Opaque MBox handle (contains state for all MBox functionality). 29 | /// 30 | typedef struct MBox MBox; 31 | 32 | typedef enum { 33 | MBOX_FIFO_STATE_NOT_FULL, 34 | MBOX_FIFO_STATE_NOT_EMPTY, 35 | } MBox_FIFO_State; 36 | 37 | /// 38 | /// Acquires a handle to the mailbox's context and defines 39 | /// mailbox callback functions. 40 | /// 41 | /// Which Mailbox to open (M4-M4 or M4-A7). 42 | /// Callback triggered when other core writes to MBox FIFO. 43 | /// If null, interrupt disabled. MBox_FIFO_ReadSync can be used to read FIFO 44 | /// directly. 45 | /// Callback triggered when other core reads 46 | /// from FIFO. If null, interrupt disabled. 47 | /// Callback triggered when not-empty|full 48 | /// thresholds are passed on the read|write FIFOs respectively. If null, 49 | /// interrupt disabled. 50 | /// Pointer to user data used in cbs. 51 | /// Configures non-full interrupt on write 52 | /// FIFO. Set to -1 to leave unconfigured (at reset setting) 53 | /// Configures non-empty interrupt on read 54 | /// FIFO. Set to -1 to leave unconfigured (at reset setting) 55 | /// A handle to a MBox context or NULL on failure. 56 | MBox* MBox_FIFO_Open( 57 | Platform_Unit unit, 58 | void (*rx_cb) (void*), 59 | void (*tx_confirmed_cb) (void*), 60 | void (*fifo_state_change_cb)(void*, MBox_FIFO_State state), 61 | void *user_data, 62 | int8_t non_full_threshold, 63 | int8_t non_empty_threshold); 64 | 65 | /// 66 | /// Releases a mailbox handle. Resets M4 MBox registers. 67 | /// 68 | /// The MBox handle which is to be released. 69 | void MBox_FIFO_Close(MBox *handle); 70 | 71 | /// 72 | /// Resets MBox either on just m4 side, or on both a7 and m4 sides 73 | /// 74 | /// The MBox handle which is to be released. 75 | /// Whether to reset bidirectionally or not. 76 | void MBox_FIFO_Reset(MBox *handle, bool both); 77 | 78 | /// 79 | /// Write to Mbox FIFO. If configured, the interrupts to expect are 80 | /// not_empty and read (if the corresponding read happens on the other core) 81 | /// 82 | /// 83 | /// MBox to write to. 84 | /// CMD buffer (required). 85 | /// DATA buffer (optional). 86 | /// Length of CMD (and DATA) buffer in elements (each 87 | /// element 32 bits). MBOX_FIFO_COUNT_MAX is limit. 88 | /// ERROR_NONE or ERROR_PARAMETER. 89 | int32_t MBox_FIFO_Write( 90 | MBox *handle, 91 | const uint32_t *cmd, 92 | const uint32_t *data, 93 | uintptr_t length); 94 | 95 | /// 96 | /// Synchronous read, blocks until `length` elements have been read. 97 | /// Can hang indefinitely, if timeouts required, specify a rx_cb in the Open 98 | /// method and do reads asynchronously. 99 | /// 100 | /// 101 | /// MBox to read from. 102 | /// CMD buffer to be read into (required). 103 | /// DATA buffer to be read into (optional). 104 | /// Length of CMD (and DATA) buffer in elements (each 105 | /// element 32 bits). MBOX_FIFO_COUNT_MAX is limit. 106 | /// ERROR_NONE or ERROR_PARAMETER. 107 | int32_t MBox_FIFO_ReadSync( 108 | MBox *handle, 109 | uint32_t *cmd, 110 | uint32_t *data, 111 | uintptr_t length); 112 | 113 | /// 114 | /// Check number of elements to be read by partner core. 115 | /// 116 | /// MBox to interrogate. 117 | /// Number of elements that are available for partner core to read. 118 | /// 119 | uintptr_t MBox_FIFO_Writes_Pending(const MBox *handle); 120 | 121 | /// 122 | /// Check number of elements available to read on FIFO. 123 | /// 124 | /// MBox to interrogate. 125 | /// Number of elements that can be read. 126 | uintptr_t MBox_FIFO_Reads_Available(const MBox *handle); 127 | 128 | 129 | /// 130 | /// Acquire semaphore (useful for implementing locks on shared memory). 131 | /// 132 | /// 133 | /// MBox to interrogate. 134 | /// ERROR_NONE, or ERROR_MBOX_SEMAPHORE_REQUEST_DENIED 135 | /// or ERROR_MBOX_SEMAPHORE_NOT_PRESENT on failure. 136 | int32_t MBox_Semaphore_Acquire(MBox* handle); 137 | 138 | /// 139 | /// Release semaphore. 140 | /// 141 | /// 142 | /// MBox to interrogate. 143 | /// ERROR_NONE, or ERROR_MBOX_SEMAPHORE_REQUEST_DENIED 144 | /// or ERROR_MBOX_SEMAPHORE_NOT_PRESENT on failure. 145 | int32_t MBox_Semaphore_Release(MBox* handle); 146 | 147 | 148 | #define MBOX_SW_INT_PORT_COUNT 8 149 | 150 | /// 151 | /// Allows user to define interrupts to enable, and assign a callback 152 | /// to be called when the other core triggers one. 153 | /// 154 | /// 155 | /// MBox to configure. 156 | /// Defines interrupt ports to be enabled. 157 | /// 158 | /// Callback to call when interrupt triggered 159 | /// by other core. 160 | /// ERROR_NONE, or ERROR_PARAMETER. 161 | int32_t MBox_SW_Interrupt_Setup( 162 | MBox *handle, 163 | uint8_t int_enable_flags, 164 | void (*sw_int_cb)(void*, uint8_t port)); 165 | 166 | /// 167 | /// Removes all config from MBox_SW_Interrupt_Setup. 168 | /// 169 | /// MBox to deconfigure. 170 | void MBox_SW_Interrupt_Teardown(MBox *handle); 171 | 172 | /// 173 | /// Fire SW interrupt #`port`. 174 | /// 175 | /// MBox to fire interrupt on. 176 | /// Interrupt to trigger (0-7). 177 | /// ERROR_NONE, or ERROR_PARAMETER. 178 | int32_t MBox_SW_Interrupt_Trigger(MBox *handle, uint8_t port); 179 | 180 | 181 | #ifdef __cplusplus 182 | } 183 | #endif 184 | 185 | #endif // #ifndef AZURE_SPHERE_MBOX_H_ 186 | -------------------------------------------------------------------------------- /mt3620/adc.h: -------------------------------------------------------------------------------- 1 | #ifndef MT3620_REG_ADC_H_ 2 | #define MT3620_REG_ADC_H_ 3 | 4 | #include 5 | #include 6 | 7 | #define MT3620_ADC_INTERRUPT (70) 8 | 9 | #define MT3620_ADC_DMA_CHANNEL 29 10 | 11 | /* Interrupt types */ 12 | #define NO_INTERRUPT_PENDING 1 13 | #define INTERRUPT_CLEAR 2 14 | #define RX_DATA_RECEIVED 4 15 | #define RX_DATA_TIMEOUT 12 16 | 17 | /* Register defaults */ 18 | #define ADC_FIFO_IER_DEF 0x00000000 19 | #define ADC_FIFO_TRI_LVL_DEF 0x0000001C 20 | 21 | //ADC DMA channel number 22 | #define MT3620_ADC_DMA_CHANNEL 29 23 | 24 | #define MT3620_ADC_COUNT 1 25 | 26 | //V_ref ranges for RG_AUXADC[31] (vcm_azure_en) 27 | #define ADC_VREF_1V8_MAX 1980 28 | #define ADC_VREF_1V8_MIN 1620 29 | #define ADC_VREF_2V5_MAX 2750 30 | #define ADC_VREF_2V5_MIN 2250 31 | 32 | /* RG_AUXADC[31] (vcm_azure_en) default setting in the range between ADC_VREF_1V8_MAX */ 33 | /* and ADC_VREF_2V5_MIN. */ 34 | #define ADC_VCM_AZURE_EN_DEF 1 35 | 36 | typedef union __attribute__((__packed__)) { 37 | struct __attribute__((__packed__)) { 38 | bool adc_cr_sw_rst_b : 1; 39 | unsigned rsvoo_b31_b1 : 31; 40 | }; 41 | 42 | uint32_t mask; 43 | } mt3620_adc_global_ctrl_t; 44 | 45 | typedef union __attribute__((__packed__)) { 46 | struct __attribute__((__packed__)) { 47 | bool adc_fsm_en : 1; 48 | unsigned reg_avg_mode : 3; 49 | unsigned reg_t_ch : 4; 50 | bool pmode_en : 1; 51 | unsigned reg_t_init : 7; 52 | uint16_t reg_ch_map : 16; 53 | }; 54 | 55 | uint32_t mask; 56 | } mt3620_adc_ctl0_t; 57 | 58 | typedef union __attribute__((__packed__)) { 59 | struct __attribute__((__packed__)) { 60 | const unsigned res_19_0 : 20; 61 | unsigned reg_adc_data_sync_mode : 1; 62 | bool reg_adc_timestamp_en : 1; 63 | const unsigned res_31_22 : 10; 64 | }; 65 | 66 | uint32_t mask; 67 | } mt3620_adc_ctl2_t; 68 | 69 | typedef union __attribute__((__packed__)) { 70 | struct __attribute__((__packed__)) { 71 | unsigned comp_time_delay : 2; 72 | unsigned comp_preamp_current : 2; 73 | bool comp_preamp_en : 1; 74 | const unsigned res_5 : 1; 75 | bool dither_en : 1; 76 | const unsigned res_7 : 1; 77 | unsigned dither_step_size : 2; 78 | const unsigned res_10 : 1; 79 | unsigned auxadc_in_mux_en : 1; 80 | const unsigned res_12 : 1; 81 | bool vcm_gen_en : 1; 82 | const unsigned res_14 : 1; 83 | bool auxadc_clk_gen_en : 1; 84 | unsigned auxadc_pmu_clk_inv : 1; 85 | unsigned auxadc_clk_src : 1; 86 | const unsigned res_30_18 : 13; 87 | bool vcm_azure_en : 1; 88 | }; 89 | 90 | uint32_t mask; 91 | } mt3620_adc_ctl3_t; 92 | 93 | typedef union __attribute__((__packed__)) { 94 | struct __attribute__((__packed__)) { 95 | bool rxfen : 1; 96 | unsigned res_1 : 1; 97 | bool rxten : 1; 98 | unsigned res_31_3 : 29; 99 | }; 100 | uint32_t mask; 101 | } mt3620_adc_fifo_ier_t; 102 | 103 | typedef union __attribute__((__packed__)) { 104 | struct __attribute__((__packed__)) { 105 | bool rx_dma_en : 1; 106 | const unsigned res_1 : 1; 107 | bool to_cnt_autorst : 1; 108 | const unsigned res_31_3 : 29; 109 | }; 110 | 111 | uint32_t mask; 112 | } mt3620_adc_fifo_dma_en_t; 113 | 114 | typedef union __attribute__((__packed__)) { 115 | struct __attribute__((__packed__)) { 116 | const unsigned res_2_1 : 2; 117 | unsigned rx_tri_lvl : 5; 118 | bool adc_loop : 1; 119 | const unsigned res_31_8 : 24; 120 | }; 121 | 122 | uint32_t mask; 123 | } mt3620_adc_fifo_tri_lvl_t; 124 | 125 | typedef union __attribute__((__packed__)) { 126 | struct __attribute__((__packed__)) { 127 | unsigned wat_time_1 : 3; 128 | unsigned wat_time_2 : 3; 129 | const unsigned res_31_6 : 26; 130 | }; 131 | 132 | uint32_t mask; 133 | } mt3620_adc_fifo_wat_time_t; 134 | 135 | typedef union __attribute__((__packed__)) { 136 | struct __attribute__((__packed__)) { 137 | bool handshake_en : 1; 138 | bool high_speed_en : 1; 139 | bool rto_ext : 1; 140 | const unsigned res_31_3 : 29; 141 | }; 142 | 143 | uint32_t mask; 144 | } mt3620_adc_fifo_handshake_t; 145 | 146 | typedef union __attribute__((__packed__)) { 147 | struct __attribute__((__packed__)) { 148 | const unsigned read_ptr : 5; 149 | const unsigned write_ptr : 5; 150 | const unsigned res_31_10 : 22; 151 | }; 152 | 153 | uint32_t mask; 154 | } mt3620_adc_fifo_debug16_t; 155 | 156 | 157 | typedef struct { 158 | // NB: GPIO registers are mostly common for ISU, ADC, GPIO and I2S 159 | // so, users should use the GPIO API. 160 | volatile uint32_t adc_global_ctrl; 161 | volatile const uint32_t res_1_63[63]; 162 | volatile uint32_t adc_ctl0; 163 | volatile uint32_t reg_period; 164 | volatile uint32_t adc_ctl2; 165 | volatile uint32_t adc_ctl3; 166 | volatile const uint32_t adc_ctl4; 167 | volatile uint32_t res_68_126[59]; 168 | 169 | volatile const uint32_t adc_fifo_rbr; 170 | volatile uint32_t adc_fifo_ier; 171 | volatile uint32_t adc_iir; 172 | volatile uint32_t adc_fifo_fakelcr; 173 | volatile const uint32_t res_131; 174 | volatile const uint32_t adc_fifo_lsr; 175 | volatile const uint32_t res_133_144[12]; 176 | volatile uint32_t adc_fifo_sleep_en; 177 | volatile uint32_t adc_fifo_dma_en; 178 | volatile const uint32_t res_147; 179 | volatile uint32_t adc_fifo_rtocnt; 180 | volatile const uint32_t res_149_150[2]; 181 | volatile uint32_t adc_fifo_tri_lvl; 182 | volatile uint32_t adc_fifo_wak; 183 | volatile uint32_t adc_fifo_wat_time; 184 | volatile uint32_t adc_fifo_handshake; 185 | volatile const uint32_t adc_fifo_debug0; 186 | volatile const uint32_t adc_fifo_debug1; 187 | volatile const uint32_t adc_fifo_debug2; 188 | volatile const uint32_t adc_fifo_debug3; 189 | volatile const uint32_t adc_fifo_debug4; 190 | volatile const uint32_t adc_fifo_debug5; 191 | volatile const uint32_t adc_fifo_debug6; 192 | volatile const uint32_t adc_fifo_debug7; 193 | volatile const uint32_t adc_fifo_debug8; 194 | volatile const uint32_t adc_fifo_debug9; 195 | volatile const uint32_t adc_fifo_debug10; 196 | volatile const uint32_t adc_fifo_debug11; 197 | volatile const uint32_t adc_fifo_debug12; 198 | volatile const uint32_t adc_fifo_debug13; 199 | volatile const uint32_t adc_fifo_debug14; 200 | volatile const uint32_t adc_fifo_debug15; 201 | volatile const uint32_t res_172_180[9]; 202 | volatile const uint32_t adc_fifo_debug16; 203 | } mt3620_adc_t; 204 | 205 | static volatile mt3620_adc_t * const mt3620_adc 206 | = (volatile mt3620_adc_t *)0x38000000; 207 | 208 | #define MT3620_ADC_FIELD_READ(reg, field) \ 209 | ((mt3620_##reg##_t)mt3620_adc->reg).field 210 | #define MT3620_ADC_FIELD_WRITE(reg, field, value) \ 211 | do { mt3620_##reg##_t reg = { .mask = mt3620_adc->reg }; \ 212 | reg.field = value; mt3620_adc->reg = reg.mask; } while (0) 213 | 214 | #endif 215 | -------------------------------------------------------------------------------- /mt3620/i2c.h: -------------------------------------------------------------------------------- 1 | #ifndef MT3620_REG_I2C_H_ 2 | #define MT3620_REG_I2C_H_ 3 | 4 | #include 5 | #include 6 | 7 | typedef union __attribute__((__packed__)) { 8 | struct __attribute__((__packed__)) { 9 | uint8_t x, y, z, w; 10 | }; 11 | 12 | uint32_t mask; 13 | } mt3620_i2c_vec4_t; 14 | 15 | typedef mt3620_i2c_vec4_t mt3620_i2c_mm_cnt_val_phl_t; 16 | typedef mt3620_i2c_vec4_t mt3620_i2c_mm_cnt_val_phh_t; 17 | 18 | typedef union __attribute__((__packed__)) { 19 | struct __attribute__((__packed__)) { 20 | bool mm_int_sta : 1; 21 | bool mm_int_en : 1; 22 | bool mm_int_msk : 1; 23 | const unsigned res_3 : 1; 24 | bool s_int_sta : 1; 25 | bool s_int_en : 1; 26 | bool s_int_msk : 1; 27 | const unsigned res_31_7 : 25; 28 | }; 29 | 30 | uint32_t mask; 31 | } mt3620_i2c_int_ctrl_t; 32 | 33 | typedef union __attribute__((__packed__)) { 34 | struct __attribute__((__packed__)) { 35 | unsigned de_cnt : 5; 36 | const unsigned res_6_5 : 2; 37 | bool sync_en : 1; 38 | const unsigned res_31_8 : 24; 39 | }; 40 | 41 | uint32_t mask; 42 | } mt3620_i2c_mm_pad_con0_t; 43 | 44 | typedef union __attribute__((__packed__)) { 45 | struct __attribute__((__packed__)) { 46 | bool mm_pack_rw0 : 1; 47 | bool mm_pack_rw1 : 1; 48 | bool mm_pack_rw2 : 1; 49 | const unsigned res_3 : 1; 50 | unsigned mm_pack_val : 2; 51 | const unsigned res_31_6 : 26; 52 | }; 53 | 54 | uint32_t mask; 55 | } mt3620_i2c_mm_pack_con0_t; 56 | 57 | typedef union __attribute__((__packed__)) { 58 | struct __attribute__((__packed__)) { 59 | const unsigned mm_ack_data : 8; 60 | const unsigned mm_ack_id : 4; 61 | const unsigned res_31_12 : 20; 62 | }; 63 | 64 | uint32_t mask; 65 | } mt3620_i2c_mm_ack_val_t; 66 | 67 | typedef union __attribute__((__packed__)) { 68 | struct __attribute__((__packed__)) { 69 | bool mm_start_en : 1; 70 | const unsigned res_13_1 : 13; 71 | bool mm_gmode : 1; 72 | bool master_en : 1; 73 | const unsigned res_31_16 : 16; 74 | }; 75 | 76 | uint32_t mask; 77 | } mt3620_i2c_mm_con0_t; 78 | 79 | typedef union __attribute__((__packed__)) { 80 | struct __attribute__((__packed__)) { 81 | const bool bus_busy : 1; 82 | bool mm_arb_had_lose : 1; 83 | const bool mm_start_ready : 1; 84 | const unsigned res_31_3 : 29; 85 | }; 86 | 87 | uint32_t mask; 88 | } mt3620_i2c_mm_status_t; 89 | 90 | typedef union __attribute__((__packed__)) { 91 | struct __attribute__((__packed__)) { 92 | bool rx_fifo_clr : 1; 93 | bool tx_fifo_clr : 1; 94 | const unsigned res_31_2 : 30; 95 | }; 96 | 97 | uint32_t mask; 98 | } mt3620_i2c_fifo_con0_t; 99 | 100 | typedef mt3620_i2c_fifo_con0_t mt3620_i2c_mm_fifo_con0_t; 101 | typedef mt3620_i2c_fifo_con0_t mt3620_i2c_s_fifo_con0_t; 102 | 103 | typedef union __attribute__((__packed__)) { 104 | struct __attribute__((__packed__)) { 105 | const bool rx_fifo_emp : 1; 106 | const bool rx_fifo_full : 1; 107 | const bool rx_fifo_undr : 1; 108 | const bool rx_fifo_ovf : 1; 109 | const bool tx_fifo_emp : 1; 110 | const bool tx_fifo_full : 1; 111 | const bool tx_fifo_undr : 1; 112 | const bool tx_fifo_ovf : 1; 113 | const unsigned res_31_8 : 24; 114 | }; 115 | 116 | uint32_t mask; 117 | } mt3620_i2c_fifo_status_t; 118 | 119 | typedef mt3620_i2c_fifo_status_t mt3620_i2c_mm_fifo_status_t; 120 | typedef mt3620_i2c_fifo_status_t mt3620_i2c_s_fifo_status_t; 121 | 122 | typedef union __attribute__((__packed__)) { 123 | struct __attribute__((__packed__)) { 124 | const unsigned rx_fifo_rptr : 4; 125 | const unsigned rx_fifo_wptr : 4; 126 | const unsigned tx_fifo_rptr : 4; 127 | const unsigned tx_fifo_wptr : 4; 128 | const unsigned res_31_16 : 16; 129 | }; 130 | 131 | uint32_t mask; 132 | } mt3620_i2c_fifo_ptr_t; 133 | 134 | typedef mt3620_i2c_fifo_ptr_t mt3620_i2c_mm_fifo_ptr_t; 135 | typedef mt3620_i2c_fifo_ptr_t mt3620_i2c_s_fifo_ptr_t; 136 | 137 | typedef union __attribute__((__packed__)) { 138 | struct __attribute__((__packed__)) { 139 | const unsigned res_3_1 : 4; 140 | bool dma_hs_en : 1; 141 | unsigned dma_hs_sel : 1; /* 0 = Master, 1 = Slave */ 142 | const unsigned res_31_6 : 26; 143 | }; 144 | 145 | uint32_t mask; 146 | } mt3620_i2c_dma_con0_t; 147 | 148 | typedef union __attribute__((__packed__)) { 149 | struct __attribute__((__packed__)) { 150 | const unsigned res_10_0 : 11; 151 | bool s_ind_en : 1; 152 | const unsigned res_13_12 : 2; 153 | bool s_mute_mode : 1; 154 | bool slave_en : 1; 155 | const unsigned res_31_16 : 16; 156 | }; 157 | 158 | uint32_t mask; 159 | } mt3620_i2c_s_con0_t; 160 | 161 | typedef union __attribute__((__packed__)) { 162 | struct __attribute__((__packed__)) { 163 | const unsigned s_received_id : 7; 164 | const bool s_received_read : 1; 165 | const unsigned res_31_8 : 24; 166 | }; 167 | 168 | uint32_t mask; 169 | } mt3620_i2c_s_id_receive_t; 170 | 171 | typedef mt3620_i2c_s_id_receive_t mt3620_i2c_s_id_receive0_t; 172 | typedef mt3620_i2c_s_id_receive_t mt3620_i2c_s_id_receive1_t; 173 | 174 | typedef struct { 175 | volatile uint32_t int_ctrl; 176 | volatile const uint32_t res_1_15[15]; 177 | volatile uint32_t mm_pad_con0; 178 | volatile uint32_t mm_cnt_val_phl; 179 | volatile uint32_t mm_cnt_val_phh; 180 | volatile const uint32_t res_19_20[2]; 181 | volatile uint32_t mm_cnt_byte_val_pk[3]; 182 | volatile uint32_t mm_slave_id; 183 | volatile const uint32_t res_25; 184 | volatile uint32_t mm_pack_con0; 185 | volatile const uint32_t mm_ack_val; 186 | volatile uint32_t mm_con0; 187 | volatile uint32_t mm_status; 188 | volatile uint32_t mm_fifo_con0; 189 | volatile const uint32_t res_31; 190 | volatile const uint32_t mm_fifo_status; 191 | volatile const uint32_t mm_fifo_ptr; 192 | volatile const uint32_t res_34_35[2]; 193 | volatile uint32_t mm_fifo_data; 194 | volatile const uint32_t res_37_47[11]; 195 | volatile uint32_t dma_con0; 196 | volatile uint32_t s_con0; 197 | volatile uint32_t s_slave_id; 198 | volatile const uint32_t s_id_receive0; 199 | volatile const uint32_t s_id_receive1; 200 | volatile const uint32_t res_53; 201 | volatile uint32_t s_fifo_con0; 202 | volatile const uint32_t res_55; 203 | volatile const uint32_t s_fifo_status; 204 | volatile const uint32_t s_fifo_ptr; 205 | volatile const uint32_t res_58_59[2]; 206 | volatile uint32_t s_fifo_data; 207 | } mt3620_i2c_t; 208 | 209 | #define MT3620_I2C_QUEUE_DEPTH 3 210 | #define MT3620_I2C_TX_FIFO_DEPTH 8 211 | #define MT3620_I2C_RX_FIFO_DEPTH 8 212 | #define MT3620_I2C_PACKET_SIZE_MAX 65535 213 | 214 | #define MT3620_I2C_CLOCK 26000000 215 | #define MT3620_I2C_MAX_SPEED 1000000 216 | 217 | #define MT3620_I2C_INTERRUPT(x) (44 + ((x) * 4)) 218 | 219 | #define MT3620_I2C_DMA_TX(x) (0 + ((x) * 2)) 220 | #define MT3620_I2C_DMA_RX(x) (1 + ((x) * 2)) 221 | 222 | #define MT3620_I2C_COUNT 6 223 | static volatile mt3620_i2c_t * const mt3620_i2c[MT3620_I2C_COUNT] = { 224 | (volatile mt3620_i2c_t *)0x38070200, 225 | (volatile mt3620_i2c_t *)0x38080200, 226 | (volatile mt3620_i2c_t *)0x38090200, 227 | (volatile mt3620_i2c_t *)0x380a0200, 228 | (volatile mt3620_i2c_t *)0x380b0200, 229 | (volatile mt3620_i2c_t *)0x380c0200, 230 | }; 231 | 232 | #define MT3620_I2C_FIELD_READ(index, reg, field) ((mt3620_i2c_##reg##_t)mt3620_i2c[index]->reg).field 233 | #define MT3620_I2C_FIELD_WRITE(index, reg, field, value) do { mt3620_i2c_##reg##_t reg = { .mask = mt3620_i2c[index]->reg }; reg.field = value; mt3620_i2c[index]->reg = reg.mask; } while (0) 234 | 235 | #endif // #ifdef MT3620_REG_I2C_H_ 236 | -------------------------------------------------------------------------------- /GPIO.c: -------------------------------------------------------------------------------- 1 | /* Copyright (c) Codethink Ltd. All rights reserved. 2 | Licensed under the MIT License. */ 3 | 4 | #include 5 | #include 6 | #include 7 | 8 | #include "GPIO.h" 9 | #include "NVIC.h" 10 | #include "mt3620/adc.h" 11 | #include "mt3620/gpio.h" 12 | #include "mt3620/irq.h" 13 | 14 | static mt3620_gpio_block pinToBlock(uint32_t pin) 15 | { 16 | if (pin > MT3620_GPIO_COUNT) { 17 | return MT3620_GPIO_BLOCK_NOT_MAPPED; 18 | } 19 | return mt3620_gpioPinMap[pin]; 20 | } 21 | 22 | static uint32_t getPinMask(uint32_t pin, mt3620_gpio_block block) 23 | { 24 | if (block > MT3620_GPIO_BLOCK_NOT_MAPPED) { 25 | return 0U; 26 | } 27 | 28 | return (1U << (pin - mt3620_gpioBlockStart[block])); 29 | } 30 | 31 | static int32_t ConfigurePin(uint32_t pin, bool asInput) 32 | { 33 | mt3620_gpio_block block = pinToBlock(pin); 34 | if (block >= MT3620_GPIO_BLOCK_NOT_MAPPED) { 35 | return ERROR_GPIO_NOT_A_PIN; 36 | } 37 | 38 | uint32_t pinMask = getPinMask(pin, block); 39 | 40 | if (asInput) { 41 | mt3620_gpio[block]->gpio_pwm_grp_ies_set = pinMask; 42 | mt3620_gpio[block]->gpio_pwm_grp_oe_reset = pinMask; 43 | } else { 44 | mt3620_gpio[block]->gpio_pwm_grp_oe_set = pinMask; 45 | mt3620_gpio[block]->gpio_pwm_grp_ies_reset = pinMask; 46 | } 47 | 48 | return ERROR_NONE; 49 | } 50 | 51 | int32_t GPIO_ConfigurePinForOutput(uint32_t pin) 52 | { 53 | return ConfigurePin(pin, false); 54 | } 55 | 56 | int32_t GPIO_ConfigurePinForInput(uint32_t pin) 57 | { 58 | return ConfigurePin(pin, true); 59 | } 60 | 61 | int32_t GPIO_Write(uint32_t pin, bool state) 62 | { 63 | mt3620_gpio_block block = pinToBlock(pin); 64 | if (block >= MT3620_GPIO_BLOCK_NOT_MAPPED) { 65 | return ERROR_GPIO_NOT_A_PIN; 66 | } 67 | 68 | uint32_t pinMask = getPinMask(pin, block); 69 | 70 | if (state) { 71 | mt3620_gpio[block]->gpio_pwm_grp_dout_set = pinMask; 72 | } else { 73 | mt3620_gpio[block]->gpio_pwm_grp_dout_reset = pinMask; 74 | } 75 | 76 | return ERROR_NONE; 77 | } 78 | 79 | int32_t GPIO_Read(uint32_t pin, bool *state) 80 | { 81 | mt3620_gpio_block block = pinToBlock(pin); 82 | if (block >= MT3620_GPIO_BLOCK_NOT_MAPPED) { 83 | return ERROR_GPIO_NOT_A_PIN; 84 | } 85 | 86 | uint32_t pinMask = getPinMask(pin, block); 87 | 88 | // The GPIO register map for ISU is undocumented, but it looks like the DIN 89 | // offset is at 0xc, as opposed to 0x4 (for GPIO). Similarly, the I2S GPIO 90 | // DIN offset is also different, but at 0x0. 91 | 92 | if (block < MT3620_GPIO_BLOCK_ISU_0) { 93 | *state = pinMask & mt3620_gpio[block]->gpio_pwm_grp_din; 94 | } 95 | else if (block < MT3620_GPIO_BLOCK_I2S_0) { 96 | *state = pinMask & mt3620_gpio[block]->gpio_pwm_grp_din_isu; 97 | } 98 | else { 99 | *state = pinMask & mt3620_gpio[block]->gpio_pwm_grp_global_ctrl__din_i2s; 100 | } 101 | 102 | return ERROR_NONE; 103 | } 104 | 105 | #define PWM_MAX_DUTY_CYCLE 65535 106 | #define PWM_CLOCK_SEL_DEADZONE 5 107 | 108 | int32_t PWM_ConfigurePin(uint32_t pin, uint32_t clockFrequency, uint32_t onTime, uint32_t offTime) 109 | { 110 | mt3620_gpio_block block = pinToBlock(pin); 111 | 112 | if ((block < MT3620_GPIO_BLOCK_0) || (block > MT3620_GPIO_BLOCK_2)) { 113 | return ERROR_PWM_NOT_A_PIN; 114 | } 115 | 116 | uint32_t pinMask = getPinMask(pin, block); 117 | uint32_t pwmBlock = block - MT3620_GPIO_BLOCK_0; 118 | 119 | if (onTime > PWM_MAX_DUTY_CYCLE || offTime > PWM_MAX_DUTY_CYCLE) { 120 | return ERROR_PWM_UNSUPPORTED_DUTY_CYCLE; 121 | } 122 | 123 | uint8_t clockSel; 124 | unsigned frequencyLow = (clockFrequency * (100ULL - PWM_CLOCK_SEL_DEADZONE)) / 100U; 125 | unsigned frequencyHigh = (clockFrequency * (100ULL + PWM_CLOCK_SEL_DEADZONE)) / 100U; 126 | 127 | if (frequencyLow <= MT3620_PWM_32k && frequencyHigh >= MT3620_PWM_32k ) { 128 | clockSel = MT3620_PWM_CLK_SEL_32K; 129 | } 130 | else if (frequencyLow <= MT3620_PWM_2M && frequencyHigh >= MT3620_PWM_2M) { 131 | clockSel = MT3620_PWM_CLK_SEL_2M; 132 | } 133 | else if (frequencyLow <= MT3620_PWM_XTAL && frequencyHigh >= MT3620_PWM_XTAL) { 134 | clockSel = MT3620_PWM_CLK_SEL_XTAL; 135 | } else { 136 | return ERROR_PWM_UNSUPPORTED_CLOCK_SEL; 137 | } 138 | 139 | // Write default values of the registers before starting as recommended in the datasheet 140 | mt3620_pwm[pwmBlock]->pwm_glo_ctrl = MT3620_PWM_GLO_CTRL_DEF; 141 | 142 | // Switch statement starts from 1 since pinMask = pwm pwmBlock + 1 143 | switch(pinMask) { 144 | case 1: 145 | mt3620_pwm[pwmBlock]->pwm0_ctrl = MT3620_PWM_CTRL_DEF; 146 | mt3620_pwm[pwmBlock]->pwm0_param_s0 = MT3620_PWM_PARAM_S0_DEF; 147 | mt3620_pwm[pwmBlock]->pwm0_param_s1 = MT3620_PWM_PARAM_S1_DEF; 148 | break; 149 | case 2: 150 | mt3620_pwm[pwmBlock]->pwm1_ctrl = MT3620_PWM_CTRL_DEF; 151 | mt3620_pwm[pwmBlock]->pwm1_param_s0 = MT3620_PWM_PARAM_S0_DEF; 152 | mt3620_pwm[pwmBlock]->pwm1_param_s1 = MT3620_PWM_PARAM_S1_DEF; 153 | break; 154 | case 4: 155 | mt3620_pwm[pwmBlock]->pwm2_ctrl = MT3620_PWM_CTRL_DEF; 156 | mt3620_pwm[pwmBlock]->pwm2_param_s0 = MT3620_PWM_PARAM_S0_DEF; 157 | mt3620_pwm[pwmBlock]->pwm2_param_s1 = MT3620_PWM_PARAM_S1_DEF; 158 | break; 159 | case 8: 160 | mt3620_pwm[pwmBlock]->pwm3_ctrl = MT3620_PWM_CTRL_DEF; 161 | mt3620_pwm[pwmBlock]->pwm3_param_s0 = MT3620_PWM_PARAM_S0_DEF; 162 | mt3620_pwm[pwmBlock]->pwm3_param_s1 = MT3620_PWM_PARAM_S1_DEF; 163 | break; 164 | default: 165 | break; 166 | } 167 | 168 | MT3620_PWM_FIELD_WRITE(pwmBlock, pwm_glo_ctrl, pwm_tick_clock_sel, clockSel); 169 | 170 | uint32_t pwm_param = ((offTime << 16) | onTime); 171 | switch (pinMask) { 172 | case 1: 173 | MT3620_PWM_FIELD_WRITE(pwmBlock, pwm0_ctrl, pwm_clock_en, 1); 174 | mt3620_pwm[pwmBlock]->pwm0_param_s0 = pwm_param; 175 | mt3620_pwm[pwmBlock]->pwm0_param_s1 = 0; 176 | mt3620_pwm0_ctrl_t pwm0_ctrl = {.mask = mt3620_pwm[pwmBlock]->pwm0_ctrl}; 177 | pwm0_ctrl.S0_stay_cycle = 1; 178 | pwm0_ctrl.pwm_io_ctrl = 0; 179 | mt3620_pwm[pwmBlock]->pwm0_ctrl = pwm0_ctrl.mask; 180 | MT3620_PWM_FIELD_WRITE(pwmBlock, pwm0_ctrl, kick, 1); 181 | break; 182 | case 2: 183 | MT3620_PWM_FIELD_WRITE(pwmBlock, pwm1_ctrl, pwm_clock_en, 1); 184 | mt3620_pwm[pwmBlock]->pwm1_param_s0 = pwm_param; 185 | mt3620_pwm[pwmBlock]->pwm1_param_s1 = 0; 186 | mt3620_pwm1_ctrl_t pwm1_ctrl = { .mask = mt3620_pwm[pwmBlock]->pwm1_ctrl }; 187 | pwm1_ctrl.S0_stay_cycle = 1; 188 | pwm1_ctrl.pwm_io_ctrl = 0; 189 | mt3620_pwm[pwmBlock]->pwm1_ctrl = pwm1_ctrl.mask; 190 | MT3620_PWM_FIELD_WRITE(pwmBlock, pwm1_ctrl, kick, 1); 191 | break; 192 | case 4: 193 | MT3620_PWM_FIELD_WRITE(pwmBlock, pwm2_ctrl, pwm_clock_en, 1); 194 | mt3620_pwm[pwmBlock]->pwm2_param_s0 = pwm_param; 195 | mt3620_pwm[pwmBlock]->pwm2_param_s1 = 0; 196 | mt3620_pwm2_ctrl_t pwm2_ctrl = { .mask = mt3620_pwm[pwmBlock]->pwm2_ctrl }; 197 | pwm2_ctrl.S0_stay_cycle = 1; 198 | pwm2_ctrl.pwm_io_ctrl = 0; 199 | mt3620_pwm[pwmBlock]->pwm2_ctrl = pwm2_ctrl.mask; 200 | MT3620_PWM_FIELD_WRITE(pwmBlock, pwm2_ctrl, kick, 1); 201 | break; 202 | case 8: 203 | MT3620_PWM_FIELD_WRITE(pwmBlock, pwm3_ctrl, pwm_clock_en, 1); 204 | mt3620_pwm[pwmBlock]->pwm3_param_s0 = pwm_param; 205 | mt3620_pwm[pwmBlock]->pwm3_param_s1 = 0; 206 | mt3620_pwm3_ctrl_t pwm3_ctrl = { .mask = mt3620_pwm[pwmBlock]->pwm3_ctrl }; 207 | pwm3_ctrl.S0_stay_cycle = 1; 208 | pwm3_ctrl.pwm_io_ctrl = 0; 209 | mt3620_pwm[pwmBlock]->pwm3_ctrl = pwm3_ctrl.mask; 210 | MT3620_PWM_FIELD_WRITE(pwmBlock, pwm3_ctrl, kick, 1); 211 | break; 212 | default: 213 | break; 214 | } 215 | 216 | return ERROR_NONE; 217 | } 218 | 219 | 220 | #define GPIO_EINT_PRIORITY 2 221 | 222 | 223 | int32_t EINT_ConfigurePin( 224 | uint32_t pin, 225 | gpio_eint_attr_t *attr) 226 | { 227 | if (pin >= GPIO_EINT_PIN_COUNT) { 228 | return ERROR_EINT_NOT_A_PIN; 229 | } 230 | 231 | gpio_eint_attr_t attribute = attr ? *attr : gpioEINTAttrDefault; 232 | 233 | if (attribute.freq >= GPIO_EINT_DBNC_FREQ_INVALID) { 234 | return ERROR_EINT_ATTRIBUTE; 235 | } 236 | 237 | MT3620_IRQ_DBNC_FIELD_WRITE(dbnc_con, en, pin, true); 238 | MT3620_IRQ_DBNC_FIELD_WRITE(dbnc_con, pol, pin, attribute.positive); 239 | MT3620_IRQ_DBNC_FIELD_WRITE(dbnc_con, dual, pin, attribute.dualEdge); 240 | MT3620_IRQ_DBNC_FIELD_WRITE(dbnc_con, prescal, pin, attribute.freq); 241 | 242 | NVIC_EnableIRQ( 243 | MT3620_IRQ_EINT_INTERRUPT(pin), GPIO_EINT_PRIORITY); 244 | 245 | return ERROR_NONE; 246 | } 247 | 248 | 249 | int32_t EINT_DeConfigurePin(uint32_t pin) 250 | { 251 | if (pin >= GPIO_EINT_PIN_COUNT) { 252 | return ERROR_EINT_NOT_A_PIN; 253 | } 254 | 255 | mt3620_irq->dbnc_con[pin] = 0; 256 | 257 | NVIC_DisableIRQ(MT3620_IRQ_EINT_INTERRUPT(pin)); 258 | return ERROR_NONE; 259 | } 260 | 261 | 262 | uint8_t EINT_GetDebounceCounter(uint32_t pin) 263 | { 264 | if (pin >= GPIO_EINT_PIN_COUNT) { 265 | return 0; 266 | } 267 | 268 | return MT3620_IRQ_DBNC_FIELD_READ(dbnc_con, cnt, pin); 269 | } 270 | -------------------------------------------------------------------------------- /GPT.h: -------------------------------------------------------------------------------- 1 | /* Copyright (c) Codethink Ltd. All rights reserved. 2 | Licensed under the MIT License. */ 3 | 4 | #ifndef AZURE_SPHERE_GPT_H_ 5 | #define AZURE_SPHERE_GPT_H_ 6 | 7 | #include "Common.h" 8 | #include "Platform.h" 9 | #include 10 | #include 11 | 12 | #ifdef __cplusplus 13 | extern "C" { 14 | #endif 15 | 16 | /// Returned when user tries to use running timer. 17 | #define ERROR_GPT_ALREADY_RUNNING (ERROR_SPECIFIC - 1) 18 | 19 | /// Returned when user tries to stop or restart non-running timer 20 | #define ERROR_GPT_NOT_RUNNING (ERROR_SPECIFIC - 2) 21 | 22 | /// Returned when user tries to use invalid timeout 23 | #define ERROR_GPT_TIMEOUT_INVALID (ERROR_SPECIFIC - 3) 24 | 25 | /// Returned when user tries to set invalid speed 26 | #define ERROR_GPT_SPEED_INVALID (ERROR_SPECIFIC - 4) 27 | 28 | /// Returned when user tries to pause a paused timer 29 | #define ERROR_GPT_ALREADY_PAUSED (ERROR_SPECIFIC - 5) 30 | 31 | /// Returned when user tries to resume a timer not paused 32 | #define ERROR_GPT_NOT_PAUSED (ERROR_SPECIFIC - 6) 33 | 34 | /// Opaque GPT handle. 35 | typedef struct GPT GPT; 36 | 37 | typedef enum { 38 | GPT_MODE_ONE_SHOT = 0, 39 | GPT_MODE_REPEAT = 1, 40 | GPT_MODE_NONE = 2, 41 | GPT_MODE_COUNT 42 | } GPT_Mode; 43 | 44 | typedef enum { 45 | GPT_UNITS_SECOND = 1, 46 | GPT_UNITS_MILLISEC = 1000, 47 | GPT_UNITS_MICROSEC = 1000000 48 | } GPT_Units; 49 | 50 | /// 51 | /// Acquires a handle to the timer's context. 52 | /// 53 | /// Which timer to initialize and acquire a handle for. 54 | /// Target speed to initialise the timer at (constructor 55 | /// will find closest value supported by HW). 56 | /// Mode that the timer should run in (if unsupported, then 57 | /// this will return NULL) 58 | /// A handle to a timer or NULL on failure. 59 | GPT* GPT_Open(int32_t id, float speedHz, GPT_Mode mode); 60 | 61 | /// 62 | /// Releases a timer handle. 63 | /// Once released the handle is free to be opened again. 64 | /// 65 | /// The GPT handle which is to be released. 66 | void GPT_Close(GPT *handle); 67 | 68 | /// 69 | /// Set timer speed. 70 | /// 71 | /// Timer to update. 72 | /// Target speed - function will find closest value 73 | /// supported by HW). 74 | /// ERROR_NONE on success or an error code. 75 | int32_t GPT_SetSpeed(GPT *handle, float speedHz); 76 | 77 | /// 78 | /// Set timer mode (one shot or repeat). 79 | /// 80 | /// Timer to update. 81 | /// Mode that the timer should run in (if unsupported, then 82 | /// this will error with ERROR_UNSUPPORTED) 83 | /// ERROR_NONE on success or an error code. 84 | int32_t GPT_SetMode(GPT *handle, GPT_Mode mode); 85 | 86 | /// 87 | /// Gives user access to platform unit ID (useful in callbacks) 88 | /// 89 | /// The GPT handle to be queried. 90 | int32_t GPT_GetId(GPT *handle); 91 | 92 | /// 93 | /// Returns enabled status of timer. If the timer is enabled, some 94 | /// operations are disallowed 95 | /// 96 | /// The GPT handle to the timer. 97 | /// Boolean with enabled state. 98 | bool GPT_IsEnabled(GPT *handle); 99 | 100 | /// 101 | /// Allows user to recover actual set speed of timer (may be different 102 | /// from value passed at construction. 103 | /// 104 | /// The GPT handle to the timer. 105 | /// User owned pointer to unsigned, function will write 106 | /// speed value in Hz to this if the function returns ERROR_NONE. 107 | /// ERROR_NONE on success or an error code. 108 | int32_t GPT_GetSpeed(GPT *handle, float *speedHz); 109 | 110 | /// 111 | /// Gives user access to the timer mode set. 112 | /// 113 | /// The GPT handle to the timer. 114 | /// User owned pointer to GPT_Mode; function will write 115 | /// mode value if the function returns ERROR_NONE. 116 | /// ERROR_NONE on success or an error code. 117 | int32_t GPT_GetMode(GPT *handle, GPT_Mode *mode); 118 | 119 | /// 120 | /// Returns timer count. 121 | /// 122 | /// The GPT handle to the timer. 123 | /// Timer count or 0 on failure. 124 | uint32_t GPT_GetCount(GPT *handle); 125 | 126 | /// 127 | /// Returns timer running time in [units]. 128 | /// 129 | /// The GPT handle to the timer. 130 | /// Units of timeout specified. 131 | /// Timer running time or 0 on failure. 132 | uint32_t GPT_GetRunningTime(GPT *handle, GPT_Units units); 133 | 134 | /// 135 | /// Gives user access to number of times timer has expired and 136 | /// restarted. 137 | /// 138 | /// The GPT handle to the timer. 139 | /// User owned pointer to unsigned; function will write 140 | /// number of cycles to this if function returns ERROR_NONE. 141 | /// ERROR_NONE on success or an error code. 142 | int32_t GPT_GetNumCycles(GPT *handle, uint32_t *numCycles); 143 | 144 | /// 145 | /// Stops passed timer. 146 | /// 147 | /// The GPT handle to the timer. 148 | /// ERROR_NONE on success or an error code. 149 | int32_t GPT_Stop(GPT *handle); 150 | 151 | /// 152 | /// Pauses timer and saves state - recovered using GPT_Resume. 153 | /// 154 | /// The GPT handle to the timer. 155 | /// ERROR_NONE on success or an error code. 156 | int32_t GPT_Pause(GPT *handle); 157 | 158 | /// 159 | /// Recovers paused timer's state and sets to enabled. 160 | /// 161 | /// The GPT handle to the timer. 162 | /// ERROR_NONE on success or an error code. 163 | int32_t GPT_Resume(GPT *handle); 164 | 165 | /// 166 | /// Register a callback for the supplied timer (if timer interrupt 167 | /// based). Only one callback can be registered at a time for each timer. 168 | /// If the timer is already running, user should close it first, reopen and 169 | /// start new timer. 170 | /// Only call this function from the main application thread or from a 171 | /// timer callback. 172 | /// 173 | /// Which hardware timer to use. 174 | /// Timeout period in [units]. 175 | /// Units of timeout specified. 176 | /// Function to invoke in interrupt context when the 177 | /// timer expires. Is passed a handle to the timer, so has callback access to 178 | /// this same API. Note that this callback happens within an interrupt, so 179 | /// if there is significant computation, it might be best to defer execution 180 | /// ERROR_NONE on success or an error code. 181 | int32_t GPT_StartTimeout( 182 | GPT *handle, 183 | uint32_t timeout, 184 | GPT_Units units, 185 | void (*callback)(GPT *)); 186 | 187 | /// 188 | /// Start timer in freerun mode. 189 | /// 190 | /// Which hardware timer to use. 191 | /// ERROR_NONE on success or an error code. 192 | int32_t GPT_Start_Freerun(GPT *handle); 193 | 194 | /// 195 | /// Wait for timeout to expire. If the timer doesn't 196 | /// support the level of precision requested (i.e. not all timers support 197 | /// microsecond precison) then ERROR_GPT_TIMEOUT_INVALID is returned. 198 | /// 199 | /// Which hardware timer to use. 200 | /// Timeout period in [units]. 201 | /// Units of timeout specified. 202 | /// ERROR_NONE on success or an error code. 203 | int32_t GPT_WaitTimer_Blocking( 204 | GPT *handle, 205 | uint32_t timeout, 206 | GPT_Units units); 207 | 208 | 209 | ///------------------------Test helpers-------------------------- 210 | 211 | #define GPT_MAX_TEST_SPEEDS 8 212 | 213 | typedef struct { 214 | uint32_t speeds[GPT_MAX_TEST_SPEEDS]; 215 | uint32_t count; 216 | } GPT_TestSpeeds; 217 | 218 | /// 219 | /// Helper function; Allows user to query what speeds are available. 220 | /// If the timer is 2-speed, then this function writes . 221 | /// If the timer supports multiple speeds, then function allows the user 222 | /// access to some intermediate speeds provided by the HW. 223 | /// Use should read datasheet to get more detail on which speeds are supported 224 | /// by which timers. 225 | /// 226 | /// Which hardware timer to use. 227 | /// GPT_TestSpeeds object; to which will be written all 228 | /// test speeds and the number of test speeds 229 | void GPT_GetTestSpeeds(GPT *handle, GPT_TestSpeeds *testSpeeds); 230 | 231 | #ifdef __cplusplus 232 | } 233 | #endif 234 | 235 | #endif // #ifndef AZURE_SPHERE_GPT_H_ 236 | -------------------------------------------------------------------------------- /ADC.c: -------------------------------------------------------------------------------- 1 | /* Copyright (c) Codethink Ltd. All rights reserved. 2 | * Licensed under the MIT License. */ 3 | 4 | #include "ADC.h" 5 | #include "Common.h" 6 | #include "GPT.h" 7 | #include "NVIC.h" 8 | #include "mt3620/adc.h" 9 | #include "mt3620/gpt.h" 10 | #include "mt3620/dma.h" 11 | #include 12 | #include 13 | #include 14 | 15 | // This enables the FIFO clear during initialisation 16 | #define ADC_FIFO_CLEAR 17 | 18 | // ADC interrupt priority 19 | #define ADC_PRIORITY 2 20 | 21 | // ADC frequency 22 | #define ADC_CLK_FREQUENCY 2000000 23 | 24 | struct AdcContext { 25 | bool init; 26 | uint32_t *rawData; 27 | ADC_Data *data; 28 | uint16_t fifoSize; 29 | uint8_t channelsCount; 30 | void (*callback)(int32_t); 31 | }; 32 | 33 | static AdcContext context[MT3620_ADC_COUNT] = {0}; 34 | 35 | static inline uint32_t ADC_UnitToID(Platform_Unit unit) { 36 | if (unit == MT3620_UNIT_ADC0) { 37 | return 0; 38 | } else { 39 | return MT3620_ADC_COUNT + 1; 40 | } 41 | } 42 | 43 | static inline void ADC_DMADisable(){ 44 | mt3620_dma_global->ch_en_set = (0 << MT3620_ADC_DMA_CHANNEL); 45 | MT3620_DMA_FIELD_WRITE(MT3620_ADC_DMA_CHANNEL, start, str, 0); 46 | } 47 | 48 | static uint8_t ADC_CountChannels(uint16_t channelMask) 49 | { 50 | uint8_t numChannels; 51 | for (numChannels = 0; channelMask; numChannels++) { 52 | channelMask &= channelMask - 1; 53 | } 54 | 55 | return numChannels; 56 | } 57 | 58 | AdcContext *ADC_Open(Platform_Unit unit) 59 | { 60 | uint32_t id = ADC_UnitToID (unit); 61 | if (id > MT3620_ADC_COUNT) { 62 | return NULL; 63 | } 64 | 65 | if (id >= MT3620_ADC_COUNT) { 66 | return NULL; 67 | } 68 | 69 | if (context[id].init) { 70 | return NULL; 71 | } 72 | 73 | context[id].init = true; 74 | context[id].callback = NULL; 75 | context[id].rawData = NULL; 76 | context[id].data = NULL; 77 | context[id].fifoSize = 0; 78 | context[id].channelsCount = 0; 79 | 80 | // Manually reset DMA and ADC 81 | mt3620_adc->adc_global_ctrl = 0; 82 | mt3620_adc->adc_global_ctrl = 1; 83 | mt3620_dma_global->ch_en_clr = (1U << MT3620_ADC_DMA_CHANNEL); 84 | 85 | // Set NVIC priority and enable the interrupt for ADC and DMA 86 | NVIC_EnableIRQ(MT3620_ADC_INTERRUPT, ADC_PRIORITY); 87 | 88 | return &context[id]; 89 | } 90 | 91 | void ADC_Close(AdcContext *handle) 92 | { 93 | if (!handle->init) { 94 | return; 95 | } 96 | 97 | // Turn off interrupt and reset trigger level to default 98 | MT3620_ADC_FIELD_WRITE(adc_fifo_ier, rxfen, 0); 99 | mt3620_adc->adc_fifo_tri_lvl = ADC_FIFO_TRI_LVL_DEF; 100 | 101 | /* Turn off ADC finite state machine and periodic mode */ 102 | mt3620_adc_ctl0_t ctl0 = { .mask = mt3620_adc->adc_ctl0 }; 103 | ctl0.adc_fsm_en = 0; 104 | ctl0.pmode_en = 0; 105 | mt3620_adc->adc_ctl0 = ctl0.mask; 106 | 107 | // Disable the interrupt for ADC and DMA 108 | NVIC_DisableIRQ(MT3620_ADC_INTERRUPT); 109 | 110 | handle->init = false; 111 | handle->rawData = NULL; 112 | handle->data = NULL; 113 | handle->fifoSize = 0; 114 | handle->channelsCount = 0; 115 | handle->callback = NULL; 116 | } 117 | 118 | static int32_t ADC_Read( 119 | AdcContext *handle, void (*callback)(int32_t status), 120 | uint32_t dmaFifoSize, ADC_Data *data, 121 | uint32_t *rawData, uint16_t channel, 122 | bool periodic, uint32_t frequency, 123 | uint16_t referenceVoltage) 124 | { 125 | handle->callback = callback; 126 | handle->fifoSize = dmaFifoSize; 127 | handle->rawData = rawData; 128 | handle->data = data; 129 | 130 | mt3620_adc_ctl3_t ctl3 = { .mask = mt3620_adc->adc_ctl3 }; 131 | ctl3.comp_time_delay = 1; 132 | ctl3.comp_preamp_current = 1; 133 | ctl3.comp_preamp_en = 1; 134 | ctl3.dither_en = 1; 135 | ctl3.dither_step_size = 2; 136 | ctl3.auxadc_in_mux_en = 1; 137 | ctl3.vcm_gen_en = 1; 138 | ctl3.auxadc_clk_gen_en = 1; 139 | ctl3.auxadc_pmu_clk_inv = 0; 140 | ctl3.auxadc_clk_src = 0; 141 | if (referenceVoltage > ADC_VREF_1V8_MIN && referenceVoltage < ADC_VREF_1V8_MAX) { 142 | ctl3.vcm_azure_en = 1; 143 | } 144 | else if (referenceVoltage > ADC_VREF_2V5_MIN && referenceVoltage < ADC_VREF_2V5_MAX) { 145 | ctl3.vcm_azure_en = 0; 146 | } 147 | else if (referenceVoltage > ADC_VREF_1V8_MAX && referenceVoltage < ADC_VREF_2V5_MIN) { 148 | ctl3.vcm_azure_en = ADC_VCM_AZURE_EN_DEF; 149 | } else { 150 | return ERROR_ADC_VREF_UNSUPPORTED; 151 | }; 152 | mt3620_adc->adc_ctl3 = ctl3.mask; 153 | 154 | mt3620_adc_ctl0_t ctl0 = { .mask = mt3620_adc->adc_ctl0 }; 155 | ctl0.adc_fsm_en = 0; 156 | ctl0.reg_avg_mode = 0; 157 | ctl0.reg_t_ch = 8; 158 | ctl0.pmode_en = 0; 159 | ctl0.reg_t_init = 20; 160 | ctl0.reg_ch_map = 0; 161 | mt3620_adc->adc_ctl0 = ctl0.mask; 162 | 163 | #ifdef ADC_FIFO_CLEAR 164 | while (true) { 165 | mt3620_adc_fifo_debug16_t debug16 = (mt3620_adc_fifo_debug16_t)mt3620_adc->adc_fifo_debug16; 166 | if (debug16.read_ptr == debug16.write_ptr) { 167 | break; 168 | } 169 | (void)mt3620_adc->adc_fifo_rbr; 170 | } 171 | #endif 172 | 173 | // Wait for time specified in datasheet 174 | GPT *timer = GPT_Open(MT3620_UNIT_GPT3, MT3620_GPT_3_LOW_SPEED, GPT_MODE_NONE); 175 | GPT_WaitTimer_Blocking(timer, 50, GPT_UNITS_MICROSEC); 176 | GPT_Close(timer); 177 | 178 | // Set trigger level based on number of channels selected 179 | uint8_t numChannels = ADC_CountChannels(channel); 180 | 181 | handle->channelsCount = numChannels; 182 | 183 | // Check fifo size is at least as great as the number of channels 184 | if (handle->fifoSize < numChannels) { 185 | return ERROR_ADC_FIFO_INVALID; 186 | } 187 | 188 | // Set DMA registers 189 | mt3620_dma_global->ch_en_set = (1 << MT3620_ADC_DMA_CHANNEL); 190 | 191 | MT3620_DMA_FIELD_WRITE(MT3620_ADC_DMA_CHANNEL, start, str, false); 192 | mt3620_dma[MT3620_ADC_DMA_CHANNEL].pgmaddr = handle->rawData; 193 | mt3620_dma[MT3620_ADC_DMA_CHANNEL].ffsize = handle->fifoSize; 194 | if (handle->fifoSize == 1) { 195 | mt3620_dma[MT3620_ADC_DMA_CHANNEL].count = 1; 196 | } else { 197 | mt3620_dma[MT3620_ADC_DMA_CHANNEL].count = ((3 * mt3620_dma[MT3620_ADC_DMA_CHANNEL].ffsize) / 4); 198 | } 199 | mt3620_dma[MT3620_ADC_DMA_CHANNEL].fixaddr = (void*)&mt3620_adc->adc_fifo_rbr; 200 | mt3620_dma[MT3620_ADC_DMA_CHANNEL].swptr = 0; 201 | 202 | MT3620_DMA_FIELD_WRITE(MT3620_ADC_DMA_CHANNEL, ackint, ack, 1); 203 | 204 | MT3620_ADC_FIELD_WRITE(adc_fifo_dma_en, rx_dma_en, 1); 205 | 206 | mt3620_dma_con_t con = { .mask = mt3620_dma[MT3620_ADC_DMA_CHANNEL].con }; 207 | con.size = 2; 208 | con.dir = 1; 209 | con.dreq = true; 210 | con.iten = true; 211 | con.toen = false; 212 | mt3620_dma[MT3620_ADC_DMA_CHANNEL].con = con.mask; 213 | 214 | MT3620_DMA_FIELD_WRITE(MT3620_ADC_DMA_CHANNEL, start, str, true); 215 | 216 | // Select ADC channel and enable ADC finite state machine 217 | ctl0.mask = mt3620_adc->adc_ctl0; 218 | if (periodic) { 219 | if (frequency > ADC_CLK_FREQUENCY) { 220 | return ERROR_ADC_FREQUENCY_UNSUPPORTED; 221 | } 222 | mt3620_adc->reg_period = (ADC_CLK_FREQUENCY / frequency) - 1; 223 | ctl0.pmode_en = periodic; 224 | } 225 | ctl0.reg_ch_map = channel; 226 | ctl0.adc_fsm_en = 1; 227 | mt3620_adc->adc_ctl0 = ctl0.mask; 228 | 229 | return ERROR_NONE; 230 | } 231 | 232 | int32_t ADC_ReadAsync( 233 | AdcContext *handle, void (*callback)(int32_t status), 234 | uint32_t dmaFifoSize, uint32_t *rawData, 235 | ADC_Data *data, uint16_t channel, uint16_t referenceVoltage) 236 | { 237 | return ADC_Read(handle, callback, dmaFifoSize, data, rawData, channel, 238 | false, 0, referenceVoltage); 239 | } 240 | 241 | int32_t ADC_ReadPeriodicAsync( 242 | AdcContext *handle, void (*callback)(int32_t status), 243 | uint32_t dmaFifoSize, ADC_Data *data, uint32_t *rawData, 244 | uint16_t channel, uint32_t frequency, uint16_t referenceVoltage) 245 | { 246 | return ADC_Read(handle, callback, dmaFifoSize, data, rawData, channel, 247 | true, frequency, referenceVoltage); 248 | } 249 | 250 | static volatile bool ADC_ReadSync_Ready = false; 251 | static int32_t ADC_ReadSync_Status; 252 | 253 | static void ADC_ReadSync_Callback(int32_t status) 254 | { 255 | ADC_ReadSync_Ready = true; 256 | ADC_ReadSync_Status = status; 257 | } 258 | 259 | int32_t ADC_ReadSync( 260 | AdcContext *handle, uint32_t dmaFifoSize, 261 | ADC_Data *data, uint32_t *rawData, 262 | uint16_t channel, uint16_t referenceVoltage) 263 | { 264 | if (ADC_CountChannels(channel) != dmaFifoSize) { 265 | return ERROR_ADC_FIFO_INVALID; 266 | } 267 | 268 | ADC_ReadSync_Ready = false; 269 | int32_t status = ADC_Read(handle, &ADC_ReadSync_Callback, dmaFifoSize, data, rawData, 270 | channel, false, 0, referenceVoltage); 271 | 272 | if (status != ERROR_NONE) { 273 | return status; 274 | } 275 | 276 | while (!ADC_ReadSync_Ready) { 277 | __asm__("wfi"); 278 | } 279 | 280 | // Disable DMA when we're not using it. 281 | ADC_DMADisable(); 282 | 283 | return ADC_ReadSync_Status; 284 | } 285 | 286 | void m4dma_irq_b_adc(void) 287 | { 288 | AdcContext *handle = &context[0]; 289 | 290 | volatile mt3620_dma_t * const dma = &mt3620_dma[MT3620_ADC_DMA_CHANNEL]; 291 | 292 | unsigned count = dma->ffcnt; 293 | unsigned swptr = MT3620_DMA_FIELD_READ(MT3620_ADC_DMA_CHANNEL, swptr, swptr) >> 2; 294 | 295 | unsigned i; 296 | for (i = 0; i < count; i++) { 297 | unsigned j = (swptr + i) & (handle->fifoSize - 1); 298 | handle->data[i].value = (handle->rawData[j] >> 4) & 0xFFF; 299 | handle->data[i].channel = handle->rawData[j] & 0xF; 300 | } 301 | 302 | // Increment swptr by count and toggle wrap bit if we wrapped 303 | swptr += count; 304 | bool wrap = (swptr >= handle->fifoSize); 305 | swptr &= (handle->fifoSize - 1); 306 | dma->swptr = ((dma->swptr ^ (wrap ? 0x00010000 : 0)) & 0xFFFF0000) | (swptr << 2); 307 | 308 | MT3620_DMA_FIELD_WRITE(MT3620_ADC_DMA_CHANNEL, ackint, ack, 1); 309 | 310 | //Pass the number of data copied back to the function caller 311 | handle->callback(count); 312 | } 313 | -------------------------------------------------------------------------------- /Print.c: -------------------------------------------------------------------------------- 1 | /* Copyright (c) Codethink Ltd. All rights reserved. 2 | Licensed under the MIT License. */ 3 | 4 | #include "Print.h" 5 | #include 6 | 7 | #define PRINT_MAX_WIDTH 10 8 | #define PRINT_TEMP_PRINTF_BUFFER 256 9 | #define PRINT_FLOAT_BASE 10 10 | #define PRINT_FLOAT_SIGDIG_DEFAULT 6 11 | 12 | int32_t UART_Print(UART *handle, const char *msg) 13 | { 14 | if (!msg) { 15 | return ERROR_PARAMETER; 16 | } 17 | return UART_Write(handle, (const uint8_t *)msg, __builtin_strlen(msg)); 18 | } 19 | 20 | int32_t UART__PrintUIntBaseFiller( 21 | UART *handle, 22 | int32_t value, 23 | unsigned base, 24 | unsigned width, 25 | bool upper, 26 | char filler) 27 | { 28 | if ((base == 0) || (base > 36)) { 29 | return ERROR_UNSUPPORTED; 30 | } 31 | 32 | if (width > PRINT_MAX_WIDTH) { 33 | return ERROR_UNSUPPORTED; 34 | } 35 | 36 | // Maximum decimal length is ten digits. 37 | char buff[PRINT_MAX_WIDTH]; 38 | 39 | uint32_t p, w, v; 40 | for (p = PRINT_MAX_WIDTH, w = 0, v = value; 41 | (width == 0 ? ((v != 0) || (w == 0)): (w < width)); w++, v /= base) { 42 | unsigned digit; 43 | if ((value != 0) && (v == 0)) { 44 | digit = filler; 45 | } 46 | else { 47 | digit = (v % base); 48 | if (digit < 10) { 49 | digit += '0'; 50 | } else { 51 | digit = (digit - 10) + (upper ? 'A' : 'a'); 52 | } 53 | } 54 | 55 | buff[--p] = digit; 56 | } 57 | 58 | return UART_Write(handle, &buff[p], w); 59 | } 60 | 61 | int32_t UART_PrintUIntBase( 62 | UART *handle, 63 | int32_t value, 64 | unsigned base, 65 | unsigned width, 66 | bool upper) 67 | { 68 | return UART__PrintUIntBaseFiller(handle, value, base, width, upper, '0'); 69 | } 70 | 71 | static inline int32_t UART__PrintIntBaseFiller( 72 | UART *handle, 73 | int32_t value, 74 | unsigned base, 75 | unsigned width, 76 | bool upper, 77 | char filler) 78 | { 79 | if (value < 0) { 80 | int32_t error = UART_Print(handle, "-"); 81 | if (error != ERROR_NONE) { 82 | return error; 83 | } 84 | value = -value; 85 | } 86 | 87 | return UART__PrintUIntBaseFiller(handle, value, base, 88 | width, upper, filler); 89 | } 90 | 91 | int32_t UART_PrintIntBase( 92 | UART *handle, 93 | int32_t value, 94 | unsigned base, 95 | unsigned width, 96 | bool upper) 97 | { 98 | return UART__PrintIntBaseFiller(handle, value, base, width, upper, '0'); 99 | } 100 | 101 | static inline int32_t Int32_Power(int32_t base, int32_t exp) 102 | { 103 | int32_t result = 1; 104 | for (;;) 105 | { 106 | if (exp & 1) 107 | result *= base; 108 | exp >>= 1; 109 | if (!exp) 110 | break; 111 | base *= base; 112 | } 113 | 114 | return result; 115 | } 116 | 117 | static inline int32_t UART__PrintFloatFiller( 118 | UART *handle, 119 | float value, 120 | unsigned sigDigits, 121 | unsigned width, 122 | char filler) 123 | { 124 | if (width > PRINT_MAX_WIDTH) { 125 | return ERROR_UNSUPPORTED; 126 | } 127 | int32_t error; 128 | 129 | if (value < 0) { 130 | error = UART_Print(handle, "-"); 131 | if (error != ERROR_NONE) { 132 | return error; 133 | } 134 | value = -value; 135 | } 136 | 137 | if (sigDigits == 0) { 138 | sigDigits = PRINT_FLOAT_SIGDIG_DEFAULT; 139 | } 140 | 141 | // Get LH and RH side of float 142 | int32_t leftHand, rightHand; 143 | 144 | leftHand = (int32_t)value; 145 | rightHand = ((value - leftHand) * Int32_Power( 146 | PRINT_FLOAT_BASE, sigDigits)); 147 | 148 | int32_t lhWidth; 149 | 150 | if ((width == 0) || ((lhWidth = width - 1 - sigDigits) > 0)) { 151 | lhWidth = 0; 152 | } 153 | 154 | // Print LH.RH 155 | if ((error = UART__PrintUIntBaseFiller(handle, leftHand, 156 | PRINT_FLOAT_BASE, (unsigned)lhWidth, 157 | false, filler)) != ERROR_NONE) { 158 | return error; 159 | } 160 | 161 | if ((error = UART_Print(handle, ".")) != ERROR_NONE) { 162 | return error; 163 | } 164 | 165 | if ((error = UART_PrintUIntBase(handle, rightHand, 166 | PRINT_FLOAT_BASE, sigDigits, 167 | false)) != ERROR_NONE) { 168 | return error; 169 | } 170 | return ERROR_NONE; 171 | } 172 | 173 | int32_t UART_PrintFloatFiller( 174 | UART *handle, 175 | float value, 176 | unsigned sigDigits, 177 | unsigned width) 178 | { 179 | return UART__PrintFloatFiller(handle, value, sigDigits, width, '0'); 180 | } 181 | 182 | typedef struct { 183 | unsigned width; 184 | char type; 185 | char filler; 186 | unsigned sigDigits; 187 | int32_t error; 188 | } formatSpec; 189 | 190 | static inline formatSpec parseFormatSpecifier( 191 | UART *handle, 192 | char *current, 193 | char **end) 194 | { 195 | formatSpec spec = {.width = 0, 196 | .type = 'd', 197 | .filler = ' ', 198 | .sigDigits = 0, 199 | .error = ERROR_NONE}; 200 | if (!handle || !current) { 201 | spec.error = ERROR_PARAMETER; 202 | return spec; 203 | } 204 | bool seenType = false, seenPoint = false; 205 | unsigned temp = 0; 206 | while (!seenType) { 207 | if ((*current >= '0') && (*current <= '9')) { 208 | if ((temp == 0) && (*current == '0')) { 209 | // Filler spec 210 | spec.filler = '0'; 211 | } 212 | else { 213 | temp *= 10; 214 | temp += (*current) - '0'; 215 | } 216 | } 217 | else if (*current == '.') { 218 | spec.width = temp; 219 | temp = 0; 220 | seenPoint = true; 221 | } 222 | else if ((*current >= 'a') || (*current <= 'z')) { 223 | if (*current == 'l') { 224 | // Ignore long types 225 | current++; 226 | continue; 227 | } 228 | spec.type = *current; 229 | if (seenPoint) { 230 | spec.sigDigits = temp; 231 | } 232 | else { 233 | spec.width = temp; 234 | } 235 | seenType = true; 236 | *end = current; 237 | } 238 | else { 239 | spec.error = ERROR_UART_PRINTF_INVALID; 240 | return spec; 241 | } 242 | current++; 243 | } 244 | 245 | return spec; 246 | } 247 | 248 | int32_t UART_vPrintf(UART *handle, const char *format, va_list args) 249 | { 250 | if (!handle) { 251 | return ERROR_PARAMETER; 252 | } 253 | 254 | char tempBuffer[PRINT_TEMP_PRINTF_BUFFER] = {'\0'}; 255 | unsigned tempIndex = 0; 256 | int32_t error = ERROR_NONE; 257 | 258 | // Loop through string and look for format specifier 259 | char *start = NULL, *end = NULL; 260 | formatSpec spec; 261 | char c; 262 | while (*format != '\0') { 263 | if (tempIndex >= (PRINT_TEMP_PRINTF_BUFFER - 1)) { 264 | error = ERROR_UART_PRINTF_INVALID; 265 | break; 266 | } 267 | 268 | if (*format == '%') { 269 | start = (char*)(format + 1); 270 | if (*start == '%') { 271 | // Handle %% pseudo-char 272 | tempBuffer[tempIndex++] = *format; 273 | format += 2; 274 | continue; 275 | } 276 | spec = parseFormatSpecifier( 277 | handle, start, &end); 278 | if (spec.error != ERROR_NONE) { 279 | error = spec.error; 280 | break; 281 | } 282 | format = end + 1; 283 | if (tempIndex > 0) { 284 | // Write previously globbed tempBuffer 285 | tempBuffer[tempIndex] = '\0'; 286 | tempIndex = 0; 287 | if ((error = UART_Print( 288 | handle, (const char*)tempBuffer)) != ERROR_NONE) { 289 | break; 290 | } 291 | } 292 | // Write formatted arg 293 | switch (spec.type) { 294 | case 'd': 295 | case 'i': 296 | error = UART__PrintIntBaseFiller( 297 | handle, va_arg(args, int), 10, 298 | spec.width, false, spec.filler); 299 | break; 300 | case 'u': 301 | error = UART__PrintUIntBaseFiller( 302 | handle, va_arg(args, uint32_t), 10, 303 | spec.width, false, spec.filler); 304 | break; 305 | case 'x': 306 | error = UART__PrintUIntBaseFiller( 307 | handle, va_arg(args, uint32_t), 16, 308 | spec.width, false, spec.filler); 309 | break; 310 | case 'o': 311 | error = UART__PrintUIntBaseFiller( 312 | handle, va_arg(args, uint32_t), 8, 313 | spec.width, false, spec.filler); 314 | break; 315 | case 'f': 316 | error = UART__PrintFloatFiller( 317 | handle, (float)(va_arg(args, double)), spec.sigDigits, 318 | spec.width, spec.filler); 319 | break; 320 | case 's': 321 | error = UART_Print( 322 | handle, va_arg(args, const char*)); 323 | break; 324 | case 'c': 325 | c = (char)va_arg(args, int); 326 | error = UART_Print( 327 | handle, (const char*)(&c)); 328 | break; 329 | } 330 | } 331 | else { 332 | tempBuffer[tempIndex++] = *format; 333 | format++; 334 | } 335 | } 336 | 337 | if (error == ERROR_NONE) { 338 | // Write previously globbed tempBuffer 339 | tempBuffer[tempIndex] = '\0'; 340 | error = UART_Print(handle, (const char*)tempBuffer); 341 | } 342 | 343 | return error; 344 | } 345 | 346 | 347 | int32_t UART_Printf(UART *handle, const char *format, ...) 348 | { 349 | if (!handle) { 350 | return ERROR_PARAMETER; 351 | } 352 | va_list args; 353 | va_start(args, format); 354 | 355 | int32_t error = UART_vPrintf(handle, format, args); 356 | 357 | va_end(args); 358 | return error; 359 | } 360 | -------------------------------------------------------------------------------- /mt3620/i2s.h: -------------------------------------------------------------------------------- 1 | #ifndef MT3620_REG_I2S_H__ 2 | #define MT3620_REG_I2S_H__ 3 | 4 | #include 5 | #include 6 | 7 | typedef enum { 8 | MT3620_I2S_CLK_SEL_XPLL_16M = 0, 9 | MT3620_I2S_CLK_SEL_XPLL_26M = 1, 10 | MT3620_I2S_CLK_SEL_XTAL_26M = 2, 11 | MT3620_I2S_CLK_SEL_EXTERNAL = 3, 12 | } mt3620_i2s_clk_sel_e; 13 | 14 | typedef union __attribute__((__packed__)) { 15 | struct __attribute__((__packed__)) { 16 | bool en : 1; 17 | bool dlfifo_en : 1; 18 | bool ulfifo_en : 1; 19 | bool engen_en : 1; 20 | bool ext_io_ck : 1; 21 | bool ext : 1; 22 | bool ext_lrsw : 1; 23 | bool dl_lrsw : 1; 24 | bool dl_mono : 1; 25 | bool dl_mono_dup : 1; 26 | bool mclk_output_en : 1; 27 | bool i2s_in_clk_en : 1; 28 | bool i2s_out_clk_en : 1; 29 | const unsigned res_13_12 : 2; 30 | const unsigned global_control_rsv_b15 : 1; 31 | const unsigned res_14 : 1; 32 | const unsigned global_control_rsv_b17 : 1; 33 | bool x26m_sel : 1; 34 | bool ext_bclk_inv : 1; 35 | bool neg_cap : 1; 36 | const unsigned global_control_rsv_b21 : 1; 37 | bool dl_empty_value_en : 1; 38 | bool ul_empty_value_en : 1; 39 | mt3620_i2s_clk_sel_e clk_sel_in : 2; 40 | mt3620_i2s_clk_sel_e clk_sel_out : 2; 41 | mt3620_i2s_clk_sel_e ext_mclk_sel : 2; 42 | const unsigned global_control_rsv_b30 : 1; 43 | bool loopback : 1; 44 | }; 45 | 46 | uint32_t mask; 47 | } mt3620_i2s_global_control_t; 48 | 49 | 50 | typedef enum { 51 | MT3620_I2S_WLEN_16BIT = 0, 52 | } mt3620_i2s_wlen_t; 53 | 54 | typedef enum { 55 | MT3620_I2S_SRC_MASTER = 0, 56 | MT3620_I2S_SRC_SLAVE = 1, 57 | } mt3620_i2s_src_t; 58 | 59 | typedef enum { 60 | MT3620_I2S_FMT_TDM = 0, 61 | MT3620_I2S_FMT_I2S = 1, 62 | } mt3620_i2s_fmt_t; 63 | 64 | // The calculation for SR seems to be based on two, 2-bit fields 65 | // The fields look like yyxx 66 | // The sample rate is: ((x + 4) << (y + 1)) * 1000 67 | #define MT3620_I2S_SR_CALC(x) (((((x) & 3) + 4) << (((x) >> 2) + 1)) * 1000U) 68 | #define MT3620_I2S_SR_IS_OFFICIAL(x) ((((x) & 1) == 0) && (((x) >> 2) < 3)) 69 | 70 | typedef enum { 71 | MT3620_I2S_SR_8K = 0x0, 72 | MT3620_I2S_SR_12K = 0x2, 73 | MT3620_I2S_SR_16K = 0x4, 74 | MT3620_I2S_SR_24K = 0x6, 75 | MT3620_I2S_SR_32K = 0x8, 76 | MT3620_I2S_SR_48K = 0xA, 77 | } mt3620_i2s_sr_t; 78 | 79 | #define MT3620_I2S_SR_COUNT 16 80 | 81 | typedef union __attribute__((__packed__)) { 82 | struct __attribute__((__packed__)) { 83 | bool en : 1; 84 | mt3620_i2s_wlen_t wlen : 1; 85 | mt3620_i2s_src_t src : 1; 86 | mt3620_i2s_fmt_t fmt : 1; 87 | const unsigned dl_control_rsv_b4 : 1; 88 | bool wsinv : 1; 89 | const unsigned dl_control_rsv_b6 : 1; 90 | bool dlfifo_2deq : 1; 91 | mt3620_i2s_sr_t sr : 4; 92 | const unsigned dl_control_rsv_b12 : 1; 93 | unsigned bit_per_s : 2; 94 | bool ws_rsync : 1; 95 | const unsigned dl_control_rsv_b16 : 1; 96 | unsigned msb_offset : 7; 97 | const unsigned dl_control_rsv_b28_24 : 5; 98 | unsigned ch_per_s : 2; 99 | const unsigned dl_control_rsv_b31 : 1; 100 | }; 101 | 102 | uint32_t mask; 103 | } mt3620_i2s_dl_control_t; 104 | 105 | typedef union __attribute__((__packed__)) { 106 | struct __attribute__((__packed__)) { 107 | bool en : 1; 108 | mt3620_i2s_wlen_t wlen : 1; 109 | mt3620_i2s_src_t src : 1; 110 | mt3620_i2s_fmt_t fmt : 1; 111 | const unsigned ul_control_rsv_b4 : 1; 112 | bool wsinv : 1; 113 | const unsigned ul_control_rsv_b7_b6 : 2; 114 | unsigned sr : 4; 115 | const unsigned ul_control_rsv_b12 : 1; 116 | unsigned bit_per_s : 2; 117 | bool ws_rsync : 1; 118 | bool down_rate : 1; 119 | unsigned msb_offset : 7; 120 | unsigned update_word : 5; 121 | unsigned ch_per_s : 2; 122 | bool lr_swap : 1; 123 | }; 124 | 125 | uint32_t mask; 126 | } mt3620_i2s_ul_control_t; 127 | 128 | typedef union __attribute__((__packed__)) { 129 | struct __attribute__((__packed__)) { 130 | bool soft_rst : 1; 131 | bool glb_soft_rst : 1; 132 | const unsigned res_3_2 : 2; 133 | bool dl_soft_rst : 1; 134 | const unsigned res_7_5 : 3; 135 | bool ul_soft_rst : 1; 136 | const unsigned res_31_9 : 23; 137 | }; 138 | 139 | uint32_t mask; 140 | } mt3620_i2s_soft_reset_t; 141 | 142 | typedef union __attribute__((__packed__)) { 143 | struct __attribute__((__packed__)) { 144 | const bool afull : 1; 145 | const bool full : 1; 146 | bool clear : 1; 147 | const unsigned res_7_3 : 5; 148 | const unsigned fifo_cnt : 8; 149 | unsigned thr : 8; 150 | const bool ready : 1; 151 | const unsigned res_31_25 : 7; 152 | }; 153 | 154 | uint32_t mask; 155 | } mt3620_i2s_fifo_w_control_t; 156 | 157 | typedef mt3620_i2s_fifo_w_control_t mt3620_i2s_dl_fifo_w_control_t; 158 | typedef mt3620_i2s_fifo_w_control_t mt3620_i2s_ul_fifo_w_control_t; 159 | 160 | typedef union __attribute__((__packed__)) { 161 | struct __attribute__((__packed__)) { 162 | const bool aempty : 1; 163 | const bool empty : 1; 164 | bool clear : 1; 165 | const unsigned res_7_3 : 5; 166 | const unsigned fifo_cnt : 8; 167 | unsigned thr : 8; 168 | const bool ready : 1; 169 | const unsigned res_31_25 : 7; 170 | }; 171 | 172 | uint32_t mask; 173 | } mt3620_i2s_fifo_r_control_t; 174 | 175 | typedef mt3620_i2s_fifo_r_control_t mt3620_i2s_dl_fifo_r_control_t; 176 | typedef mt3620_i2s_fifo_r_control_t mt3620_i2s_ul_fifo_r_control_t; 177 | 178 | typedef union __attribute__((__packed__)) { 179 | struct __attribute__((__packed__)) { 180 | unsigned dl_empt_value_r : 16; 181 | unsigned dl_empt_value_l : 16; 182 | }; 183 | 184 | uint32_t mask; 185 | } mt3620_i2s_dl_empty_value_lr_t; 186 | 187 | typedef union __attribute__((__packed__)) { 188 | struct __attribute__((__packed__)) { 189 | unsigned dl_empt_value_r1 : 16; 190 | unsigned dl_empt_value_l1 : 16; 191 | }; 192 | 193 | uint32_t mask; 194 | } mt3620_i2s_dl_empty_value_l1r1_t; 195 | 196 | typedef union __attribute__((__packed__)) { 197 | struct __attribute__((__packed__)) { 198 | unsigned dbg_sel : 4; 199 | const unsigned res_5_4 : 2; 200 | bool dbg_swap : 1; 201 | bool dbg_sel_src : 1; 202 | unsigned res_31_8 : 24; 203 | }; 204 | 205 | uint32_t mask; 206 | } mt3620_i2s_debug_control_t; 207 | 208 | typedef union __attribute__((__packed__)) { 209 | struct __attribute__((__packed__)) { 210 | unsigned dl_dmareq_mi_num : 2; 211 | const unsigned res_3_2 : 2; 212 | bool dl_ahb_early_en : 1; 213 | const unsigned res_14_5 : 10; 214 | bool dl_dma_mode_sel : 1; 215 | unsigned ul_dmareq_mi_num : 2; 216 | const unsigned res_19_18 : 2; 217 | bool ul_ahb_early_en : 1; 218 | const unsigned res_30_21 : 10; 219 | bool ul_dma_mode_sel : 1; 220 | }; 221 | 222 | uint32_t mask; 223 | } mt3620_i2s_dma_if_control_t; 224 | 225 | typedef union __attribute__((__packed__)) { 226 | struct __attribute__((__packed__)) { 227 | bool dl_wfifo_full : 1; 228 | bool dl_rfifo_empt : 1; 229 | const unsigned res_3_2 : 2; 230 | bool dl_fifo_wrdy : 1; 231 | bool dl_fifo_rrdy : 1; 232 | const unsigned res_7_6 : 2; 233 | bool ul_wfifo_full : 1; 234 | bool ul_rfifo_empt : 1; 235 | const unsigned res_11_10 : 2; 236 | bool ul_fifo_wrdy : 1; 237 | bool ul_fifo_rrdy : 1; 238 | const unsigned res_15_14 : 2; 239 | bool dl_mi_ovf : 1; 240 | bool dl_mi_undr : 1; 241 | bool ul_mi_ovf : 1; 242 | bool ul_mi_undr : 1; 243 | const unsigned res_31_20 : 12; 244 | }; 245 | 246 | uint32_t mask; 247 | } mt3620_i2s_global_int_t; 248 | 249 | typedef mt3620_i2s_global_int_t mt3620_i2s_global_int_en_t; 250 | typedef mt3620_i2s_global_int_t mt3620_i2s_global_int_sts_clr_t; 251 | typedef mt3620_i2s_global_int_t mt3620_i2s_global_int_sts_t; 252 | 253 | typedef union __attribute__((__packed__)) { 254 | struct __attribute__((__packed__)) { 255 | bool pad_i2s_tx : 1; 256 | bool pad_i2s_mclk : 1; 257 | bool pad_i2s_fs : 1; 258 | bool pad_i2s_rx : 1; 259 | bool pad_i2s_bclk : 1; 260 | const unsigned res_31_5 : 27; 261 | }; 262 | 263 | uint32_t mask; 264 | } mt3620_i2s_gpio_t; 265 | 266 | typedef mt3620_i2s_gpio_t mt3620_i2s_gpio_din_t; 267 | typedef mt3620_i2s_gpio_t mt3620_i2s_gpio_dout_t; 268 | typedef mt3620_i2s_gpio_t mt3620_i2s_gpio_dout_set_t; 269 | typedef mt3620_i2s_gpio_t mt3620_i2s_gpio_dout_reset_t; 270 | typedef mt3620_i2s_gpio_t mt3620_i2s_gpio_oe_t; 271 | typedef mt3620_i2s_gpio_t mt3620_i2s_gpio_oe_set_t; 272 | typedef mt3620_i2s_gpio_t mt3620_i2s_gpio_oe_reset_t; 273 | typedef mt3620_i2s_gpio_t mt3620_i2s_gpio_pu_t; 274 | typedef mt3620_i2s_gpio_t mt3620_i2s_gpio_pu_set_t; 275 | typedef mt3620_i2s_gpio_t mt3620_i2s_gpio_pu_reset_t; 276 | typedef mt3620_i2s_gpio_t mt3620_i2s_gpio_pd_t; 277 | typedef mt3620_i2s_gpio_t mt3620_i2s_gpio_pd_set_t; 278 | typedef mt3620_i2s_gpio_t mt3620_i2s_gpio_pd_reset_t; 279 | typedef mt3620_i2s_gpio_t mt3620_i2s_gpio_sr_t; 280 | typedef mt3620_i2s_gpio_t mt3620_i2s_gpio_sr_set_t; 281 | typedef mt3620_i2s_gpio_t mt3620_i2s_gpio_sr_reset_t; 282 | typedef mt3620_i2s_gpio_t mt3620_i2s_gpio_ies_t; 283 | typedef mt3620_i2s_gpio_t mt3620_i2s_gpio_ies_set_t; 284 | typedef mt3620_i2s_gpio_t mt3620_i2s_gpio_ies_reset_t; 285 | 286 | typedef union __attribute__((__packed__)) { 287 | struct __attribute__((__packed__)) { 288 | unsigned pad_i2s_tx : 2; 289 | unsigned pad_i2s_mclk : 2; 290 | unsigned pad_i2s_fs : 2; 291 | unsigned pad_i2s_rx : 2; 292 | unsigned pad_i2s_bclk : 2; 293 | const unsigned res_31_10 : 22; 294 | }; 295 | 296 | uint32_t mask; 297 | } mt3620_i2s_gpio_paddrv_t; 298 | 299 | typedef union __attribute__((__packed__)) { 300 | struct __attribute__((__packed__)) { 301 | unsigned pad_i2s_tx : 2; 302 | unsigned pad_i2s_mclk : 2; 303 | unsigned pad_i2s_fs : 2; 304 | unsigned pad_i2s_rx : 2; 305 | unsigned pad_i2s_bclk : 2; 306 | const unsigned res_31_10 : 22; 307 | }; 308 | 309 | uint32_t mask; 310 | } mt3620_i2s_gpio_rdsel_t; 311 | 312 | typedef union __attribute__((__packed__)) { 313 | struct __attribute__((__packed__)) { 314 | unsigned pad_i2s_tx : 4; 315 | unsigned pad_i2s_mclk : 4; 316 | unsigned pad_i2s_fs : 4; 317 | unsigned pad_i2s_rx : 4; 318 | unsigned pad_i2s_bclk : 4; 319 | const unsigned res_31_20 : 12; 320 | }; 321 | 322 | uint32_t mask; 323 | } mt3620_i2s_gpio_tdsel_t; 324 | 325 | typedef struct { 326 | volatile uint32_t global_control; 327 | volatile uint32_t dl_control; 328 | volatile uint32_t ul_control; 329 | volatile uint32_t soft_reset; 330 | volatile uint32_t dl_fifo_w_control; 331 | volatile uint32_t dl_fifo_r_control; 332 | volatile uint32_t ul_fifo_w_control; 333 | volatile uint32_t ul_fifo_r_control; 334 | volatile uint32_t dl_empty_value_lr; 335 | volatile uint32_t dl_empty_value_l1r1; 336 | volatile uint32_t debug_control; 337 | volatile const uint32_t debug_probe; 338 | volatile uint32_t dma_if_control; 339 | volatile const uint32_t res_16_14[3]; 340 | volatile uint32_t global_int_en; 341 | volatile uint32_t global_int_sts_clr; 342 | volatile uint32_t global_int_sts; 343 | } mt3620_i2s_t; 344 | 345 | #define MT3620_I2S_INTERRUPT(x) (68 + (x)) 346 | 347 | #define MT3620_I2S_DMA_TX(x) (25 + ((x) * 2)) 348 | #define MT3620_I2S_DMA_RX(x) (26 + ((x) * 2)) 349 | 350 | #define MT3620_I2S_STREAM_COUNT 2 351 | 352 | #define MT3620_I2S_COUNT 2 353 | static volatile mt3620_i2s_t * const mt3620_i2s[MT3620_I2S_COUNT] = { 354 | (volatile mt3620_i2s_t *)0x380d0000, 355 | (volatile mt3620_i2s_t *)0x380e0000, 356 | }; 357 | 358 | static volatile uint32_t * const mt3620_i2s_fifo[MT3620_I2S_COUNT] = { 359 | (volatile uint32_t *)0x380f0000, 360 | (volatile uint32_t *)0x38100000, 361 | }; 362 | 363 | #define MT3620_I2S_FIELD_READ(index, reg, field) \ 364 | ((mt3620_i2s_##reg##_t)mt3620_i2s[index]->reg).field 365 | #define MT3620_I2S_FIELD_WRITE(index, reg, field, value) \ 366 | do { mt3620_i2s_##reg##_t reg = { .mask = mt3620_i2s[index]->reg }; reg.field = value; \ 367 | mt3620_i2s[index]->reg = reg.mask; } while (0) 368 | 369 | #endif 370 | -------------------------------------------------------------------------------- /I2CMaster.h: -------------------------------------------------------------------------------- 1 | /* Copyright (c) Codethink Ltd. All rights reserved. 2 | Licensed under the MIT License. */ 3 | 4 | #ifndef AZURE_SPHERE_I2CMASTER_H_ 5 | #define AZURE_SPHERE_I2CMASTER_H_ 6 | 7 | #include "Common.h" 8 | #include "Platform.h" 9 | #include 10 | #include 11 | 12 | #ifdef __cplusplus 13 | extern "C" { 14 | #endif 15 | 16 | /// Returned when an I2C transfer fails to receive an ACK. 17 | #define ERROR_I2C_ADDRESS_NACK (ERROR_SPECIFIC - 1) 18 | 19 | /// Returned when an I2C transfer fails arbitration on a multi-master bus. 20 | #define ERROR_I2C_ARBITRATION_LOST (ERROR_SPECIFIC - 2) 21 | 22 | /// Returned when an I2C transfer fails to complete. 23 | #define ERROR_I2C_TRANSFER_INCOMPLETE (ERROR_SPECIFIC - 3) 24 | 25 | /// Opaque I2C Master handle. 26 | typedef struct I2CMaster I2CMaster; 27 | 28 | /// Enum for standard I2C bus speeds, obviously any integer can be used provided it 29 | /// remains within the hardware capabilities of the target device. 30 | typedef enum { 31 | I2C_BUS_SPEED_LOW = 10000, 32 | I2C_BUS_SPEED_STANDARD = 100000, 33 | I2C_BUS_SPEED_FAST = 400000, 34 | I2C_BUS_SPEED_FAST_PLUS = 1000000, 35 | I2C_BUS_SPEED_HIGH = 3400000, 36 | } I2C_BusSpeed; 37 | 38 | /// I2C transfer entry, used for queueing multiple transfers 39 | typedef struct { 40 | /// 41 | /// Pointer to data to be transmitted. 42 | /// Must not be set at the same time as readData. 43 | /// Must reside in DMA bus accessible RAM for large transfers. 44 | /// 45 | const void *writeData; 46 | /// 47 | /// Pointer to buffer where received data will be written. 48 | /// Must not be set at the same time as writeData. 49 | /// Must reside in DMA bus accessible RAM for large transfers. 50 | /// 51 | void *readData; 52 | /// Length of data to be transmitted or received. 53 | uintptr_t length; 54 | } I2C_Transfer; 55 | 56 | /// 57 | /// Acquires a handle before using a given I2C interface. 58 | /// 59 | /// Which I2C interface to initialize and acquire a handle for. 60 | /// A handle to an I2C interface or NULL on failure. 61 | I2CMaster *I2CMaster_Open(Platform_Unit unit); 62 | 63 | /// 64 | /// Releases a handle once it's finished using a given I2C interface. 65 | /// Once released the handle is free to be opened again. 66 | /// 67 | /// The I2C handle which is to be released. 68 | void I2CMaster_Close(I2CMaster *handle); 69 | 70 | /// Sets the speed of the I2C interface to the closest 71 | /// supported hardware speed. 72 | /// The I2C handle to set the speed of. 73 | /// The approximate bus speed to be set, may be an integer or 74 | /// an enum value provided in . 75 | /// ERROR_NONE on success or an error code. 76 | int32_t I2CMaster_SetBusSpeed(I2CMaster *handle, I2C_BusSpeed speed); 77 | 78 | /// Calculates the exact speed of the I2C interface. 79 | /// The I2C handle to calculate the speed of. 80 | /// A pointer to the variable where the calculated speed will be written 81 | /// or NULL. Only written to when the function returns ERROR_NONE. 82 | /// ERROR_NONE on success or an error code. 83 | int32_t I2CMaster_GetBusSpeed(const I2CMaster *handle, I2C_BusSpeed *speed); 84 | 85 | /// 86 | /// Executes a queue of I2C operations on the interface provided. 87 | /// The maximum queue length and transfer sizes are determined by the target hardware. 88 | /// 89 | /// The I2C handle to perform the transfer on. 90 | /// The subordinate device address of the target I2C device. 91 | /// A pointer to the base of an array of transfers, for more information 92 | /// look at . 93 | /// The total number of transfers in the transfer array. 94 | /// A pointer to a function which will be called once the transfer is 95 | /// completed. 96 | /// ERROR_NONE on success or an error code. 97 | int32_t I2CMaster_TransferSequentialAsync( 98 | I2CMaster *handle, uint16_t address, 99 | const I2C_Transfer *transfer, uint32_t count, 100 | void (*callback)(int32_t status, uintptr_t count)); 101 | 102 | /// 103 | /// Identical to I2CMaster_TransferSequentialAsync, but with facility for 104 | /// user to provide pointer to data that can be accessed in the completetion 105 | /// callback. Note that this callback happens in an interrupt, so if extensive 106 | /// computation is required, it might make sense to defer execution. 107 | /// The maximum queue length and transfer sizes are determined by the target hardware. 108 | /// 109 | /// The I2C handle to perform the transfer on. 110 | /// The subordinate device address of the target I2C device. 111 | /// A pointer to the base of an array of transfers, for more information 112 | /// look at . 113 | /// The total number of transfers in the transfer array. 114 | /// A pointer to a function which will be called once the transfer is 115 | /// completed. 116 | /// Pointer to data that can be accessed in completion callback. 117 | /// ERROR_NONE on success or an error code. 118 | int32_t I2CMaster_TransferSequentialAsync_UserData( 119 | I2CMaster *handle, uint16_t address, 120 | const I2C_Transfer *transfer, uint32_t count, 121 | void (*callback)(int32_t status, uintptr_t count, void* userData), 122 | void *userData); 123 | 124 | /// 125 | /// Executes a back-to-back write then read operations on the I2C interface provided. 126 | /// 127 | /// The I2C handle to perform the transfer on. 128 | /// The subordinate device address of the target I2C device. 129 | /// A pointer to the data to be written. 130 | /// The length of the data to be written. 131 | /// A pointer to the data to be read. 132 | /// The length of the data to be read. 133 | /// A pointer to a function which will be called once the transfer is 134 | /// completed. 135 | /// ERROR_NONE on success or an error code. 136 | static inline int32_t I2CMaster_WriteThenReadAsync( 137 | I2CMaster *handle, uint16_t address, 138 | const void *writeData, uintptr_t writeLength, 139 | void *readData, uintptr_t readLength, 140 | void (*callback)(int32_t status, uintptr_t count)); 141 | 142 | /// 143 | /// Executes a single write operation on the I2C interface provided. 144 | /// 145 | /// The I2C handle to perform the transfer on. 146 | /// The subordinate device address of the target I2C device. 147 | /// A pointer to the data to be written. 148 | /// The length of the data to be written. 149 | /// A pointer to a function which will be called once the transfer is 150 | /// completed. 151 | /// ERROR_NONE on success or an error code. 152 | static inline int32_t I2CMaster_WriteAsync( 153 | I2CMaster *handle, uint16_t address, 154 | const void *data, uintptr_t length, 155 | void (*callback)(int32_t status, uintptr_t count)); 156 | 157 | /// 158 | /// Executes a single read operation on the I2C interface provided. 159 | /// 160 | /// The I2C handle to perform the transfer on. 161 | /// The subordinate device address of the target I2C device. 162 | /// A pointer to the data to be read. 163 | /// The length of the data to be read. 164 | /// A pointer to a function which will be called once the transfer is 165 | /// completed. 166 | /// ERROR_NONE on success or an error code. 167 | static inline int32_t I2CMaster_ReadAsync( 168 | I2CMaster *handle, uint16_t address, 169 | void *data, uintptr_t length, 170 | void (*callback)(int32_t status, uintptr_t count)); 171 | 172 | /// 173 | /// Executes a queue of I2C operations on the interface provided. 174 | /// The maximum queue length and transfer sizes are determined by the target hardware. 175 | /// This is a synchronous wrapper around . 176 | /// 177 | /// The I2C handle to perform the transfer on. 178 | /// The subordinate device address of the target I2C device. 179 | /// A pointer to the base of an array of transfers, for more information 180 | /// look at . 181 | /// The total number of transfers in the transfer array. 182 | /// completed. 183 | /// ERROR_NONE on success or an error code. 184 | int32_t I2CMaster_TransferSequentialSync( 185 | I2CMaster *handle, uint16_t address, 186 | const I2C_Transfer *transfer, uint32_t count); 187 | 188 | /// 189 | /// Executes a back-to-back write then read operations on the I2C interface provided. 190 | /// This is a synchronous wrapper around . 191 | /// 192 | /// The I2C handle to perform the transfer on. 193 | /// The subordinate device address of the target I2C device. 194 | /// A pointer to the data to be written. 195 | /// The length of the data to be written. 196 | /// A pointer to the data to be read. 197 | /// The length of the data to be read. 198 | /// ERROR_NONE on success or an error code. 199 | static inline int32_t I2CMaster_WriteThenReadSync( 200 | I2CMaster *handle, uint16_t address, 201 | const void *writeData, uintptr_t writeLength, 202 | void *readData, uintptr_t readLength); 203 | 204 | /// 205 | /// Executes a single write operation on the I2C interface provided. 206 | /// This is a synchronous wrapper around . 207 | /// 208 | /// The I2C handle to perform the transfer on. 209 | /// The subordinate device address of the target I2C device. 210 | /// A pointer to the data to be written. 211 | /// The length of the data to be written. 212 | /// ERROR_NONE on success or an error code. 213 | static inline int32_t I2CMaster_WriteSync( 214 | I2CMaster *handle, uint16_t address, 215 | const void *data, uintptr_t length); 216 | 217 | /// 218 | /// Executes a single read operation on the I2C interface provided. 219 | /// This is a synchronous wrapper around . 220 | /// 221 | /// The I2C handle to perform the transfer on. 222 | /// The subordinate device address of the target I2C device. 223 | /// A pointer to the data to be read. 224 | /// The length of the data to be read. 225 | /// ERROR_NONE on success or an error code. 226 | static inline int32_t I2CMaster_ReadSync( 227 | I2CMaster *handle, uint16_t address, 228 | void *data, uintptr_t length); 229 | 230 | 231 | static inline int32_t I2CMaster_WriteThenReadAsync( 232 | I2CMaster *handle, uint16_t address, 233 | const void *writeData, uintptr_t writeLength, 234 | void *readData, uintptr_t readLength, 235 | void (*callback)(int32_t status, uintptr_t count)) 236 | { 237 | I2C_Transfer transfer[2] = { 238 | { .writeData = writeData, .readData = NULL , .length = writeLength }, 239 | { .writeData = NULL , .readData = readData, .length = readLength }, 240 | }; 241 | return I2CMaster_TransferSequentialAsync(handle, address, transfer, 2, callback); 242 | } 243 | 244 | static inline int32_t I2CMaster_WriteAsync( 245 | I2CMaster *handle, uint16_t address, 246 | const void *data, uintptr_t length, 247 | void (*callback)(int32_t status, uintptr_t count)) 248 | { 249 | I2C_Transfer transfer = { 250 | .writeData = data, 251 | .readData = NULL, 252 | .length = length, 253 | }; 254 | return I2CMaster_TransferSequentialAsync(handle, address, &transfer, 1, callback); 255 | } 256 | 257 | static inline int32_t I2CMaster_ReadAsync( 258 | I2CMaster *handle, uint16_t address, 259 | void *data, uintptr_t length, 260 | void (*callback)(int32_t status, uintptr_t count)) 261 | { 262 | I2C_Transfer transfer = { 263 | .writeData = NULL, 264 | .readData = data, 265 | .length = length, 266 | }; 267 | return I2CMaster_TransferSequentialAsync(handle, address, &transfer, 1, callback); 268 | } 269 | 270 | 271 | static inline int32_t I2CMaster_WriteThenReadSync( 272 | I2CMaster *handle, uint16_t address, 273 | const void *writeData, uintptr_t writeLength, 274 | void *readData, uintptr_t readLength) 275 | { 276 | I2C_Transfer transfer[2] = { 277 | { .writeData = writeData, .readData = NULL , .length = writeLength }, 278 | { .writeData = NULL , .readData = readData, .length = readLength }, 279 | }; 280 | return I2CMaster_TransferSequentialSync(handle, address, transfer, 2); 281 | } 282 | 283 | static inline int32_t I2CMaster_WriteSync( 284 | I2CMaster *handle, uint16_t address, 285 | const void *data, uintptr_t length) 286 | { 287 | I2C_Transfer transfer = { 288 | .writeData = data, 289 | .readData = NULL, 290 | .length = length, 291 | }; 292 | return I2CMaster_TransferSequentialSync(handle, address, &transfer, 1); 293 | } 294 | 295 | static inline int32_t I2CMaster_ReadSync( 296 | I2CMaster *handle, uint16_t address, 297 | void *data, uintptr_t length) 298 | { 299 | I2C_Transfer transfer = { 300 | .writeData = NULL, 301 | .readData = data, 302 | .length = length, 303 | }; 304 | return I2CMaster_TransferSequentialSync(handle, address, &transfer, 1); 305 | } 306 | 307 | #ifdef __cplusplus 308 | } 309 | #endif 310 | 311 | #endif // #ifndef AZURE_SPHERE_I2CMASTER_H_ 312 | -------------------------------------------------------------------------------- /mt3620/uart.h: -------------------------------------------------------------------------------- 1 | #ifndef MT3620_REG_UART_H__ 2 | #define MT3620_REG_UART_H__ 3 | 4 | #include 5 | #include 6 | 7 | typedef union __attribute__((__packed__)) { 8 | struct __attribute__((__packed__)) { 9 | const uint8_t rbr; 10 | const uint8_t res_15_8; 11 | const uint8_t res_23_16; 12 | const uint8_t res_31_24; 13 | }; 14 | 15 | uint32_t mask; 16 | } mt3620_uart_rbr_t; 17 | 18 | typedef union __attribute__((__packed__)) { 19 | struct __attribute__((__packed__)) { 20 | uint8_t thr; 21 | const uint8_t res_15_8; 22 | const uint8_t res_23_16; 23 | const uint8_t res_31_24; 24 | }; 25 | 26 | uint32_t mask; 27 | } mt3620_uart_thr_t; 28 | 29 | typedef union __attribute__((__packed__)) { 30 | struct __attribute__((__packed__)) { 31 | bool erbfi : 1; 32 | bool etbei : 1; 33 | bool elsi : 1; 34 | bool edssi : 1; 35 | const unsigned res_4 : 1; 36 | bool xoffi : 1; 37 | bool rtsi : 1; 38 | bool ctsi : 1; 39 | const unsigned res_31_8 : 24; 40 | }; 41 | 42 | uint32_t mask; 43 | } mt3620_uart_ier_t; 44 | 45 | typedef enum 46 | { 47 | MT3620_UART_IIR_ID_MODEM_STATUS_CHANGE = 0x00, 48 | MT3620_UART_IIR_ID_NO_INTERRUPT_PENDING = 0x01, 49 | MT3620_UART_IIR_ID_TX_HOLDING_REGISTER_EMPTY = 0x02, 50 | MT3620_UART_IIR_ID_RX_DATA_RECEIVED = 0x04, 51 | MT3620_UART_IIR_ID_LINE_STATUS = 0x06, 52 | MT3620_UART_IIR_ID_RX_DATA_TIMEOUT = 0x0C, 53 | MT3620_UART_IIR_ID_SOFTWARE_FLOW_CONTROL = 0x10, 54 | MT3620_UART_IIR_ID_HARDWARE_FLOW_CONTROL = 0x20, 55 | } mt3620_uart_iir_id_e; 56 | 57 | typedef union __attribute__((__packed__)) { 58 | struct __attribute__((__packed__)) { 59 | const mt3620_uart_iir_id_e iir_id : 6; 60 | const unsigned fifoe : 2; 61 | const unsigned res_31_8 : 24; 62 | }; 63 | 64 | uint32_t mask; 65 | } mt3620_uart_iir_t; 66 | 67 | typedef union __attribute__((__packed__)) { 68 | struct __attribute__((__packed__)) { 69 | bool fifoe : 1; 70 | bool clrr : 1; 71 | bool clrt : 1; 72 | const unsigned res_3 : 1; 73 | unsigned tftl : 2; 74 | unsigned rftl : 2; 75 | const unsigned res_31_8 : 24; 76 | }; 77 | 78 | uint32_t mask; 79 | } mt3620_uart_fcr_t; 80 | 81 | typedef union __attribute__((__packed__)) { 82 | struct __attribute__((__packed__)) { 83 | unsigned wls : 2; 84 | bool stb : 1; 85 | bool pen : 1; 86 | bool eps : 1; 87 | bool sp : 1; 88 | bool sb : 1; 89 | bool dlab : 1; 90 | const unsigned res_31_8 : 24; 91 | }; 92 | 93 | uint32_t mask; 94 | } mt3620_uart_lcr_t; 95 | 96 | typedef union __attribute__((__packed__)) { 97 | struct __attribute__((__packed__)) { 98 | bool dtr : 1; 99 | bool rts : 1; 100 | bool out1 : 1; 101 | bool out2 : 1; 102 | bool loop : 1; 103 | const unsigned res_6_5 : 2; 104 | const bool xoff_status : 1; 105 | const unsigned res_31_8 : 24; 106 | }; 107 | 108 | uint32_t mask; 109 | } mt3620_uart_mcr_t; 110 | 111 | typedef union __attribute__((__packed__)) { 112 | struct __attribute__((__packed__)) { 113 | const bool dr : 1; 114 | const bool oe : 1; 115 | const bool pe : 1; 116 | const bool fe : 1; 117 | const bool bi : 1; 118 | const bool thre : 1; 119 | const bool temt : 1; 120 | const bool fifoerr : 1; 121 | const unsigned res_31_8 : 24; 122 | }; 123 | 124 | uint32_t mask; 125 | } mt3620_uart_lsr_t; 126 | 127 | typedef union __attribute__((__packed__)) { 128 | struct __attribute__((__packed__)) { 129 | bool dctr : 1; 130 | bool ddsr : 1; 131 | bool teri : 1; 132 | bool ddcd : 1; 133 | const bool cts : 1; 134 | const bool dsr : 1; 135 | const bool ri : 1; 136 | const bool dcd : 1; 137 | const unsigned res_31_8 : 24; 138 | }; 139 | 140 | uint32_t mask; 141 | } mt3620_uart_msr_t; 142 | 143 | typedef union __attribute__((__packed__)) { 144 | struct __attribute__((__packed__)) { 145 | uint8_t scr; 146 | const uint8_t res_15_8; 147 | const uint8_t res_23_16; 148 | const uint8_t res_31_24; 149 | }; 150 | 151 | uint32_t mask; 152 | } mt3620_uart_scr_t; 153 | 154 | typedef union __attribute__((__packed__)) { 155 | struct __attribute__((__packed__)) { 156 | uint8_t dll; 157 | const uint8_t res_15_8; 158 | const uint8_t res_23_16; 159 | const uint8_t res_31_24; 160 | }; 161 | 162 | uint32_t mask; 163 | } mt3620_uart_dll_t; 164 | 165 | typedef union __attribute__((__packed__)) { 166 | struct __attribute__((__packed__)) { 167 | uint8_t dlm; 168 | const uint8_t res_15_8; 169 | const uint8_t res_23_16; 170 | const uint8_t res_31_24; 171 | }; 172 | 173 | uint32_t mask; 174 | } mt3620_uart_dlm_t; 175 | 176 | typedef union __attribute__((__packed__)) { 177 | struct __attribute__((__packed__)) { 178 | unsigned sw_flow_cont : 4; 179 | bool enable_e : 1; 180 | const unsigned res_5 : 1; 181 | bool auto_rts : 1; 182 | bool auto_cts : 1; 183 | const unsigned res_31_8 : 24; 184 | }; 185 | 186 | uint32_t mask; 187 | } mt3620_uart_efr_t; 188 | 189 | typedef union __attribute__((__packed__)) { 190 | struct __attribute__((__packed__)) { 191 | uint8_t xon1; 192 | const uint8_t res_15_8; 193 | const uint8_t res_23_16; 194 | const uint8_t res_31_24; 195 | }; 196 | 197 | uint32_t mask; 198 | } mt3620_uart_xon1_t; 199 | 200 | typedef union __attribute__((__packed__)) { 201 | struct __attribute__((__packed__)) { 202 | uint8_t xon2; 203 | const uint8_t res_15_8; 204 | const uint8_t res_23_16; 205 | const uint8_t res_31_24; 206 | }; 207 | 208 | uint32_t mask; 209 | } mt3620_uart_xon2_t; 210 | 211 | typedef union __attribute__((__packed__)) { 212 | struct __attribute__((__packed__)) { 213 | uint8_t xoff1; 214 | const uint8_t res_15_8; 215 | const uint8_t res_23_16; 216 | const uint8_t res_31_24; 217 | }; 218 | 219 | uint32_t mask; 220 | } mt3620_uart_xoff1_t; 221 | 222 | typedef union __attribute__((__packed__)) { 223 | struct __attribute__((__packed__)) { 224 | uint8_t xoff2; 225 | const uint8_t res_15_8; 226 | const uint8_t res_23_16; 227 | const uint8_t res_31_24; 228 | }; 229 | 230 | uint32_t mask; 231 | } mt3620_uart_xoff2_t; 232 | 233 | typedef union __attribute__((__packed__)) { 234 | struct __attribute__((__packed__)) { 235 | const unsigned res_5_0 : 6; 236 | bool ignore_ack : 1; 237 | bool rx_level_ctl_en : 1; 238 | const unsigned res_31_8 : 24; 239 | }; 240 | 241 | uint32_t mask; 242 | } mt3620_uart_rx_level_ctl_t; 243 | 244 | typedef union __attribute__((__packed__)) { 245 | struct __attribute__((__packed__)) { 246 | unsigned speed : 2; 247 | const unsigned res_31_2 : 30; 248 | }; 249 | 250 | uint32_t mask; 251 | } mt3620_uart_highspeed_t; 252 | 253 | typedef union __attribute__((__packed__)) { 254 | struct __attribute__((__packed__)) { 255 | uint8_t sample_count; 256 | const uint8_t res_15_8; 257 | const uint8_t res_23_16; 258 | const uint8_t res_31_24; 259 | }; 260 | 261 | uint32_t mask; 262 | } mt3620_uart_sample_count_t; 263 | 264 | typedef union __attribute__((__packed__)) { 265 | struct __attribute__((__packed__)) { 266 | uint8_t sample_point; 267 | const uint8_t res_15_8; 268 | const uint8_t res_23_16; 269 | const uint8_t res_31_24; 270 | }; 271 | 272 | uint32_t mask; 273 | } mt3620_uart_sample_point_t; 274 | 275 | typedef union __attribute__((__packed__)) { 276 | struct __attribute__((__packed__)) { 277 | unsigned guard_cnt : 4; 278 | bool guard_en : 1; 279 | const unsigned res_31_2 : 27; 280 | }; 281 | 282 | uint32_t mask; 283 | } mt3620_uart_guard_t; 284 | 285 | typedef union __attribute__((__packed__)) { 286 | struct __attribute__((__packed__)) { 287 | uint8_t escape_dat; 288 | const uint8_t res_15_8; 289 | const uint8_t res_23_16; 290 | const uint8_t res_31_24; 291 | }; 292 | 293 | uint32_t mask; 294 | } mt3620_uart_escape_dat_t; 295 | 296 | typedef union __attribute__((__packed__)) { 297 | struct __attribute__((__packed__)) { 298 | bool esc_en : 1; 299 | const unsigned res_31_1 : 31; 300 | }; 301 | 302 | uint32_t mask; 303 | } mt3620_uart_escape_en_t; 304 | 305 | typedef union __attribute__((__packed__)) { 306 | struct __attribute__((__packed__)) { 307 | const unsigned res_0 : 1; 308 | bool sw_rto_limit_en : 1; 309 | unsigned sw_rto_limit : 6; 310 | const unsigned res_31_1 : 24; 311 | }; 312 | 313 | uint32_t mask; 314 | } mt3620_uart_swo_rto_limit_t; 315 | 316 | typedef union __attribute__((__packed__)) { 317 | struct __attribute__((__packed__)) { 318 | bool vfifo_en : 1; 319 | const unsigned res_31_1 : 31; 320 | }; 321 | 322 | uint32_t mask; 323 | } mt3620_uart_vfifo_en_t; 324 | 325 | typedef union __attribute__((__packed__)) { 326 | struct __attribute__((__packed__)) { 327 | unsigned rxtrig : 6; 328 | const unsigned res_31_6 : 26; 329 | }; 330 | 331 | uint32_t mask; 332 | } mt3620_uart_rxtrig_t; 333 | 334 | typedef union __attribute__((__packed__)) { 335 | struct __attribute__((__packed__)) { 336 | uint8_t fracdiv_l; 337 | const uint8_t res_15_8; 338 | const uint8_t res_23_16; 339 | const uint8_t res_31_24; 340 | }; 341 | 342 | uint32_t mask; 343 | } mt3620_uart_fracdiv_l_t; 344 | 345 | typedef union __attribute__((__packed__)) { 346 | struct __attribute__((__packed__)) { 347 | unsigned fracdiv_m : 2; 348 | const unsigned res_31_2 : 30; 349 | }; 350 | 351 | uint32_t mask; 352 | } mt3620_uart_fracdiv_m_t; 353 | 354 | typedef union __attribute__((__packed__)) { 355 | struct __attribute__((__packed__)) { 356 | const bool fifoe : 1; 357 | const bool clrr : 1; 358 | const bool clrt : 1; 359 | const unsigned res_3 : 1; 360 | const unsigned tftl : 2; 361 | const unsigned rftl : 2; 362 | const unsigned res_31_8 : 24; 363 | }; 364 | 365 | uint32_t mask; 366 | } mt3620_uart_fcr_rd_t; 367 | 368 | typedef union __attribute__((__packed__)) { 369 | struct __attribute__((__packed__)) { 370 | bool rx_dma_hsk_en : 1; 371 | bool tx_dma_hsk_en : 1; 372 | bool tx_auto_trans : 1; 373 | const unsigned res_31_3 : 29; 374 | }; 375 | 376 | uint32_t mask; 377 | } mt3620_uart_extend_add_t; 378 | 379 | typedef union __attribute__((__packed__)) { 380 | struct __attribute__((__packed__)) { 381 | const unsigned rx_offset : 6; 382 | const unsigned res_31_6 : 26; 383 | }; 384 | 385 | uint32_t mask; 386 | } mt3620_uart_rx_offset_t; 387 | 388 | typedef union __attribute__((__packed__)) { 389 | struct __attribute__((__packed__)) { 390 | const unsigned tx_offset : 5; 391 | const unsigned res_31_5 : 27; 392 | }; 393 | 394 | uint32_t mask; 395 | } mt3620_uart_tx_offset_t; 396 | 397 | typedef union __attribute__((__packed__)) { 398 | struct __attribute__((__packed__)) { 399 | const bool prior1 : 1; 400 | const bool prior2to : 1; 401 | const bool prior2 : 1; 402 | const bool prior3 : 1; 403 | const bool prior4 : 1; 404 | const bool prior5 : 1; 405 | const bool prior6 : 1; 406 | const bool hwfifo_limit : 1; 407 | const unsigned res_31_8 : 24; 408 | }; 409 | 410 | uint32_t mask; 411 | } mt3620_uart_interupt_sta_t; 412 | 413 | 414 | typedef struct { 415 | union { 416 | const volatile uint32_t rbr; 417 | volatile uint32_t thr; 418 | volatile uint32_t dll; 419 | }; 420 | 421 | union { 422 | volatile uint32_t ier; 423 | volatile uint32_t dlm; 424 | }; 425 | 426 | union { 427 | volatile const uint32_t iir; 428 | volatile uint32_t fcr; 429 | volatile uint32_t efr; 430 | }; 431 | 432 | volatile uint32_t lcr; 433 | 434 | union { 435 | volatile uint32_t mcr; 436 | volatile uint32_t xon1; 437 | }; 438 | 439 | union { 440 | const volatile uint32_t lsr; 441 | volatile uint32_t xon2; 442 | }; 443 | 444 | union { 445 | volatile uint32_t msr; 446 | volatile uint32_t xoff1; 447 | }; 448 | 449 | union { 450 | volatile uint32_t scr; 451 | volatile uint32_t xoff2; 452 | }; 453 | 454 | volatile uint32_t rx_level_ctl; 455 | volatile uint32_t highspeed; 456 | volatile uint32_t sample_count; 457 | volatile uint32_t sample_point; 458 | const volatile uint32_t res_12_14[3]; 459 | volatile uint32_t guard; 460 | volatile uint32_t escape_dat; 461 | volatile uint32_t escape_en; 462 | volatile uint32_t sw_rto_limit; 463 | volatile uint32_t vfifo_en; 464 | volatile uint32_t rxtrig; 465 | volatile uint32_t fracdiv_l; 466 | volatile uint32_t fracdiv_m; 467 | const volatile uint32_t fcr_rd; 468 | const volatile uint32_t res_24; 469 | volatile uint32_t extend_add; 470 | const volatile uint32_t rx_offset; 471 | const volatile uint32_t tx_offset; 472 | const volatile uint32_t interrupt_sta; 473 | } mt3620_uart_t; 474 | 475 | 476 | #define MT3620_UART_TX_FIFO_DEPTH 16 477 | #define MT3620_UART_RX_FIFO_DEPTH 16 478 | 479 | #define MT3620_UART_CLOCK 26000000 480 | #define MT3620_UART_MAX_SPEED 3000000 481 | 482 | #define MT3620_UART_INTERRUPT(x) ((x) == 0 ? 4 : (47 + (((x) - 1) * 4))) 483 | 484 | #define MT3620_UART_DMA_TX(x) ((x) == 0 ? 0 : (13 + (((x) - 1) * 2))) 485 | #define MT3620_UART_DMA_RX(x) ((x) == 0 ? 0 : (14 + (((x) - 1) * 2))) 486 | 487 | #define MT3620_UART_COUNT 7 488 | static volatile mt3620_uart_t * const mt3620_uart[MT3620_UART_COUNT] = { 489 | (volatile mt3620_uart_t *)0x21040000, 490 | (volatile mt3620_uart_t *)0x38070500, 491 | (volatile mt3620_uart_t *)0x38080500, 492 | (volatile mt3620_uart_t *)0x38090500, 493 | (volatile mt3620_uart_t *)0x380a0500, 494 | (volatile mt3620_uart_t *)0x380b0500, 495 | (volatile mt3620_uart_t *)0x380c0500, 496 | }; 497 | 498 | #define MT3620_UART_FIELD_READ(index, reg, field) \ 499 | ((mt3620_uart_##reg##_t)mt3620_uart[index]->reg).field 500 | #define MT3620_UART_FIELD_WRITE(index, reg, field, value) \ 501 | do { mt3620_uart_##reg##_t reg = { .mask = mt3620_uart[index]->reg }; reg.field = value; \ 502 | mt3620_uart[index]->reg = reg.mask; } while (0) 503 | 504 | static const uint16_t mt3620_uart_fract_lut[10] = { 505 | 0b0000000000, 506 | 0b0000000001, 507 | 0b0000100001, 508 | 0b0001001001, 509 | 0b0010100101, 510 | 0b0101010101, 511 | 0b0110110111, 512 | 0b0111101111, 513 | 0b0111111111, 514 | }; 515 | 516 | #endif // #ifndef MT3620_REG_UART_H__ 517 | -------------------------------------------------------------------------------- /VectorTable.c: -------------------------------------------------------------------------------- 1 | #include "VectorTable.h" 2 | #include "NVIC.h" 3 | #include "mt3620/dma.h" 4 | #include 5 | #include 6 | #include 7 | 8 | 9 | extern uintptr_t StackTop; // &StackTop == end of TCM0 10 | 11 | _Noreturn void RTCoreMain(void); 12 | 13 | // Exception Handlers 14 | static _Noreturn void DefaultExceptionHandler(void) { while (true); } 15 | 16 | static _Noreturn void NMIExceptionHandler(void) { while (true); } 17 | 18 | static _Noreturn void HardFaultExceptionHandler(void) { while (true); } 19 | 20 | static _Noreturn void MPUFaultExceptionHandler(void) { while (true); } 21 | 22 | static _Noreturn void BusFaultExceptionHandler(void) { while (true); } 23 | 24 | static _Noreturn void UsageFaultExceptionHandler(void) { while (true); } 25 | 26 | static _Noreturn void SVCallExceptionHandler(void) { while (true); } 27 | 28 | static _Noreturn void DebugMonitorExceptionHandler(void) { while (true); } 29 | 30 | static _Noreturn void PendSVExceptionHandler(void) { while (true); } 31 | 32 | static _Noreturn void SysTickExceptionHandler(void) { while (true); } 33 | 34 | void __attribute__((weak, alias("NMIExceptionHandler"))) NMI(void); 35 | void __attribute__((weak, alias("HardFaultExceptionHandler"))) HardFault(void); 36 | void __attribute__((weak, alias("MPUFaultExceptionHandler"))) MPUFault(void); 37 | void __attribute__((weak, alias("BusFaultExceptionHandler"))) BusFault(void); 38 | void __attribute__((weak, alias("UsageFaultExceptionHandler"))) UsageFault(void); 39 | void __attribute__((weak, alias("SVCallExceptionHandler"))) SVCall(void); 40 | void __attribute__((weak, alias("DebugMonitorExceptionHandler"))) DebugMonitor(void); 41 | void __attribute__((weak, alias("PendSVExceptionHandler"))) PendSV(void); 42 | void __attribute__((weak, alias("SysTickExceptionHandler"))) SysTick(void); 43 | 44 | void __attribute__((weak, alias("DefaultExceptionHandler"))) wic_int_wake_up(void); 45 | void __attribute__((weak, alias("DefaultExceptionHandler"))) gpt_int_b(void); 46 | void __attribute__((weak, alias("DefaultExceptionHandler"))) gpt3_int_b(void); 47 | void __attribute__((weak, alias("DefaultExceptionHandler"))) wdt_m4_io_irq_b(void); 48 | void __attribute__((weak, alias("DefaultExceptionHandler"))) uart_irq_b(void); 49 | void __attribute__((weak, alias("DefaultExceptionHandler"))) infra_bus_int(void); 50 | void __attribute__((weak, alias("DefaultExceptionHandler"))) cm4_mbox_m4a2a7n_rd_int(void); 51 | void __attribute__((weak, alias("DefaultExceptionHandler"))) cm4_mbox_m4a2a7n_nf_int(void); 52 | void __attribute__((weak, alias("DefaultExceptionHandler"))) cm4_mbox_a7n2m4a_wr_int(void); 53 | void __attribute__((weak, alias("DefaultExceptionHandler"))) cm4_mbox_a7n2m4a_ne_int(void); 54 | void __attribute__((weak, alias("DefaultExceptionHandler"))) cm4_mbox_a7n_fifo_int(void); 55 | void __attribute__((weak, alias("DefaultExceptionHandler"))) cm4_mbox_a7n2m4a_sw_int(void); 56 | void __attribute__((weak, alias("DefaultExceptionHandler"))) cm4_mbox_m4a2m4b_rd_int(void); 57 | void __attribute__((weak, alias("DefaultExceptionHandler"))) cm4_mbox_m4a2m4b_nf_int(void); 58 | void __attribute__((weak, alias("DefaultExceptionHandler"))) cm4_mbox_m4b2m4a_wr_int(void); 59 | void __attribute__((weak, alias("DefaultExceptionHandler"))) cm4_mbox_m4b2m4a_ne_int(void); 60 | void __attribute__((weak, alias("DefaultExceptionHandler"))) cm4_mbox_m4b_fifo_int(void); 61 | void __attribute__((weak, alias("DefaultExceptionHandler"))) cm4_mbox_m4b2m4a_sw_int(void); 62 | void __attribute__((weak, alias("DefaultExceptionHandler"))) mbox_a7n_wake_m4a_int(void); 63 | void __attribute__((weak, alias("DefaultExceptionHandler"))) mbox_m4b_wake_m4a_int(void); 64 | void __attribute__((weak, alias("DefaultExceptionHandler"))) gpio_g0_irq0(void); // EINT0 65 | void __attribute__((weak, alias("DefaultExceptionHandler"))) gpio_g0_irq1(void); // EINT1 66 | void __attribute__((weak, alias("DefaultExceptionHandler"))) gpio_g0_irq2(void); // EINT2 67 | void __attribute__((weak, alias("DefaultExceptionHandler"))) gpio_g0_irq3(void); // EINT3 68 | void __attribute__((weak, alias("DefaultExceptionHandler"))) gpio_g1_irq0(void); // EINT4 69 | void __attribute__((weak, alias("DefaultExceptionHandler"))) gpio_g1_irq1(void); // EINT5 70 | void __attribute__((weak, alias("DefaultExceptionHandler"))) gpio_g1_irq2(void); // EINT6 71 | void __attribute__((weak, alias("DefaultExceptionHandler"))) gpio_g1_irq3(void); // EINT7 72 | void __attribute__((weak, alias("DefaultExceptionHandler"))) gpio_g2_irq0(void); // EINT8 73 | void __attribute__((weak, alias("DefaultExceptionHandler"))) gpio_g2_irq1(void); // EINT9 74 | void __attribute__((weak, alias("DefaultExceptionHandler"))) gpio_g2_irq2(void); // EINT10 75 | void __attribute__((weak, alias("DefaultExceptionHandler"))) gpio_g2_irq3(void); // EINT11 76 | void __attribute__((weak, alias("DefaultExceptionHandler"))) gpio_g3_irq0(void); // EINT12 77 | void __attribute__((weak, alias("DefaultExceptionHandler"))) gpio_g3_irq1(void); // EINT13 78 | void __attribute__((weak, alias("DefaultExceptionHandler"))) gpio_g3_irq2(void); // EINT14 79 | void __attribute__((weak, alias("DefaultExceptionHandler"))) gpio_g3_irq3(void); // EINT15 80 | void __attribute__((weak, alias("DefaultExceptionHandler"))) gpio_g4_irq0(void); // EINT16 81 | void __attribute__((weak, alias("DefaultExceptionHandler"))) gpio_g4_irq1(void); // EINT17 82 | void __attribute__((weak, alias("DefaultExceptionHandler"))) gpio_g4_irq2(void); // EINT18 83 | void __attribute__((weak, alias("DefaultExceptionHandler"))) gpio_g4_irq3(void); // EINT19 84 | void __attribute__((weak, alias("DefaultExceptionHandler"))) gpio_g5_irq0(void); // EINT20 85 | void __attribute__((weak, alias("DefaultExceptionHandler"))) gpio_g5_irq1(void); // EINT21 86 | void __attribute__((weak, alias("DefaultExceptionHandler"))) gpio_g5_irq2(void); // EINT22 87 | void __attribute__((weak, alias("DefaultExceptionHandler"))) gpio_g5_irq3(void); // EINT23 88 | void __attribute__((weak, alias("DefaultExceptionHandler"))) isu_g0_i2c_irq(void); 89 | void __attribute__((weak, alias("DefaultExceptionHandler"))) isu_g0_spim_irq(void); 90 | void __attribute__((weak, alias("DefaultExceptionHandler"))) isu_g0_uart_irq_b(void); 91 | void __attribute__((weak, alias("DefaultExceptionHandler"))) isu_g1_i2c_irq(void); 92 | void __attribute__((weak, alias("DefaultExceptionHandler"))) isu_g1_spim_irq(void); 93 | void __attribute__((weak, alias("DefaultExceptionHandler"))) isu_g1_uart_irq_b(void); 94 | void __attribute__((weak, alias("DefaultExceptionHandler"))) isu_g2_i2c_irq(void); 95 | void __attribute__((weak, alias("DefaultExceptionHandler"))) isu_g2_spim_irq(void); 96 | void __attribute__((weak, alias("DefaultExceptionHandler"))) isu_g2_uart_irq_b(void); 97 | void __attribute__((weak, alias("DefaultExceptionHandler"))) isu_g3_i2c_irq(void); 98 | void __attribute__((weak, alias("DefaultExceptionHandler"))) isu_g3_spim_irq(void); 99 | void __attribute__((weak, alias("DefaultExceptionHandler"))) isu_g3_uart_irq_b(void); 100 | void __attribute__((weak, alias("DefaultExceptionHandler"))) isu_g4_i2c_irq(void); 101 | void __attribute__((weak, alias("DefaultExceptionHandler"))) isu_g4_spim_irq(void); 102 | void __attribute__((weak, alias("DefaultExceptionHandler"))) isu_g4_uart_irq_b(void); 103 | void __attribute__((weak, alias("DefaultExceptionHandler"))) isu_g5_i2c_irq(void); 104 | void __attribute__((weak, alias("DefaultExceptionHandler"))) isu_g5_spim_irq(void); 105 | void __attribute__((weak, alias("DefaultExceptionHandler"))) isu_g5_uart_irq_b(void); 106 | void __attribute__((weak, alias("DefaultExceptionHandler"))) i2s0_irq_b(void); 107 | void __attribute__((weak, alias("DefaultExceptionHandler"))) i2s1_irq_b(void); 108 | void __attribute__((weak, alias("DefaultExceptionHandler"))) adc_irq_b(void); 109 | void __attribute__((weak, alias("DefaultExceptionHandler"))) gpio_g3_cnt_irq(void); 110 | void __attribute__((weak, alias("DefaultExceptionHandler"))) gpio_g4_cnt_irq(void); 111 | void __attribute__((weak, alias("DefaultExceptionHandler"))) gpio_g5_cnt_irq(void); 112 | void __attribute__((weak, alias("DefaultExceptionHandler"))) iom4_CDBGPWRUPREQ(void); 113 | void __attribute__((weak, alias("DefaultExceptionHandler"))) iom4_CDBGPWRUPACK(void); 114 | 115 | void __attribute__((weak, alias("DefaultExceptionHandler"))) m4dma_irq_b_uart0_rx(void); 116 | void __attribute__((weak, alias("DefaultExceptionHandler"))) m4dma_irq_b_uart1_rx(void); 117 | void __attribute__((weak, alias("DefaultExceptionHandler"))) m4dma_irq_b_uart2_rx(void); 118 | void __attribute__((weak, alias("DefaultExceptionHandler"))) m4dma_irq_b_uart3_rx(void); 119 | void __attribute__((weak, alias("DefaultExceptionHandler"))) m4dma_irq_b_uart4_rx(void); 120 | void __attribute__((weak, alias("DefaultExceptionHandler"))) m4dma_irq_b_uart5_rx(void); 121 | void __attribute__((weak, alias("DefaultExceptionHandler"))) m4dma_irq_b_adc(void); 122 | void __attribute__((weak, alias("DefaultExceptionHandler"))) m4dma_irq_b_i2s0_tx(void); 123 | void __attribute__((weak, alias("DefaultExceptionHandler"))) m4dma_irq_b_i2s0_rx(void); 124 | void __attribute__((weak, alias("DefaultExceptionHandler"))) m4dma_irq_b_i2s1_tx(void); 125 | void __attribute__((weak, alias("DefaultExceptionHandler"))) m4dma_irq_b_i2s1_rx(void); 126 | 127 | // DMA can interrupt many drivers, so we handle that here. 128 | static void m4dma_irq_b(void) 129 | { 130 | static void (*m4dma_irq_b_isr[MT3620_DMA_COUNT])(void) = { 131 | [14] = m4dma_irq_b_uart0_rx, 132 | [16] = m4dma_irq_b_uart1_rx, 133 | [18] = m4dma_irq_b_uart2_rx, 134 | [20] = m4dma_irq_b_uart3_rx, 135 | [22] = m4dma_irq_b_uart4_rx, 136 | [24] = m4dma_irq_b_uart5_rx, 137 | [25] = m4dma_irq_b_i2s0_tx, 138 | [26] = m4dma_irq_b_i2s0_rx, 139 | [27] = m4dma_irq_b_i2s1_tx, 140 | [28] = m4dma_irq_b_i2s1_rx, 141 | [29] = m4dma_irq_b_adc, 142 | }; 143 | 144 | unsigned i; 145 | for (i = 0; i < MT3620_DMA_COUNT; i++) { 146 | uint32_t glbsta = (i < 16 147 | ? mt3620_dma_global->glbsta0 148 | : mt3620_dma_global->glbsta1); 149 | if (((glbsta >> (((i % 16) * 2) + 1)) & 1) != 0) { 150 | void (*isr)(void) = m4dma_irq_b_isr[i]; 151 | if (isr) isr(); 152 | } 153 | } 154 | } 155 | 156 | #define EXC(x) ((x) + 0) 157 | #define INT(x) ((x) + 16) 158 | 159 | // ARM DDI0403E.d SB1.5.2-3 160 | // From SB1.5.3, "The Vector table must be naturally aligned to a power of two whose alignment 161 | // value is greater than or equal to (Number of Exceptions supported x 4), with a minimum alignment 162 | // of 128 bytes.". The array is aligned in linker.ld, using the dedicated section ".vector_table". 163 | 164 | // The exception vector table contains a stack pointer, 15 exception handlers, and an entry for 165 | // each interrupt. 166 | const void (*ExceptionVectorTable[])(void) 167 | __attribute__((section(".vector_table"))) __attribute__((used)) = { 168 | [EXC( 0)] = (void*)&StackTop, // Main Stack Pointer (MSP) 169 | [EXC( 1)] = RTCoreMain, // Reset 170 | [EXC( 2)] = NMI, 171 | [EXC( 3)] = HardFault, 172 | [EXC( 4)] = MPUFault, 173 | [EXC( 5)] = BusFault, 174 | [EXC( 6)] = UsageFault, 175 | [EXC( 7)] = NULL, 176 | [EXC( 8)] = NULL, 177 | [EXC( 9)] = NULL, 178 | [EXC(10)] = NULL, 179 | [EXC(11)] = SVCall, 180 | [EXC(12)] = DebugMonitor, 181 | [EXC(13)] = NULL, 182 | [EXC(14)] = PendSV, 183 | [EXC(15)] = SysTick, 184 | 185 | [INT( 0)] = wic_int_wake_up, 186 | [INT( 1)] = gpt_int_b, 187 | [INT( 2)] = gpt3_int_b, 188 | [INT( 3)] = wdt_m4_io_irq_b, 189 | [INT( 4)] = uart_irq_b, 190 | [INT( 5)] = infra_bus_int, 191 | [INT( 6)] = cm4_mbox_m4a2a7n_rd_int, 192 | [INT( 7)] = cm4_mbox_m4a2a7n_nf_int, 193 | [INT( 8)] = cm4_mbox_a7n2m4a_wr_int, 194 | [INT( 9)] = cm4_mbox_a7n2m4a_ne_int, 195 | [INT(10)] = cm4_mbox_a7n_fifo_int, 196 | [INT(11)] = cm4_mbox_a7n2m4a_sw_int, 197 | [INT(12)] = cm4_mbox_m4a2m4b_rd_int, 198 | [INT(13)] = cm4_mbox_m4a2m4b_nf_int, 199 | [INT(14)] = cm4_mbox_m4b2m4a_wr_int, 200 | [INT(15)] = cm4_mbox_m4b2m4a_ne_int, 201 | [INT(16)] = cm4_mbox_m4b_fifo_int, 202 | [INT(17)] = cm4_mbox_m4b2m4a_sw_int, 203 | [INT(18)] = mbox_a7n_wake_m4a_int, 204 | [INT(19)] = mbox_m4b_wake_m4a_int, 205 | [INT(20)] = gpio_g0_irq0, // EINT0 206 | [INT(21)] = gpio_g0_irq1, // EINT1 207 | [INT(22)] = gpio_g0_irq2, // EINT2 208 | [INT(23)] = gpio_g0_irq3, // EINT3 209 | [INT(24)] = gpio_g1_irq0, // EINT4 210 | [INT(25)] = gpio_g1_irq1, // EINT5 211 | [INT(26)] = gpio_g1_irq2, // EINT6 212 | [INT(27)] = gpio_g1_irq3, // EINT7 213 | [INT(28)] = gpio_g2_irq0, // EINT8 214 | [INT(29)] = gpio_g2_irq1, // EINT9 215 | [INT(30)] = gpio_g2_irq2, // EINT10 216 | [INT(31)] = gpio_g2_irq3, // EINT11 217 | [INT(32)] = gpio_g3_irq0, // EINT12 218 | [INT(33)] = gpio_g3_irq1, // EINT13 219 | [INT(34)] = gpio_g3_irq2, // EINT14 220 | [INT(35)] = gpio_g3_irq3, // EINT15 221 | [INT(36)] = gpio_g4_irq0, // EINT16 222 | [INT(37)] = gpio_g4_irq1, // EINT17 223 | [INT(38)] = gpio_g4_irq2, // EINT18 224 | [INT(39)] = gpio_g4_irq3, // EINT19 225 | [INT(40)] = gpio_g5_irq0, // EINT20 226 | [INT(41)] = gpio_g5_irq1, // EINT21 227 | [INT(42)] = gpio_g5_irq2, // EINT22 228 | [INT(43)] = gpio_g5_irq3, // EINT23 229 | [INT(44)] = isu_g0_i2c_irq, 230 | [INT(45)] = isu_g0_spim_irq, 231 | [INT(46)] = NULL, 232 | [INT(47)] = isu_g0_uart_irq_b, 233 | [INT(48)] = isu_g1_i2c_irq, 234 | [INT(49)] = isu_g1_spim_irq, 235 | [INT(50)] = NULL, 236 | [INT(51)] = isu_g1_uart_irq_b, 237 | [INT(52)] = isu_g2_i2c_irq, 238 | [INT(53)] = isu_g2_spim_irq, 239 | [INT(54)] = NULL, 240 | [INT(55)] = isu_g2_uart_irq_b, 241 | [INT(56)] = isu_g3_i2c_irq, 242 | [INT(57)] = isu_g3_spim_irq, 243 | [INT(58)] = NULL, 244 | [INT(59)] = isu_g3_uart_irq_b, 245 | [INT(60)] = isu_g4_i2c_irq, 246 | [INT(61)] = isu_g4_spim_irq, 247 | [INT(62)] = NULL, 248 | [INT(63)] = isu_g4_uart_irq_b, 249 | [INT(64)] = isu_g5_i2c_irq, 250 | [INT(65)] = isu_g5_spim_irq, 251 | [INT(66)] = NULL, 252 | [INT(67)] = isu_g5_uart_irq_b, 253 | [INT(68)] = i2s0_irq_b, 254 | [INT(69)] = i2s1_irq_b, 255 | [INT(70)] = adc_irq_b, 256 | [INT(71)] = NULL, 257 | [INT(72)] = NULL, 258 | [INT(73)] = NULL, 259 | [INT(74)] = gpio_g3_cnt_irq, 260 | [INT(75)] = gpio_g4_cnt_irq, 261 | [INT(76)] = gpio_g5_cnt_irq, 262 | [INT(77)] = m4dma_irq_b, 263 | [INT(78)] = iom4_CDBGPWRUPREQ, 264 | [INT(79)] = iom4_CDBGPWRUPACK, 265 | [INT(80)] = NULL, 266 | [INT(81)] = NULL, 267 | [INT(82)] = NULL, 268 | [INT(83)] = NULL, 269 | [INT(84)] = NULL, 270 | [INT(85)] = NULL, 271 | [INT(86)] = NULL, 272 | [INT(87)] = NULL, 273 | [INT(88)] = NULL, 274 | [INT(89)] = NULL, 275 | [INT(90)] = NULL, 276 | [INT(91)] = NULL, 277 | [INT(92)] = NULL, 278 | [INT(93)] = NULL, 279 | [INT(94)] = NULL, 280 | [INT(95)] = NULL, 281 | [INT(96)] = NULL, 282 | [INT(97)] = NULL, 283 | [INT(98)] = NULL, 284 | [INT(99)] = NULL, 285 | }; 286 | 287 | static volatile uint32_t * const VTOR = (volatile uint32_t *)0xE000ED08; 288 | 289 | void VectorTableInit(void) 290 | { 291 | // SCB->VTOR = ExceptionVectorTable 292 | *VTOR = (uint32_t)ExceptionVectorTable; 293 | 294 | // We have to enable DMA here as it's used in multiple drivers. 295 | NVIC_EnableIRQ(MT3620_DMA_INTERRUPT, 2); 296 | } 297 | 298 | 299 | 300 | #include "CPUFreq.h" 301 | #include "mt3620/clock.h" 302 | 303 | #define CPUFREQ_TOLERANCE_PERCENT 5 304 | 305 | bool CPUFreq_Set(unsigned freq) 306 | { 307 | unsigned freq_high = (freq * (100ULL + CPUFREQ_TOLERANCE_PERCENT)) / 100; 308 | unsigned freq_low = (freq * (100ULL - CPUFREQ_TOLERANCE_PERCENT)) / 100; 309 | 310 | unsigned i; 311 | for (i = 0; i < MT3620_CLOCK_COUNT; i++) { 312 | if ((mt3620_clock_freq[i] >= freq_low) 313 | && (mt3620_clock_freq[i] <= freq_high)) { 314 | mt3620_hclk_clock_source_set(i); 315 | return true; 316 | } 317 | } 318 | 319 | return false; 320 | } 321 | 322 | unsigned CPUFreq_Get(void) 323 | { 324 | mt3620_clock_t src = mt3620_hclk_clock_source_get(); 325 | if (src >= MT3620_CLOCK_COUNT) return 0; 326 | return mt3620_clock_freq[src]; 327 | } 328 | -------------------------------------------------------------------------------- /MBox.c: -------------------------------------------------------------------------------- 1 | /* Copyright (c) Codethink Ltd. All rights reserved. 2 | Licensed under the MIT License. */ 3 | 4 | #include "CPUFreq.h" 5 | #include "MBox.h" 6 | #include "NVIC.h" 7 | 8 | #include "mt3620/mbox.h" 9 | 10 | #include 11 | #include 12 | 13 | 14 | #define MBOX_MAX_INDEX (MT3620_UNIT_MBOX_CA7 + MT3620_UNIT_MBOX_COUNT - 1) 15 | 16 | #define MBOX_DEFAULT_PRIORITY 2 17 | 18 | struct MBox { 19 | bool fifo_open; 20 | Platform_Unit unit; 21 | void (*rx_cb )(void*); 22 | void (*tx_confirmed_cb )(void*); 23 | void (*fifo_state_change_cb)(void*, MBox_FIFO_State state); 24 | void *user_data; 25 | int8_t non_full_threshold; 26 | int8_t non_empty_threshold; 27 | void (*sw_int_cb )(void*, uint8_t port); 28 | }; 29 | 30 | static MBox context[MT3620_UNIT_MBOX_COUNT] = {0}; 31 | 32 | 33 | static inline int32_t MBox__Get_Index(Platform_Unit unit) 34 | { 35 | int32_t index = unit - MT3620_UNIT_MBOX_CA7; 36 | return ((index > MBOX_MAX_INDEX) || (index < 0)) ? -1 : index; 37 | } 38 | 39 | 40 | static void MBox_FIFO__Toggle_Interrupts(MBox *handle, bool enable) 41 | { 42 | if (!handle) { 43 | return; 44 | } 45 | int32_t index = MBox__Get_Index(handle->unit); 46 | if (index == -1) { 47 | return; 48 | } 49 | MT3620_MBOX_FIELD_WRITE( 50 | index, mbox_int_en, int_fifo_wr, enable && !!handle->rx_cb); 51 | MT3620_MBOX_FIELD_WRITE( 52 | index, mbox_int_en, int_fifo_rd, enable && !!handle->tx_confirmed_cb); 53 | MT3620_MBOX_FIELD_WRITE( 54 | index, mbox_int_en, int_fifo_nf, enable && !!handle->fifo_state_change_cb); 55 | MT3620_MBOX_FIELD_WRITE( 56 | index, mbox_int_en, int_fifo_ne, enable && !!handle->fifo_state_change_cb); 57 | 58 | if (enable && handle->rx_cb) { 59 | NVIC_EnableIRQ(MT3620_MBOX_INTERRUPT( 60 | index, MT3620_MBOX_INT_RX), MBOX_DEFAULT_PRIORITY); 61 | } 62 | else { 63 | NVIC_DisableIRQ(MT3620_MBOX_INTERRUPT(index, MT3620_MBOX_INT_RX)); 64 | } 65 | 66 | if (enable && handle->tx_confirmed_cb) { 67 | NVIC_EnableIRQ(MT3620_MBOX_INTERRUPT( 68 | index, MT3620_MBOX_INT_TX_CONFIRMED), MBOX_DEFAULT_PRIORITY); 69 | } 70 | else { 71 | NVIC_DisableIRQ(MT3620_MBOX_INTERRUPT( 72 | index, MT3620_MBOX_INT_TX_CONFIRMED)); 73 | } 74 | 75 | if (enable && handle->fifo_state_change_cb) { 76 | NVIC_EnableIRQ(MT3620_MBOX_INTERRUPT( 77 | index, MT3620_MBOX_INT_TX_FIFO_NF), MBOX_DEFAULT_PRIORITY); 78 | NVIC_EnableIRQ(MT3620_MBOX_INTERRUPT( 79 | index, MT3620_MBOX_INT_TX_FIFO_NE), MBOX_DEFAULT_PRIORITY); 80 | } 81 | else { 82 | NVIC_DisableIRQ(MT3620_MBOX_INTERRUPT( 83 | index, MT3620_MBOX_INT_TX_FIFO_NF)); 84 | NVIC_DisableIRQ(MT3620_MBOX_INTERRUPT( 85 | index, MT3620_MBOX_INT_TX_FIFO_NE)); 86 | } 87 | } 88 | 89 | 90 | MBox* MBox_FIFO_Open( 91 | Platform_Unit unit, 92 | void (*rx_cb) (void*), 93 | void (*tx_confirmed_cb) (void*), 94 | void (*fifo_state_change_cb)(void*, MBox_FIFO_State state), 95 | void *user_data, 96 | int8_t non_full_threshold, 97 | int8_t non_empty_threshold) 98 | { 99 | int32_t index = MBox__Get_Index(unit); 100 | if (index == -1) { 101 | return NULL; 102 | } 103 | 104 | MBox *handle = &context[index]; 105 | 106 | if (handle->fifo_open) { 107 | return NULL; 108 | } 109 | 110 | MBox_FIFO_Reset(handle, true); 111 | 112 | handle->fifo_open = true; 113 | handle->unit = unit; 114 | 115 | handle->rx_cb = rx_cb; 116 | handle->tx_confirmed_cb = tx_confirmed_cb; 117 | handle->fifo_state_change_cb = fifo_state_change_cb; 118 | handle->user_data = user_data; 119 | 120 | handle->non_full_threshold = non_full_threshold; 121 | handle->non_empty_threshold = non_empty_threshold; 122 | 123 | // Configure Thresholds 124 | if ((non_full_threshold > 0) && 125 | (non_full_threshold <= MT3620_MBOX_FIFO_COUNT_MAX)) 126 | { 127 | mt3620_mbox[index]->mbox_nf_thrs = non_full_threshold; 128 | } 129 | 130 | if ((non_empty_threshold > 0) && 131 | (non_empty_threshold <= MT3620_MBOX_FIFO_COUNT_MAX)) 132 | { 133 | mt3620_mbox[index]->mbox_ne_thrs = non_empty_threshold; 134 | } 135 | 136 | // Configure Interrupts 137 | MBox_FIFO__Toggle_Interrupts(handle, true); 138 | 139 | return handle; 140 | } 141 | 142 | 143 | void MBox_FIFO_Close(MBox *handle) 144 | { 145 | if (!handle || !handle->fifo_open) { 146 | return; 147 | } 148 | 149 | MBox_FIFO_Reset(handle, false); 150 | 151 | handle->fifo_open = false; 152 | 153 | handle->rx_cb = NULL; 154 | handle->tx_confirmed_cb = NULL; 155 | handle->fifo_state_change_cb = NULL; 156 | 157 | handle->non_full_threshold = -1; 158 | handle->non_empty_threshold = -1; 159 | 160 | MBox_FIFO__Toggle_Interrupts(handle, false); 161 | } 162 | 163 | 164 | void MBox_FIFO_Reset(MBox *handle, bool both) 165 | { 166 | if (!handle) { 167 | return; 168 | } 169 | 170 | // Note that the MB on the partner core must also be reset 171 | int32_t index = MBox__Get_Index(handle->unit); 172 | 173 | if (index != -1) { 174 | if (both) { 175 | MT3620_MBOX_FIELD_WRITE( 176 | index, mbox_gen_ctrl, soft_rst, 1); 177 | } 178 | else { 179 | MT3620_MBOX_FIELD_WRITE( 180 | index, mbox_gen_ctrl, soft_rst_myself, 1); 181 | } 182 | } 183 | } 184 | 185 | 186 | int32_t MBox_FIFO_Write( 187 | MBox *handle, 188 | const uint32_t *cmd, 189 | const uint32_t *data, 190 | uintptr_t length) 191 | { 192 | if (!handle || !handle->fifo_open || 193 | length > MT3620_MBOX_FIFO_COUNT_MAX) 194 | { 195 | return ERROR_PARAMETER; 196 | } 197 | 198 | int32_t index = MBox__Get_Index(handle->unit); 199 | 200 | if (index == -1) { 201 | return ERROR_HARDWARE_STATE; 202 | } 203 | 204 | if (length > (MT3620_MBOX_FIFO_COUNT_MAX - 205 | mt3620_mbox[index]->fifo_push_cnt)) 206 | { 207 | return ERROR_MBOX_FIFO_INSUFFICIENT_SPACE; 208 | } 209 | 210 | // CMD write increments the write ptr, so we write any DATA first 211 | for (unsigned i = 0; i < length; i++) { 212 | if (data) { 213 | mt3620_mbox[index]->data_push = data[i]; 214 | } 215 | mt3620_mbox[index]->cmd_push = cmd[i]; 216 | } 217 | 218 | return ERROR_NONE; 219 | } 220 | 221 | 222 | int32_t MBox_FIFO_ReadSync( 223 | MBox *handle, 224 | uint32_t *cmd, 225 | uint32_t *data, 226 | uintptr_t length) 227 | { 228 | if (!handle || !handle->fifo_open || 229 | length > MT3620_MBOX_FIFO_COUNT_MAX) 230 | { 231 | return ERROR_PARAMETER; 232 | } 233 | 234 | int32_t index = MBox__Get_Index(handle->unit); 235 | 236 | if (index == -1) { 237 | return ERROR_HARDWARE_STATE; 238 | } 239 | 240 | for (unsigned i = 0; i < length; i++) { 241 | // wait until data is available to read 242 | while (mt3620_mbox[index]->fifo_pop_cnt == 0); 243 | // As above, CMD read decrements the read ptr, so we read DATA first 244 | if (data) { 245 | data[i] = mt3620_mbox[index]->data_pop; 246 | } 247 | cmd[i] = mt3620_mbox[index]->cmd_pop; 248 | } 249 | 250 | return ERROR_NONE; 251 | } 252 | 253 | 254 | uintptr_t MBox_FIFO_Writes_Pending(const MBox *handle) 255 | { 256 | if (!handle || !handle->fifo_open) { 257 | return 0; 258 | } 259 | 260 | int32_t index = MBox__Get_Index(handle->unit); 261 | 262 | if (index == -1) { 263 | return 0; 264 | } 265 | 266 | return mt3620_mbox[index]->fifo_push_cnt; 267 | } 268 | 269 | 270 | uintptr_t MBox_FIFO_Reads_Available(const MBox *handle) 271 | { 272 | if (!handle || !handle->fifo_open) { 273 | return 0; 274 | } 275 | 276 | int32_t index = MBox__Get_Index(handle->unit); 277 | 278 | if (index == -1) { 279 | return 0; 280 | } 281 | 282 | return mt3620_mbox[index]->fifo_pop_cnt; 283 | } 284 | 285 | 286 | 287 | /// Semaphore 288 | int32_t MBox_Semaphore_Acquire(MBox* handle) 289 | { 290 | if (!handle) { 291 | return ERROR_PARAMETER; 292 | } 293 | 294 | if (handle->unit == MT3620_UNIT_MBOX_CM4) { 295 | return ERROR_MBOX_SEMAPHORE_NOT_PRESENT; 296 | } 297 | 298 | int32_t index = MBox__Get_Index(handle->unit); 299 | 300 | if (index == -1) { 301 | return ERROR_HARDWARE_STATE; 302 | } 303 | 304 | if (mt3620_mbox[index]->semaphore_p != 1U) { 305 | return ERROR_MBOX_SEMAPHORE_REQUEST_DENIED; 306 | } 307 | else { 308 | return ERROR_NONE; 309 | } 310 | } 311 | 312 | 313 | int32_t MBox_Semaphore_Release(MBox* handle) 314 | { 315 | if (!handle) { 316 | return ERROR_PARAMETER; 317 | } 318 | 319 | if (handle->unit == MT3620_UNIT_MBOX_CM4) { 320 | return ERROR_MBOX_SEMAPHORE_NOT_PRESENT; 321 | } 322 | 323 | int32_t index = MBox__Get_Index(handle->unit); 324 | 325 | if (index == -1) { 326 | return ERROR_HARDWARE_STATE; 327 | } 328 | 329 | if (mt3620_mbox[index]->semaphore_p != 1U) { 330 | return ERROR_MBOX_SEMAPHORE_REQUEST_DENIED; 331 | } 332 | else { 333 | mt3620_mbox[index]->semaphore_p = 0; 334 | return ERROR_NONE; 335 | } 336 | } 337 | 338 | 339 | 340 | /// SW Interrupts 341 | int32_t MBox_SW_Interrupt_Setup( 342 | MBox *handle, 343 | uint8_t int_enable_flags, 344 | void (*sw_int_cb)(void*, uint8_t port)) 345 | { 346 | if (!handle) { 347 | return ERROR_PARAMETER; 348 | } 349 | 350 | handle->sw_int_cb = sw_int_cb; 351 | 352 | int32_t index = MBox__Get_Index(handle->unit); 353 | 354 | if (index == -1) { 355 | return ERROR_HARDWARE_STATE; 356 | } 357 | 358 | mt3620_mbox[index]->sw_rx_int_en = int_enable_flags; 359 | 360 | // Configure Interrupts 361 | if (sw_int_cb) { 362 | NVIC_EnableIRQ(MT3620_MBOX_INTERRUPT( 363 | index, MT3620_MBOX_INT_SW_INT), MBOX_DEFAULT_PRIORITY); 364 | } 365 | else { 366 | NVIC_DisableIRQ(MT3620_MBOX_INTERRUPT(index, MT3620_MBOX_INT_SW_INT)); 367 | } 368 | 369 | return ERROR_NONE; 370 | } 371 | 372 | 373 | void MBox_SW_Interrupt_Teardown(MBox *handle) 374 | { 375 | if (!handle) { 376 | return; 377 | } 378 | 379 | handle->sw_int_cb = NULL; 380 | 381 | int32_t index = MBox__Get_Index(handle->unit); 382 | 383 | if (index == -1) { 384 | return; 385 | } 386 | 387 | mt3620_mbox[index]->sw_rx_int_en = 0; 388 | 389 | NVIC_DisableIRQ(MT3620_MBOX_INTERRUPT(index, MT3620_MBOX_INT_SW_INT)); 390 | } 391 | 392 | 393 | int32_t MBox_SW_Interrupt_Trigger(MBox *handle, uint8_t port) 394 | { 395 | if (!handle || (port >= MBOX_SW_INT_PORT_COUNT)) { 396 | return ERROR_PARAMETER; 397 | } 398 | 399 | int32_t index = MBox__Get_Index(handle->unit); 400 | 401 | if (index == -1) { 402 | return ERROR_HARDWARE_STATE; 403 | } 404 | 405 | mt3620_mbox[index]->sw_tx_int_port = 1U << port; 406 | 407 | return ERROR_NONE; 408 | } 409 | 410 | 411 | 412 | /// IRQs 413 | static void MBox_IRQ(MBox *handle, mt3620_mbox_int cb_type) 414 | { 415 | if (!handle || !handle->fifo_open) { 416 | return; 417 | } 418 | 419 | switch (cb_type) { 420 | case MT3620_MBOX_INT_RX: 421 | if (handle->rx_cb) { 422 | handle->rx_cb(handle->user_data); 423 | } 424 | break; 425 | 426 | case MT3620_MBOX_INT_TX_CONFIRMED: 427 | if (handle->tx_confirmed_cb) { 428 | handle->tx_confirmed_cb(handle->user_data); 429 | } 430 | break; 431 | 432 | case MT3620_MBOX_INT_TX_FIFO_NF: 433 | if (handle->fifo_state_change_cb) { 434 | handle->fifo_state_change_cb( 435 | handle->user_data, MBOX_FIFO_STATE_NOT_FULL); 436 | } 437 | break; 438 | 439 | case MT3620_MBOX_INT_TX_FIFO_NE: 440 | if (handle->fifo_state_change_cb) { 441 | handle->fifo_state_change_cb( 442 | handle->user_data, MBOX_FIFO_STATE_NOT_EMPTY); 443 | } 444 | break; 445 | 446 | case MT3620_MBOX_INT_SW_INT: 447 | { 448 | if (!handle->sw_int_cb) { 449 | break; 450 | } 451 | uint8_t flags = 452 | (mt3620_mbox[MBox__Get_Index(handle->unit)]->sw_rx_int_sts) & 453 | (mt3620_mbox[MBox__Get_Index(handle->unit)]->sw_rx_int_en); 454 | 455 | for (uint8_t port = 0; 456 | port < MBOX_SW_INT_PORT_COUNT; 457 | port++, flags >>= port) { 458 | if (flags & 1U) { 459 | handle->sw_int_cb(handle->user_data, port); 460 | } 461 | } 462 | break; 463 | } 464 | 465 | default: 466 | break; 467 | } 468 | } 469 | 470 | static inline void mbox_rd_int(int32_t index) 471 | { 472 | if (MT3620_MBOX_FIELD_READ(index, mbox_int_en, int_fifo_rd) && 473 | MT3620_MBOX_FIELD_READ(index, mbox_int_sts, int_fifo_rd)) 474 | { 475 | MBox *handle = &(context[index]); 476 | MBox_IRQ(handle, MT3620_MBOX_INT_TX_CONFIRMED); 477 | } 478 | 479 | MT3620_MBOX_FIELD_WRITE(index, mbox_int_sts, int_fifo_rd, 1); 480 | } 481 | 482 | static inline void mbox_nf_int(int32_t index) 483 | { 484 | if (MT3620_MBOX_FIELD_READ(index, mbox_int_en, int_fifo_nf) && 485 | MT3620_MBOX_FIELD_READ(index, mbox_int_sts, int_fifo_nf)) 486 | { 487 | MBox *handle = &(context[MBox__Get_Index(MT3620_UNIT_MBOX_CA7)]); 488 | MBox_IRQ(handle, MT3620_MBOX_INT_TX_FIFO_NF); 489 | } 490 | 491 | MT3620_MBOX_FIELD_WRITE(index, mbox_int_sts, int_fifo_nf, 1); 492 | } 493 | 494 | static inline void mbox_wr_int(int32_t index) 495 | { 496 | if (MT3620_MBOX_FIELD_READ(index, mbox_int_en, int_fifo_wr) && 497 | MT3620_MBOX_FIELD_READ(index, mbox_int_sts, int_fifo_wr)) 498 | { 499 | MBox *handle = &(context[MBox__Get_Index(MT3620_UNIT_MBOX_CA7)]); 500 | MBox_IRQ(handle, MT3620_MBOX_INT_RX); 501 | } 502 | 503 | MT3620_MBOX_FIELD_WRITE(index, mbox_int_sts, int_fifo_wr, 1); 504 | } 505 | 506 | static inline void mbox_ne_int(int32_t index) 507 | { 508 | if (MT3620_MBOX_FIELD_READ(index, mbox_int_en, int_fifo_ne) && 509 | MT3620_MBOX_FIELD_READ(index, mbox_int_sts, int_fifo_ne)) 510 | { 511 | MBox *handle = &(context[MBox__Get_Index(MT3620_UNIT_MBOX_CA7)]); 512 | MBox_IRQ(handle, MT3620_MBOX_INT_TX_FIFO_NE); 513 | } 514 | 515 | MT3620_MBOX_FIELD_WRITE(index, mbox_int_sts, int_fifo_ne, 1); 516 | } 517 | 518 | static inline void mbox_sw_int(int32_t index) 519 | { 520 | if ((mt3620_mbox[index]->sw_rx_int_en & 521 | mt3620_mbox[index]->sw_rx_int_sts) != 0) 522 | { 523 | MBox *handle = &(context[MBox__Get_Index(MT3620_UNIT_MBOX_CA7)]); 524 | MBox_IRQ(handle, MT3620_MBOX_INT_SW_INT); 525 | } 526 | 527 | // Reset interrupt flags 528 | mt3620_mbox[index]->sw_rx_int_sts = 0xFF; 529 | } 530 | 531 | /// M4 <-> A7 Mailbox 532 | void cm4_mbox_m4a2a7n_rd_int(void) 533 | { 534 | mbox_rd_int(MBox__Get_Index(MT3620_UNIT_MBOX_CA7)); 535 | } 536 | 537 | void cm4_mbox_m4a2a7n_nf_int(void) 538 | { 539 | mbox_nf_int(MBox__Get_Index(MT3620_UNIT_MBOX_CA7)); 540 | } 541 | 542 | void cm4_mbox_a7n2m4a_wr_int(void) 543 | { 544 | mbox_wr_int(MBox__Get_Index(MT3620_UNIT_MBOX_CA7)); 545 | } 546 | 547 | void cm4_mbox_a7n2m4a_ne_int(void) 548 | { 549 | mbox_ne_int(MBox__Get_Index(MT3620_UNIT_MBOX_CA7)); 550 | } 551 | 552 | void cm4_mbox_a7n_fifo_int(void) 553 | { 554 | 555 | } 556 | 557 | void cm4_mbox_a7n2m4a_sw_int(void) 558 | { 559 | mbox_sw_int(MBox__Get_Index(MT3620_UNIT_MBOX_CA7)); 560 | } 561 | 562 | /// M4 <-> M4 Mailbox 563 | void cm4_mbox_m4a2m4b_rd_int(void) 564 | { 565 | mbox_rd_int(MBox__Get_Index(MT3620_UNIT_MBOX_CM4)); 566 | } 567 | 568 | void cm4_mbox_m4a2m4b_nf_int(void) 569 | { 570 | mbox_nf_int(MBox__Get_Index(MT3620_UNIT_MBOX_CM4)); 571 | } 572 | 573 | void cm4_mbox_m4b2m4a_wr_int(void) 574 | { 575 | mbox_wr_int(MBox__Get_Index(MT3620_UNIT_MBOX_CM4)); 576 | } 577 | 578 | void cm4_mbox_m4b2m4a_ne_int(void) 579 | { 580 | mbox_ne_int(MBox__Get_Index(MT3620_UNIT_MBOX_CM4)); 581 | } 582 | 583 | void cm4_mbox_m4b_fifo_int(void) 584 | { 585 | 586 | } 587 | 588 | void cm4_mbox_m4b2m4a_sw_int(void) 589 | { 590 | mbox_sw_int(MBox__Get_Index(MT3620_UNIT_MBOX_CM4)); 591 | } 592 | -------------------------------------------------------------------------------- /SPIMaster.h: -------------------------------------------------------------------------------- 1 | /* Copyright (c) Codethink Ltd. All rights reserved. 2 | Licensed under the MIT License. */ 3 | 4 | #ifndef AZURE_SPHERE_SPIMASTER_H_ 5 | #define AZURE_SPHERE_SPIMASTER_H_ 6 | 7 | #include "Common.h" 8 | #include "Platform.h" 9 | #include 10 | #include 11 | #include 12 | 13 | #ifdef __cplusplus 14 | extern "C" { 15 | #endif 16 | 17 | /// SPI specific errors. 18 | #define ERROR_SPI_MODE (ERROR_SPECIFIC - 1) 19 | #define ERROR_SPI_FRAME_FORMAT (ERROR_SPECIFIC - 2) 20 | #define ERROR_SPI_DATA_BITS (ERROR_SPECIFIC - 3) 21 | #define ERROR_SPI_BIT_ORDER (ERROR_SPECIFIC - 4) 22 | #define ERROR_SPI_CS_SELECT (ERROR_SPECIFIC - 5) 23 | #define ERROR_SPI_TRANSFER_FAIL (ERROR_SPECIFIC - 6) 24 | #define ERROR_SPI_TRANSFER_CANCEL (ERROR_SPECIFIC - 7) 25 | 26 | /// SPI Master opaque handle. 27 | typedef struct SPIMaster SPIMaster; 28 | 29 | /// SPI transfer entry, used for queueing multiple transfers. 30 | typedef struct { 31 | /// 32 | /// Pointer to data to be transmitted. 33 | /// The writeData is a variable for transfering data to the SDOR buffer. 34 | /// 35 | const void *writeData; 36 | /// 37 | /// Pointer to buffer where received data will be written. 38 | /// The readData is a variable for receiving data from the SDIR buffer. 39 | /// 40 | void *readData; 41 | /// 42 | /// Length of data to be transmitted or received. 43 | /// 44 | uintptr_t length; 45 | } SPITransfer; 46 | 47 | /// Enum for SPI idle line level. 48 | typedef enum { 49 | /// The MOSI line will idle low 50 | SPI_IDLE_LEVEL_LOW = 0, 51 | /// The MOSI line will idle high 52 | SPI_IDLE_LEVEL_HIGH = 1, 53 | /// The MOSI line will idle at any level, may be faster on some hardware. 54 | SPI_IDLE_LEVEL_DONT_CARE, 55 | } SPI_IdleLevel; 56 | 57 | /// 58 | /// Sets the idle line level of MOSI line. 59 | /// 60 | /// SPI handle to be configured. 61 | /// Sets the level to be used when MOSI idle. 62 | /// Returns ERROR_NONE on success, or an error code on failure. 63 | int32_t SPIMaster_SelectIdleLineLevel(SPIMaster *handle, SPI_IdleLevel level); 64 | 65 | /// 66 | /// Sets the subordinate device select channel. 67 | /// 68 | /// SPI handle to be configured. 69 | /// Sets the CS line to be used for hardware chip-select functionality. 70 | /// Note: If the value is valid, then this function also enables the CS line. 71 | /// Returns ERROR_NONE on success, or an error code on failure. 72 | int32_t SPIMaster_Select(SPIMaster *handle, unsigned csLine); 73 | 74 | /// 75 | /// Allows user to enable/disable hardware chip-select functionality, enabling 76 | /// resets the csLine to the value it had prior to disabling (if csCallback is not in use). 77 | /// 78 | /// SPI handle to be configured. 79 | /// Whether to enable the csLine 80 | /// Returns ERROR_NONE on success, or an error code on failure. 81 | int32_t SPIMaster_SelectEnable(SPIMaster *handle, bool enable); 82 | 83 | /// 84 | /// Sets callback alternative to HW chip select; allowing for GPIO CS. This allows the user 85 | /// to work-around the limitations of hardware chip-select functionality. 86 | /// 87 | /// SPI handle to update. 88 | /// Callback to associate with CS - called when transaction starts 89 | /// with select=true and when transaction ends or is cancelled with select=false. Note that SPI 90 | /// subordinate devices expect the line to go to logic low (0) for select, and high (1) for 91 | /// unselected. Can be NULL - which means that the callback will be unset. Note: If the value is 92 | /// a valid callback, then this function also enables the CS line, otherwise it's disabled. 93 | /// Returns ERROR_NONE on success, or an error code on failure. 94 | int32_t SPIMaster_SetSelectLineCallback( 95 | SPIMaster *handle, 96 | void (*csCallback)(SPIMaster *handle, bool select)); 97 | 98 | /// 99 | /// Sets the configuration parameters for the SPI transaction. 100 | /// 101 | /// SPI handle to be configured. 102 | /// SPI clock polarity. 103 | /// SPI clock phase. 104 | /// Selects the closest compatible baud rate below this value. 105 | /// Returns ERROR_NONE on success, or an error code on failure. 106 | int32_t SPIMaster_Configure(SPIMaster *handle, bool cpol, bool cpha, uint32_t busSpeed); 107 | 108 | /// 109 | /// Enable or disable DMA acceleration for the SPI device. 110 | /// 111 | /// SPI handle for which DMA will be configured. 112 | /// Whether the DMA unit will be enabled or not. 113 | /// Returns ERROR_NONE on success, or an error code on failure. 114 | int32_t SPIMaster_DMAEnable(SPIMaster *handle, bool enable); 115 | 116 | /// 117 | /// Configures the drive strength on the SPI interface provided. 118 | /// This should only be used if glitches or faults are seen on the SPI line as high values 119 | /// may cause EMI issues. 120 | /// 121 | /// Selects the SPI handle to configure the drive strength of. 122 | /// Drive strength in milliamps 123 | /// Returns ERROR_NONE on success, or an error code on failure. 124 | int32_t SPIMaster_ConfigureDriveStrength(SPIMaster *handle, unsigned drive); 125 | 126 | /// 127 | /// Initialize the SPIMaster handle and return a pointer to it. 128 | /// 129 | /// SPI HW unit to initialize and acquire a handle for. 130 | /// A handle of an SPI interface or NULL on failure. 131 | SPIMaster *SPIMaster_Open(Platform_Unit unit); 132 | 133 | /// 134 | /// Cleanup and close any outstanding transactions and release the Platform unit for a 135 | /// subsequent Open(). 136 | /// 137 | /// SPI handle to be closed. 138 | void SPIMaster_Close(SPIMaster *handle); 139 | 140 | /// 141 | /// Executes a sequence of asynchronous SPI transactions 142 | /// (Read, Write or WriteThenRead) on the interface provided. 143 | /// 144 | /// SPI handle to perform the transfer on. 145 | /// A pointer to the base of an array of transfers, for more information 146 | /// look at . 147 | /// The total number of transfers in the transfer array. 148 | /// Callback called once the transfer is completed. 149 | /// Returns ERROR_NONE on success, or an error code on failure. 150 | int32_t SPIMaster_TransferSequentialAsync( 151 | SPIMaster *handle, SPITransfer *transfer, 152 | uint32_t count, void (*callback)(int32_t status, uintptr_t data_count)); 153 | 154 | /// 155 | /// Identical to SPIMaster_TransferSequentialAsync, but allows for user 156 | /// to provide pointer to data that can be accessed on transfer completion 157 | /// or cancelation. Note that this callback happens within an IRQ, so if there 158 | /// is significant computation, it might be best to defer execution. 159 | /// 160 | /// SPI handle to perform the transfer on. 161 | /// A pointer to the base of an array of transfers, for more information 162 | /// look at . 163 | /// The total number of transfers in the transfer array. 164 | /// Callback called once the transfer is completed. 165 | /// Data available in callback. 166 | /// Returns ERROR_NONE on success, or an error code on failure. 167 | int32_t SPIMaster_TransferSequentialAsync_UserData( 168 | SPIMaster *handle, SPITransfer *transfer, 169 | uint32_t count, void (*callback)( 170 | int32_t status, uintptr_t data_count, void *userData), void *userData); 171 | 172 | /// 173 | /// Cancels the ongoing transfer. 174 | /// 175 | /// SPI handle to cancel transfer on. 176 | /// Returns ERROR_NONE on success, or an error code on failure. 177 | int32_t SPIMaster_TransferCancel(SPIMaster *handle); 178 | 179 | /// 180 | /// Executes a single write operation on the SPI interface provided. 181 | /// 182 | /// SPI handle to perform the transfer on. 183 | /// A pointer to the data to be written. 184 | /// The length of the data to be written. 185 | /// Callback called once the transfer is completed. 186 | /// Returns ERROR_NONE on success, or an error code on failure. 187 | static inline int32_t SPIMaster_WriteAsync( 188 | SPIMaster *handle, const void *data, 189 | uintptr_t length, void (*callback)(int32_t status, uintptr_t dataCount)); 190 | 191 | /// 192 | /// Executes a single read operation on the SPI interface provided. 193 | /// 194 | /// Selects the SPI handle to perform the transfer on. 195 | /// A pointer to the data to be read. 196 | /// The length of the data to be read. 197 | /// Callback called once the transfer is completed. 198 | /// Returns ERROR_NONE on success, or an error code on failure. 199 | static inline int32_t SPIMaster_ReadAsync( 200 | SPIMaster *handle, void *data, 201 | uintptr_t length, void (*callback)(int32_t status, uintptr_t dataCount)); 202 | 203 | /// 204 | /// Executes back-to-back write then read operations on the SPI interface provided. 205 | /// 206 | /// SPI handle to perform the transfer on. 207 | /// A pointer to the data to be written 208 | /// The length of the data to be written. 209 | /// A pointer to the data to be read. 210 | /// The length of the data to be read. 211 | /// Callback called once the transfer is completed. 212 | /// Returns ERROR_NONE on success, or an error code on failure. 213 | static inline int32_t SPIMaster_WriteThenReadAsync ( 214 | SPIMaster *handle, const void *writeData, 215 | uintptr_t writeLength, void *readData, uintptr_t readLength, 216 | void (*callback)(int32_t status, uintptr_t dataCount)); 217 | 218 | /// 219 | /// Executes a sequence of SPI operations on the interface provided. 220 | /// This is a synchronous wrapper around 221 | /// . 222 | /// 223 | /// SPI handle to perform the transfer on. 224 | /// A pointer to the base of an array of transfers, for more information 225 | /// look at . 226 | /// Number of sequential SPI transactions. 227 | /// Returns ERROR_NONE on success, or an error code on failure. 228 | int32_t SPIMaster_TransferSequentialSync( 229 | SPIMaster *handle, SPITransfer *transfer, uint32_t count); 230 | 231 | /// 232 | /// Executes a single write operation on the SPI interface provided. 233 | /// This is a synchronous wrapper around . 234 | /// 235 | /// Selects the SPI handle to perform the transfer on. 236 | /// A pointer to the data to be written. 237 | /// The length of the data to be written. 238 | /// Returns ERROR_NONE if successful, else returns an error code. 239 | static inline int32_t SPIMaster_WriteSync( 240 | SPIMaster *handle, const void *data, uintptr_t length); 241 | 242 | /// 243 | /// Executes a single read operation on the SPI interface provided. 244 | /// This is a synchronous wrapper around . 245 | /// 246 | /// Selects the SPI handle to perform the transfer on. 247 | /// A pointer to the data to be read. 248 | /// The length of the data to be read. 249 | /// Returns ERROR_NONE on success, or an error code on failure. 250 | static inline int32_t SPIMaster_ReadSync( 251 | SPIMaster *handle, void *data, uintptr_t length); 252 | 253 | /// 254 | /// Executes back-to-back write then read operations on the SPI interface provided. 255 | /// This is a synchronous wrapper around . 256 | /// 257 | /// Selects the SPI handle to perform the transfer on. 258 | /// A pointer to the data to be written. 259 | /// The length of the data to be written. 260 | /// A pointer to the data to be read. 261 | /// The length of the data to be read. 262 | /// Returns ERROR_NONE on success, or an error code on failure. 263 | static inline int32_t SPIMaster_WriteThenReadSync( 264 | SPIMaster *handle, const void *writeData, 265 | uintptr_t writeLength, void *readData, uintptr_t readLength); 266 | 267 | static inline int32_t SPIMaster_WriteAsync( 268 | SPIMaster *handle, const void *data, uintptr_t length, 269 | void (*callback)(int32_t status, uintptr_t dataCount)) 270 | { 271 | SPITransfer transfer = { 272 | .writeData = data, 273 | .readData = NULL, 274 | .length = length, 275 | }; 276 | return SPIMaster_TransferSequentialAsync(handle, &transfer, 1, callback); 277 | } 278 | 279 | static inline int32_t SPIMaster_ReadAsync( 280 | SPIMaster *handle, void *data, uintptr_t length, 281 | void (*callback)(int32_t status, uintptr_t dataCount)) 282 | { 283 | SPITransfer transfer = { 284 | .writeData = NULL, 285 | .readData = data, 286 | .length = length, 287 | }; 288 | return SPIMaster_TransferSequentialAsync(handle, &transfer, 1, callback); 289 | } 290 | 291 | static inline int32_t SPIMaster_WriteThenReadAsync( 292 | SPIMaster *handle, const void *writeData, uintptr_t writeLength, 293 | void *readData, uintptr_t readLength, void (*callback)(int32_t status, uintptr_t dataCount)) 294 | { 295 | SPITransfer transfer[2] = { 296 | {.writeData = writeData, .readData = NULL , .length = writeLength }, 297 | {.writeData = NULL , .readData = readData, .length = readLength }, 298 | }; 299 | return SPIMaster_TransferSequentialAsync(handle, transfer, 2, callback); 300 | } 301 | 302 | static inline int32_t SPIMaster_WriteSync(SPIMaster *handle, const void *data, uintptr_t length) 303 | { 304 | SPITransfer transfer = { 305 | .writeData = data, 306 | .readData = NULL, 307 | .length = length, 308 | }; 309 | return SPIMaster_TransferSequentialSync(handle, &transfer, 1); 310 | } 311 | 312 | static inline int32_t SPIMaster_ReadSync(SPIMaster *handle, void *data, uintptr_t length) 313 | { 314 | SPITransfer transfer = { 315 | .writeData = NULL, 316 | .readData = data, 317 | .length = length, 318 | }; 319 | return SPIMaster_TransferSequentialSync(handle, &transfer, 1); 320 | } 321 | 322 | static inline int32_t SPIMaster_WriteThenReadSync( 323 | SPIMaster *handle, const void *writeData, uintptr_t writeLength, void *readData, uintptr_t readLength) 324 | { 325 | SPITransfer transfer[2] = { 326 | { .writeData = writeData, .readData = NULL , .length = writeLength }, 327 | { .writeData = NULL , .readData = readData, .length = readLength }, 328 | }; 329 | return SPIMaster_TransferSequentialSync(handle, transfer, 2); 330 | } 331 | 332 | #ifdef __cplusplus 333 | } 334 | #endif 335 | 336 | #endif // #ifndef AZURE_SPHERE_SPIMASTER_H_ 337 | --------------------------------------------------------------------------------