From 09822a7bb37f298bf9b10851635b4752ac56caf9 Mon Sep 17 00:00:00 2001 From: rtel Date: Wed, 20 Jun 2018 21:18:14 +0000 Subject: [PATCH] Add starting point for IGLOO2 RISV-V demo project. git-svn-id: https://svn.code.sf.net/p/freertos/code/trunk@2553 1d2547de-c912-0410-9cb9-b8ca96c0e9e2 --- .../.cproject | 125 + .../.project | 162 ++ .../.settings/language.settings.xml | 14 + .../FreeRTOSConfig.h | 151 ++ .../README.md | 48 + .../RTOSDemo Debug.launch | 59 + .../drivers/Core16550/core16550_regs.h | 582 +++++ .../drivers/Core16550/core_16550.c | 865 +++++++ .../drivers/Core16550/core_16550.h | 1264 +++++++++ .../drivers/CoreGPIO/core_gpio.c | 461 ++++ .../drivers/CoreGPIO/core_gpio.h | 552 ++++ .../drivers/CoreGPIO/coregpio_regs.h | 40 + .../drivers/CoreI2C/core_i2c.c | 1563 +++++++++++ .../drivers/CoreI2C/core_i2c.h | 2280 +++++++++++++++++ .../drivers/CoreI2C/core_smbus_regs.h | 190 ++ .../drivers/CoreI2C/i2c_interrupt.c | 35 + .../drivers/CoreTimer/core_timer.c | 158 ++ .../drivers/CoreTimer/core_timer.h | 206 ++ .../drivers/CoreTimer/coretimer_regs.h | 109 + .../drivers/CoreUARTapb/core_uart_apb.c | 296 +++ .../drivers/CoreUARTapb/core_uart_apb.h | 407 +++ .../drivers/CoreUARTapb/coreuartapb_regs.h | 130 + .../hal/cpu_types.h | 31 + .../hal/hal.h | 207 ++ .../hal/hal_assert.h | 29 + .../hal/hal_irq.c | 36 + .../hal/hw_macros.h | 97 + .../hal/hw_reg_access.S | 209 ++ .../hal/hw_reg_access.h | 229 ++ .../hw_platform.h | 119 + .../RISC-V_IGLOO2_Creative_SoftConsole/main.c | 136 + .../riscv_hal/encoding.h | 596 +++++ .../riscv_hal/entry.S | 160 ++ .../riscv_hal/init.c | 80 + .../riscv_hal/microsemi-riscv-igloo2.ld | 137 + .../riscv_hal/microsemi-riscv-ram.ld | 137 + .../riscv_hal/riscv_hal.c | 251 ++ .../riscv_hal/riscv_hal.h | 55 + .../riscv_hal/riscv_hal_stubs.c | 227 ++ .../riscv_hal/riscv_plic.h | 249 ++ .../riscv_hal/sample_hw_platform.h | 120 + .../riscv_hal/syscall.c | 266 ++ 42 files changed, 13068 insertions(+) create mode 100644 FreeRTOS/Demo/RISC-V_IGLOO2_Creative_SoftConsole/.cproject create mode 100644 FreeRTOS/Demo/RISC-V_IGLOO2_Creative_SoftConsole/.project create mode 100644 FreeRTOS/Demo/RISC-V_IGLOO2_Creative_SoftConsole/.settings/language.settings.xml create mode 100644 FreeRTOS/Demo/RISC-V_IGLOO2_Creative_SoftConsole/FreeRTOSConfig.h create mode 100644 FreeRTOS/Demo/RISC-V_IGLOO2_Creative_SoftConsole/README.md create mode 100644 FreeRTOS/Demo/RISC-V_IGLOO2_Creative_SoftConsole/RTOSDemo Debug.launch create mode 100644 FreeRTOS/Demo/RISC-V_IGLOO2_Creative_SoftConsole/drivers/Core16550/core16550_regs.h create mode 100644 FreeRTOS/Demo/RISC-V_IGLOO2_Creative_SoftConsole/drivers/Core16550/core_16550.c create mode 100644 FreeRTOS/Demo/RISC-V_IGLOO2_Creative_SoftConsole/drivers/Core16550/core_16550.h create mode 100644 FreeRTOS/Demo/RISC-V_IGLOO2_Creative_SoftConsole/drivers/CoreGPIO/core_gpio.c create mode 100644 FreeRTOS/Demo/RISC-V_IGLOO2_Creative_SoftConsole/drivers/CoreGPIO/core_gpio.h create mode 100644 FreeRTOS/Demo/RISC-V_IGLOO2_Creative_SoftConsole/drivers/CoreGPIO/coregpio_regs.h create mode 100644 FreeRTOS/Demo/RISC-V_IGLOO2_Creative_SoftConsole/drivers/CoreI2C/core_i2c.c create mode 100644 FreeRTOS/Demo/RISC-V_IGLOO2_Creative_SoftConsole/drivers/CoreI2C/core_i2c.h create mode 100644 FreeRTOS/Demo/RISC-V_IGLOO2_Creative_SoftConsole/drivers/CoreI2C/core_smbus_regs.h create mode 100644 FreeRTOS/Demo/RISC-V_IGLOO2_Creative_SoftConsole/drivers/CoreI2C/i2c_interrupt.c create mode 100644 FreeRTOS/Demo/RISC-V_IGLOO2_Creative_SoftConsole/drivers/CoreTimer/core_timer.c create mode 100644 FreeRTOS/Demo/RISC-V_IGLOO2_Creative_SoftConsole/drivers/CoreTimer/core_timer.h create mode 100644 FreeRTOS/Demo/RISC-V_IGLOO2_Creative_SoftConsole/drivers/CoreTimer/coretimer_regs.h create mode 100644 FreeRTOS/Demo/RISC-V_IGLOO2_Creative_SoftConsole/drivers/CoreUARTapb/core_uart_apb.c create mode 100644 FreeRTOS/Demo/RISC-V_IGLOO2_Creative_SoftConsole/drivers/CoreUARTapb/core_uart_apb.h create mode 100644 FreeRTOS/Demo/RISC-V_IGLOO2_Creative_SoftConsole/drivers/CoreUARTapb/coreuartapb_regs.h create mode 100644 FreeRTOS/Demo/RISC-V_IGLOO2_Creative_SoftConsole/hal/cpu_types.h create mode 100644 FreeRTOS/Demo/RISC-V_IGLOO2_Creative_SoftConsole/hal/hal.h create mode 100644 FreeRTOS/Demo/RISC-V_IGLOO2_Creative_SoftConsole/hal/hal_assert.h create mode 100644 FreeRTOS/Demo/RISC-V_IGLOO2_Creative_SoftConsole/hal/hal_irq.c create mode 100644 FreeRTOS/Demo/RISC-V_IGLOO2_Creative_SoftConsole/hal/hw_macros.h create mode 100644 FreeRTOS/Demo/RISC-V_IGLOO2_Creative_SoftConsole/hal/hw_reg_access.S create mode 100644 FreeRTOS/Demo/RISC-V_IGLOO2_Creative_SoftConsole/hal/hw_reg_access.h create mode 100644 FreeRTOS/Demo/RISC-V_IGLOO2_Creative_SoftConsole/hw_platform.h create mode 100644 FreeRTOS/Demo/RISC-V_IGLOO2_Creative_SoftConsole/main.c create mode 100644 FreeRTOS/Demo/RISC-V_IGLOO2_Creative_SoftConsole/riscv_hal/encoding.h create mode 100644 FreeRTOS/Demo/RISC-V_IGLOO2_Creative_SoftConsole/riscv_hal/entry.S create mode 100644 FreeRTOS/Demo/RISC-V_IGLOO2_Creative_SoftConsole/riscv_hal/init.c create mode 100644 FreeRTOS/Demo/RISC-V_IGLOO2_Creative_SoftConsole/riscv_hal/microsemi-riscv-igloo2.ld create mode 100644 FreeRTOS/Demo/RISC-V_IGLOO2_Creative_SoftConsole/riscv_hal/microsemi-riscv-ram.ld create mode 100644 FreeRTOS/Demo/RISC-V_IGLOO2_Creative_SoftConsole/riscv_hal/riscv_hal.c create mode 100644 FreeRTOS/Demo/RISC-V_IGLOO2_Creative_SoftConsole/riscv_hal/riscv_hal.h create mode 100644 FreeRTOS/Demo/RISC-V_IGLOO2_Creative_SoftConsole/riscv_hal/riscv_hal_stubs.c create mode 100644 FreeRTOS/Demo/RISC-V_IGLOO2_Creative_SoftConsole/riscv_hal/riscv_plic.h create mode 100644 FreeRTOS/Demo/RISC-V_IGLOO2_Creative_SoftConsole/riscv_hal/sample_hw_platform.h create mode 100644 FreeRTOS/Demo/RISC-V_IGLOO2_Creative_SoftConsole/riscv_hal/syscall.c diff --git a/FreeRTOS/Demo/RISC-V_IGLOO2_Creative_SoftConsole/.cproject b/FreeRTOS/Demo/RISC-V_IGLOO2_Creative_SoftConsole/.cproject new file mode 100644 index 000000000..c1655cff0 --- /dev/null +++ b/FreeRTOS/Demo/RISC-V_IGLOO2_Creative_SoftConsole/.cproject @@ -0,0 +1,125 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/FreeRTOS/Demo/RISC-V_IGLOO2_Creative_SoftConsole/.project b/FreeRTOS/Demo/RISC-V_IGLOO2_Creative_SoftConsole/.project new file mode 100644 index 000000000..f7313f56f --- /dev/null +++ b/FreeRTOS/Demo/RISC-V_IGLOO2_Creative_SoftConsole/.project @@ -0,0 +1,162 @@ + + + RTOSDemo + + + + + + org.eclipse.cdt.managedbuilder.core.genmakebuilder + clean,full,incremental, + + + + + org.eclipse.cdt.managedbuilder.core.ScannerConfigBuilder + full,incremental, + + + + + + org.eclipse.cdt.core.cnature + org.eclipse.cdt.managedbuilder.core.managedBuildNature + org.eclipse.cdt.managedbuilder.core.ScannerConfigNature + + + + FreeRTOS_Source + 2 + FREERTOS_ROOT/FreeRTOS/Source + + + + + 1529524430510 + FreeRTOS_Source + 9 + + org.eclipse.ui.ide.multiFilter + 1.0-name-matches-false-false-include + + + + 1529524430514 + FreeRTOS_Source + 9 + + org.eclipse.ui.ide.multiFilter + 1.0-name-matches-false-false-portable + + + + 1529524430518 + FreeRTOS_Source + 5 + + org.eclipse.ui.ide.multiFilter + 1.0-name-matches-false-false-event_groups.c + + + + 1529524430521 + FreeRTOS_Source + 5 + + org.eclipse.ui.ide.multiFilter + 1.0-name-matches-false-false-list.c + + + + 1529524430525 + FreeRTOS_Source + 5 + + org.eclipse.ui.ide.multiFilter + 1.0-name-matches-false-false-queue.c + + + + 1529524430529 + FreeRTOS_Source + 5 + + org.eclipse.ui.ide.multiFilter + 1.0-name-matches-false-false-stream_buffer.c + + + + 1529524430533 + FreeRTOS_Source + 5 + + org.eclipse.ui.ide.multiFilter + 1.0-name-matches-false-false-tasks.c + + + + 1529524430538 + FreeRTOS_Source + 5 + + org.eclipse.ui.ide.multiFilter + 1.0-name-matches-false-false-timers.c + + + + 1529524475525 + FreeRTOS_Source/portable + 9 + + org.eclipse.ui.ide.multiFilter + 1.0-name-matches-false-false-ThirdParty + + + + 1529524475530 + FreeRTOS_Source/portable + 9 + + org.eclipse.ui.ide.multiFilter + 1.0-name-matches-false-false-MemMang + + + + 1529524494421 + FreeRTOS_Source/portable/MemMang + 5 + + org.eclipse.ui.ide.multiFilter + 1.0-name-matches-false-false-heap_4.c + + + + 1529524515837 + FreeRTOS_Source/portable/ThirdParty + 9 + + org.eclipse.ui.ide.multiFilter + 1.0-name-matches-false-false-GCC + + + + 1529524627661 + FreeRTOS_Source/portable/ThirdParty/GCC + 9 + + org.eclipse.ui.ide.multiFilter + 1.0-name-matches-false-false-RISC-V + + + + + + FREERTOS_ROOT + $%7BPARENT-3-PROJECT_LOC%7D + + + copy_PARENT + $%7BPARENT-4-PROJECT_LOC%7D/FreeRTOS/WorkingCopy/FreeRTOS + + + diff --git a/FreeRTOS/Demo/RISC-V_IGLOO2_Creative_SoftConsole/.settings/language.settings.xml b/FreeRTOS/Demo/RISC-V_IGLOO2_Creative_SoftConsole/.settings/language.settings.xml new file mode 100644 index 000000000..6dc13a6a3 --- /dev/null +++ b/FreeRTOS/Demo/RISC-V_IGLOO2_Creative_SoftConsole/.settings/language.settings.xml @@ -0,0 +1,14 @@ + + + + + + + + + + + + + + diff --git a/FreeRTOS/Demo/RISC-V_IGLOO2_Creative_SoftConsole/FreeRTOSConfig.h b/FreeRTOS/Demo/RISC-V_IGLOO2_Creative_SoftConsole/FreeRTOSConfig.h new file mode 100644 index 000000000..0cd797d12 --- /dev/null +++ b/FreeRTOS/Demo/RISC-V_IGLOO2_Creative_SoftConsole/FreeRTOSConfig.h @@ -0,0 +1,151 @@ +/* + FreeRTOS V8.2.3 - Copyright (C) 2015 Real Time Engineers Ltd. + All rights reserved + + VISIT http://www.FreeRTOS.org TO ENSURE YOU ARE USING THE LATEST VERSION. + + This file is part of the FreeRTOS distribution. + + FreeRTOS is free software; you can redistribute it and/or modify it under + the terms of the GNU General Public License (version 2) as published by the + Free Software Foundation >>>> AND MODIFIED BY <<<< the FreeRTOS exception. + + *************************************************************************** + >>! NOTE: The modification to the GPL is included to allow you to !<< + >>! distribute a combined work that includes FreeRTOS without being !<< + >>! obliged to provide the source code for proprietary components !<< + >>! outside of the FreeRTOS kernel. !<< + *************************************************************************** + + FreeRTOS is distributed in the hope that it will be useful, but WITHOUT ANY + WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + FOR A PARTICULAR PURPOSE. Full license text is available on the following + link: http://www.freertos.org/a00114.html + + *************************************************************************** + * * + * FreeRTOS provides completely free yet professionally developed, * + * robust, strictly quality controlled, supported, and cross * + * platform software that is more than just the market leader, it * + * is the industry's de facto standard. * + * * + * Help yourself get started quickly while simultaneously helping * + * to support the FreeRTOS project by purchasing a FreeRTOS * + * tutorial book, reference manual, or both: * + * http://www.FreeRTOS.org/Documentation * + * * + *************************************************************************** + + http://www.FreeRTOS.org/FAQHelp.html - Having a problem? Start by reading + the FAQ page "My application does not run, what could be wrong?". Have you + defined configASSERT()? + + http://www.FreeRTOS.org/support - In return for receiving this top quality + embedded software for free we request you assist our global community by + participating in the support forum. + + http://www.FreeRTOS.org/training - Investing in training allows your team to + be as productive as possible as early as possible. Now you can receive + FreeRTOS training directly from Richard Barry, CEO of Real Time Engineers + Ltd, and the world's leading authority on the world's leading RTOS. + + http://www.FreeRTOS.org/plus - A selection of FreeRTOS ecosystem products, + including FreeRTOS+Trace - an indispensable productivity tool, a DOS + compatible FAT file system, and our tiny thread aware UDP/IP stack. + + http://www.FreeRTOS.org/labs - Where new FreeRTOS products go to incubate. + Come and try FreeRTOS+TCP, our new open source TCP/IP stack for FreeRTOS. + + http://www.OpenRTOS.com - Real Time Engineers ltd. license FreeRTOS to High + Integrity Systems ltd. to sell under the OpenRTOS brand. Low cost OpenRTOS + licenses offer ticketed support, indemnification and commercial middleware. + + http://www.SafeRTOS.com - High Integrity Systems also provide a safety + engineered and independently SIL3 certified version for use in safety and + mission critical applications that require provable dependability. + + 1 tab == 4 spaces! +*/ + + +#ifndef FREERTOS_CONFIG_H +#define FREERTOS_CONFIG_H + + +/*----------------------------------------------------------- + * Application specific definitions. + * + * These definitions should be adjusted for your particular hardware and + * application requirements. + * + * THESE PARAMETERS ARE DESCRIBED WITHIN THE 'CONFIGURATION' SECTION OF THE + * FreeRTOS API DOCUMENTATION AVAILABLE ON THE FreeRTOS.org WEB SITE. + * + * See http://www.freertos.org/a00110.html. + *----------------------------------------------------------*/ + +#include +#include +#include "riscv_plic.h" + +extern uint32_t SystemCoreClock; + +#define configUSE_PREEMPTION 1 +#define configUSE_IDLE_HOOK 1 +#define configUSE_TICK_HOOK 0 +#define configCPU_CLOCK_HZ ( ( unsigned long ) 83000000 ) +#define configTICK_RATE_HZ ( ( TickType_t ) 1000 ) +#define configMAX_PRIORITIES ( 5 ) +#define configMINIMAL_STACK_SIZE ( ( unsigned short ) 1024 ) +#define configTOTAL_HEAP_SIZE ( ( size_t ) ( 100 * 1024 ) ) +#define configMAX_TASK_NAME_LEN ( 16 ) +#define configUSE_TRACE_FACILITY 1 +#define configUSE_16_BIT_TICKS 0 +#define configIDLE_SHOULD_YIELD 1 +#define configUSE_MUTEXES 1 +#define configQUEUE_REGISTRY_SIZE 8 +#define configCHECK_FOR_STACK_OVERFLOW 0 //2 +#define configUSE_RECURSIVE_MUTEXES 1 +#define configUSE_MALLOC_FAILED_HOOK 1 +#define configUSE_APPLICATION_TASK_TAG 0 +#define configUSE_COUNTING_SEMAPHORES 1 +#define configGENERATE_RUN_TIME_STATS 0 + +/* Co-routine definitions. */ +#define configUSE_CO_ROUTINES 0 +#define configMAX_CO_ROUTINE_PRIORITIES ( 2 ) + +/* Software timer definitions. */ +#define configUSE_TIMERS 0 +#define configTIMER_TASK_PRIORITY ( 2 ) +#define configTIMER_QUEUE_LENGTH 2 +#define configTIMER_TASK_STACK_DEPTH ( configMINIMAL_STACK_SIZE ) + +/* Task priorities. Allow these to be overridden. */ +#ifndef uartPRIMARY_PRIORITY + #define uartPRIMARY_PRIORITY ( configMAX_PRIORITIES - 3 ) +#endif + +/* Set the following definitions to 1 to include the API function, or zero +to exclude the API function. */ +#define INCLUDE_vTaskPrioritySet 1 +#define INCLUDE_uxTaskPriorityGet 1 +#define INCLUDE_vTaskDelete 1 +#define INCLUDE_vTaskCleanUpResources 1 +#define INCLUDE_vTaskSuspend 1 +#define INCLUDE_vTaskDelayUntil 1 +#define INCLUDE_vTaskDelay 1 +#define INCLUDE_eTaskGetState 1 + +/* Normal assert() semantics without relying on the provision of an assert.h +header file. */ +#define configASSERT( x ) if( ( x ) == 0 ) { taskDISABLE_INTERRUPTS(); for( ;; ); } + +/* Definitions that map the FreeRTOS port interrupt handlers to their CMSIS +standard names - or at least those used in the unmodified vector table. */ +#define vPortSVCHandler SVCall_Handler +#define xPortPendSVHandler PendSV_Handler +#define vPortSysTickHandler SysTick_Handler + +extern void vApplicationMallocFailedHook(); +#endif /* FREERTOS_CONFIG_H */ diff --git a/FreeRTOS/Demo/RISC-V_IGLOO2_Creative_SoftConsole/README.md b/FreeRTOS/Demo/RISC-V_IGLOO2_Creative_SoftConsole/README.md new file mode 100644 index 000000000..211d2466d --- /dev/null +++ b/FreeRTOS/Demo/RISC-V_IGLOO2_Creative_SoftConsole/README.md @@ -0,0 +1,48 @@ +## FreeRTOS port for Mi-V Soft Processor + +### HW Platform and FPGA design: +This project is tested on following hardware platforms: + +RISCV-Creative-Board +- [RISC-V Creative board Mi-V Sample Design](https://github.com/RISCV-on-Microsemi-FPGA/RISC-V-Creative-Board/tree/master/Programming_The_Target_Device/PROC_SUBSYSTEM_MIV_RV32IMA_BaseDesign) + +PolarFire-Eval-Kit +- [PolarFire Eval Kit RISC-V Sample Design](https://github.com/RISCV-on-Microsemi-FPGA/PolarFire-Eval-Kit/tree/master/Programming_The_Target_Device/MIV_RV32IMA_L1_AHB_BaseDesign) + +SmartFusion2-Advanced-Dev-Kit +- [SmartFusion2 Advanced Development Kit RISC-V Sample Design](https://github.com/RISCV-on-Microsemi-FPGA/SmartFusion2-Advanced-Dev-Kit/tree/master/Programming_The_Target_Device/PROC_SUBSYSTEM_BaseDesign) + +### How to run the FreeRTOS RISC-V port: +To know how to use the SoftConsole workspace, please refer the [Readme.md](https://github.com/RISCV-on-Microsemi-FPGA/SoftConsole/blob/master/README.md) + +The miv-rv32im-freertos-port-test is a self contained project. This project demonstrates +the FreeRTOS running with Microsemi RISC-V processor. This project creates two +tasks and runs them at regular intervals. + +This example project requires USB-UART interface to be connected to a host PC. +The host PC must connect to the serial port using a terminal emulator such as +TeraTerm or PuTTY configured as follows: + + - 115200 baud + - 8 data bits + - 1 stop bit + - no parity + - no flow control + +The ./hw_platform.h file contains the design related information that is required +for this project. If you update the design, the hw_platform.h must be updated +accordingly. + +### FreeRTOS Configurations +You must configure the FreeRTOS as per your applications need. Please read and modify FreeRTOSConfig.h. +E.g. You must set configCPU_CLOCK_HZ parameter in FreeRTOSConfig.h according to the hardware platform +design that you are using. + +The RISC-V creative board design uses 66Mhz processor clock. The PolarFire Eval Kit design uses 50Mhz processor clock. The SmartFusion2 Adv. Development kit design uses 83Mhz processor clock. + +### Microsemi SoftConsole Toolchain +To know more please refer: [SoftConsole](https://github.com/RISCV-on-Microsemi-FPGA/SoftConsole) + +### Documentation for Microsemi RISC-V processor, SoftConsole toochain, Debug Tools, FPGA design etc. +To know more please refer: [Documentation](https://github.com/RISCV-on-Microsemi-FPGA/Documentation) + diff --git a/FreeRTOS/Demo/RISC-V_IGLOO2_Creative_SoftConsole/RTOSDemo Debug.launch b/FreeRTOS/Demo/RISC-V_IGLOO2_Creative_SoftConsole/RTOSDemo Debug.launch new file mode 100644 index 000000000..9bc0bf0f3 --- /dev/null +++ b/FreeRTOS/Demo/RISC-V_IGLOO2_Creative_SoftConsole/RTOSDemo Debug.launch @@ -0,0 +1,59 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/FreeRTOS/Demo/RISC-V_IGLOO2_Creative_SoftConsole/drivers/Core16550/core16550_regs.h b/FreeRTOS/Demo/RISC-V_IGLOO2_Creative_SoftConsole/drivers/Core16550/core16550_regs.h new file mode 100644 index 000000000..0b921ce74 --- /dev/null +++ b/FreeRTOS/Demo/RISC-V_IGLOO2_Creative_SoftConsole/drivers/Core16550/core16550_regs.h @@ -0,0 +1,582 @@ +/******************************************************************************* + * (c) Copyright 2007-2015 Microsemi SoC Products Group. All rights reserved. + * + * IP core registers definitions. This file contains the definitions required + * for accessing the IP core through the hardware abstraction layer (HAL). + * This file was automatically generated, using "get_header.exe" version 0.4.0, + * from the IP-XACT description for: + * + * Core16550 version: 2.0.0 + * + * SVN $Revision: 7963 $ + * SVN $Date: 2015-10-09 17:58:21 +0530 (Fri, 09 Oct 2015) $ + * + *******************************************************************************/ +#ifndef CORE_16550_REGISTERS_H_ +#define CORE_16550_REGISTERS_H_ 1 + +#ifdef __cplusplus +extern "C" { +#endif + +/******************************************************************************* + * RBR register: + *------------------------------------------------------------------------------ + * Receive Buffer Register + */ +#define RBR_REG_OFFSET 0x00U + +/******************************************************************************* + * THR register: + *------------------------------------------------------------------------------ + * Transmit Holding Register + */ +#define THR_REG_OFFSET 0x00U + +/******************************************************************************* + * DLR register: + *------------------------------------------------------------------------------ + * Divisor Latch(LSB) Register + */ +#define DLR_REG_OFFSET 0x00U + +/******************************************************************************* + * DMR register: + *------------------------------------------------------------------------------ + * Divisor Latch(MSB) Register + */ +#define DMR_REG_OFFSET 0x04U + +/******************************************************************************* + * IER register: + *------------------------------------------------------------------------------ + * Interrupt Enable Register + */ +#define IER_REG_OFFSET 0x04U + +/*------------------------------------------------------------------------------ + * IER_ERBFI: + * ERBFI field of register IER. + *------------------------------------------------------------------------------ + * Enables Received Data Available Interrupt. 0 - Disabled; 1 - Enabled + */ +#define IER_ERBFI_OFFSET 0x04U +#define IER_ERBFI_MASK 0x01U +#define IER_ERBFI_SHIFT 0U + +/*------------------------------------------------------------------------------ + * IER_ETBEI: + * ETBEI field of register IER. + *------------------------------------------------------------------------------ + * Enables the Transmitter Holding Register Empty Interrupt. 0 - Disabled; 1 - + * Enabled + */ +#define IER_ETBEI_OFFSET 0x04U +#define IER_ETBEI_MASK 0x02U +#define IER_ETBEI_SHIFT 1U + +/*------------------------------------------------------------------------------ + * IER_ELSI: + * ELSI field of register IER. + *------------------------------------------------------------------------------ + * Enables the Receiver Line Status Interrupt. 0 - Disabled; 1 - Enabled + */ +#define IER_ELSI_OFFSET 0x04U +#define IER_ELSI_MASK 0x04U +#define IER_ELSI_SHIFT 2U + +/*------------------------------------------------------------------------------ + * IER_EDSSI: + * EDSSI field of register IER. + *------------------------------------------------------------------------------ + * Enables the Modem Status Interrupt 0 - Disabled; 1 - Enabled + */ +#define IER_EDSSI_OFFSET 0x04U +#define IER_EDSSI_MASK 0x08U +#define IER_EDSSI_SHIFT 3U + +/******************************************************************************* + * IIR register: + *------------------------------------------------------------------------------ + * Interrupt Identification + */ +#define IIR_REG_OFFSET 0x08U + +/*------------------------------------------------------------------------------ + * IIR_IIR: + * IIR field of register IIR. + *------------------------------------------------------------------------------ + * Interrupt Identification bits. + */ +#define IIR_IIR_OFFSET 0x08U +#define IIR_IIR_MASK 0x0FU +#define IIR_IIR_SHIFT 0U + +/*------------------------------------------------------------------------------ + * IIR_IIR: + * IIR field of register IIR. + *------------------------------------------------------------------------------ + * Interrupt Identification bits. + */ + +/*------------------------------------------------------------------------------ + * IIR_Mode: + * Mode field of register IIR. + *------------------------------------------------------------------------------ + * 11 - FIFO mode + */ +#define IIR_MODE_OFFSET 0x08U +#define IIR_MODE_MASK 0xC0U +#define IIR_MODE_SHIFT 6U + +/******************************************************************************* + * FCR register: + *------------------------------------------------------------------------------ + * FIFO Control Register + */ +#define FCR_REG_OFFSET 0x08 + +/*------------------------------------------------------------------------------ + * FCR_Bit0: + * Bit0 field of register FCR. + *------------------------------------------------------------------------------ + * This bit enables both the TX and RX FIFOs. + */ +#define FCR_BIT0_OFFSET 0x08U +#define FCR_BIT0_MASK 0x01U +#define FCR_BIT0_SHIFT 0U + +#define FCR_ENABLE_OFFSET 0x08U +#define FCR_ENABLE_MASK 0x01U +#define FCR_ENABLE_SHIFT 0U + +/*------------------------------------------------------------------------------ + * FCR_Bit1: + * Bit1 field of register FCR. + *------------------------------------------------------------------------------ + * Clears all bytes in the RX FIFO and resets its counter logic. The shift + * register is not cleared. 0 - Disabled; 1 - Enabled + */ +#define FCR_BIT1_OFFSET 0x08U +#define FCR_BIT1_MASK 0x02U +#define FCR_BIT1_SHIFT 1U + +#define FCR_CLEAR_RX_OFFSET 0x08U +#define FCR_CLEAR_RX_MASK 0x02U +#define FCR_CLEAR_RX_SHIFT 1U + +/*------------------------------------------------------------------------------ + * FCR_Bit2: + * Bit2 field of register FCR. + *------------------------------------------------------------------------------ + * Clears all bytes in the TX FIFO and resets its counter logic. The shift + * register is not cleared. 0 - Disabled; 1 - Enabled + */ +#define FCR_BIT2_OFFSET 0x08U +#define FCR_BIT2_MASK 0x04U +#define FCR_BIT2_SHIFT 2U + +#define FCR_CLEAR_TX_OFFSET 0x08U +#define FCR_CLEAR_TX_MASK 0x04U +#define FCR_CLEAR_TX_SHIFT 2U + +/*------------------------------------------------------------------------------ + * FCR_Bit3: + * Bit3 field of register FCR. + *------------------------------------------------------------------------------ + * Enables RXRDYN and TXRDYN pins when set to 1. Otherwise, they are disabled. + */ +#define FCR_BIT3_OFFSET 0x08U +#define FCR_BIT3_MASK 0x08U +#define FCR_BIT3_SHIFT 3U + +#define FCR_RDYN_EN_OFFSET 0x08U +#define FCR_RDYN_EN_MASK 0x08U +#define FCR_RDYN_EN_SHIFT 3U + +/*------------------------------------------------------------------------------ + * FCR_Bit6: + * Bit6 field of register FCR. + *------------------------------------------------------------------------------ + * These bits are used to set the trigger level for the RX FIFO interrupt. RX + * FIFO Trigger Level: 0 - 1; 1 - 4; 2 - 8; 3 - 14 + */ +#define FCR_BIT6_OFFSET 0x08U +#define FCR_BIT6_MASK 0xC0U +#define FCR_BIT6_SHIFT 6U + +#define FCR_TRIG_LEVEL_OFFSET 0x08U +#define FCR_TRIG_LEVEL_MASK 0xC0U +#define FCR_TRIG_LEVEL_SHIFT 6U + +/******************************************************************************* + * LCR register: + *------------------------------------------------------------------------------ + * Line Control Register + */ +#define LCR_REG_OFFSET 0x0CU + +/*------------------------------------------------------------------------------ + * LCR_WLS: + * WLS field of register LCR. + *------------------------------------------------------------------------------ + * Word Length Select: 00 - 5 bits; 01 - 6 bits; 10 - 7 bits; 11 - 8 bits + */ +#define LCR_WLS_OFFSET 0x0CU +#define LCR_WLS_MASK 0x03U +#define LCR_WLS_SHIFT 0U + +/*------------------------------------------------------------------------------ + * LCR_STB: + * STB field of register LCR. + *------------------------------------------------------------------------------ + * Number of Stop Bits: 0 - 1 stop bit; 1 - 1½ stop bits when WLS = 00, 2 stop + * bits in other cases + */ +#define LCR_STB_OFFSET 0x0CU +#define LCR_STB_MASK 0x04U +#define LCR_STB_SHIFT 2U + +/*------------------------------------------------------------------------------ + * LCR_PEN: + * PEN field of register LCR. + *------------------------------------------------------------------------------ + * Parity Enable 0 - Disabled; 1 - Enabled. Parity is added in transmission and + * checked in receiving. + */ +#define LCR_PEN_OFFSET 0x0CU +#define LCR_PEN_MASK 0x08U +#define LCR_PEN_SHIFT 3U + +/*------------------------------------------------------------------------------ + * LCR_EPS: + * EPS field of register LCR. + *------------------------------------------------------------------------------ + * Even Parity Select 0 - Odd parity; 1 - Even parity + */ +#define LCR_EPS_OFFSET 0x0CU +#define LCR_EPS_MASK 0x10U +#define LCR_EPS_SHIFT 4U + +/*------------------------------------------------------------------------------ + * LCR_SP: + * SP field of register LCR. + *------------------------------------------------------------------------------ + * Stick Parity 0 - Disabled; 1 - Enabled When stick parity is enabled, it + * works as follows: Bits 4..3, 11 - 0 will be sent as a parity bit, and + * checked in receiving. 01 - 1 will be sent as a parity bit, and checked in + * receiving. + */ +#define LCR_SP_OFFSET 0x0CU +#define LCR_SP_MASK 0x20U +#define LCR_SP_SHIFT 5U + +/*------------------------------------------------------------------------------ + * LCR_SB: + * SB field of register LCR. + *------------------------------------------------------------------------------ + * Set Break 0 - Disabled 1 - Set break. SOUT is forced to 0. This does not + * have any effect on transmitter logic. The break is disabled by setting the + * bit to 0. + */ +#define LCR_SB_OFFSET 0x0CU +#define LCR_SB_MASK 0x40U +#define LCR_SB_SHIFT 6U + +/*------------------------------------------------------------------------------ + * LCR_DLAB: + * DLAB field of register LCR. + *------------------------------------------------------------------------------ + * Divisor Latch Access Bit 0 - Disabled. Normal addressing mode in use 1 - + * Enabled. Enables access to the Divisor Latch registers during read or write + * operation to addresses 0 and 1. + */ +#define LCR_DLAB_OFFSET 0x0CU +#define LCR_DLAB_MASK 0x80U +#define LCR_DLAB_SHIFT 7U + +/******************************************************************************* + * MCR register: + *------------------------------------------------------------------------------ + * Modem Control Register + */ +#define MCR_REG_OFFSET 0x10U + +/*------------------------------------------------------------------------------ + * MCR_DTR: + * DTR field of register MCR. + *------------------------------------------------------------------------------ + * Controls the Data Terminal Ready (DTRn) output. 0 - DTRn <= 1; 1 - DTRn <= 0 + */ +#define MCR_DTR_OFFSET 0x10U +#define MCR_DTR_MASK 0x01U +#define MCR_DTR_SHIFT 0U + +/*------------------------------------------------------------------------------ + * MCR_RTS: + * RTS field of register MCR. + *------------------------------------------------------------------------------ + * Controls the Request to Send (RTSn) output. 0 - RTSn <= 1; 1 - RTSn <= 0 + */ +#define MCR_RTS_OFFSET 0x10U +#define MCR_RTS_MASK 0x02U +#define MCR_RTS_SHIFT 1U + +/*------------------------------------------------------------------------------ + * MCR_Out1: + * Out1 field of register MCR. + *------------------------------------------------------------------------------ + * Controls the Output1 (OUT1n) signal. 0 - OUT1n <= 1; 1 - OUT1n <= 0 + */ +#define MCR_OUT1_OFFSET 0x10U +#define MCR_OUT1_MASK 0x04U +#define MCR_OUT1_SHIFT 2U + +/*------------------------------------------------------------------------------ + * MCR_Out2: + * Out2 field of register MCR. + *------------------------------------------------------------------------------ + * Controls the Output2 (OUT2n) signal. 0 - OUT2n <=1; 1 - OUT2n <=0 + */ +#define MCR_OUT2_OFFSET 0x10U +#define MCR_OUT2_MASK 0x08U +#define MCR_OUT2_SHIFT 3U + +/*------------------------------------------------------------------------------ + * MCR_Loop: + * Loop field of register MCR. + *------------------------------------------------------------------------------ + * Loop enable bit 0 - Disabled; 1 - Enabled. The following happens in loop + * mode: SOUT is set to 1. The SIN, DSRn, CTSn, RIn, and DCDn inputs are + * disconnected. The output of the Transmitter Shift Register is looped back + * into the Receiver Shift Register. The modem control outputs (DTRn, RTSn, + * OUT1n, and OUT2n) are connected internally to the modem control inputs, and + * the modem control output pins are set at 1. In loopback mode, the + * transmitted data is immediately received, allowing the CPU to check the + * operation of the UART. The interrupts are operating in loop mode. + */ +#define MCR_LOOP_OFFSET 0x10U +#define MCR_LOOP_MASK 0x10U +#define MCR_LOOP_SHIFT 4U + +/******************************************************************************* + * LSR register: + *------------------------------------------------------------------------------ + * Line Status Register + */ +#define LSR_REG_OFFSET 0x14U + +/*------------------------------------------------------------------------------ + * LSR_DR: + * DR field of register LSR. + *------------------------------------------------------------------------------ + * Data Ready indicator 1 when a data byte has been received and stored in the + * FIFO. DR is cleared to 0 when the CPU reads the data from the FIFO. + */ +#define LSR_DR_OFFSET 0x14U +#define LSR_DR_MASK 0x01U +#define LSR_DR_SHIFT 0U + +/*------------------------------------------------------------------------------ + * LSR_OE: + * OE field of register LSR. + *------------------------------------------------------------------------------ + * Overrun Error indicator Indicates that the new byte was received before the + * CPU read the byte from the receive buffer, and that the earlier data byte + * was destroyed. OE is cleared when the CPU reads the Line Status Register. If + * the data continues to fill the FIFO beyond the trigger level, an overrun + * error will occur once the FIFO is full and the next character has been + * completely received in the shift register. The character in the shift + * register is overwritten, but it is not transferred to the FIFO. + */ +#define LSR_OE_OFFSET 0x14U +#define LSR_OE_MASK 0x02U +#define LSR_OE_SHIFT 1U + +/*------------------------------------------------------------------------------ + * LSR_PE: + * PE field of register LSR. + *------------------------------------------------------------------------------ + * Parity Error indicator Indicates that the received byte had a parity error. + * PE is cleared when the CPU reads the Line Status Register. This error is + * revealed to the CPU when its associated character is at the top of the FIFO. + */ +#define LSR_PE_OFFSET 0x14U +#define LSR_PE_MASK 0x04U +#define LSR_PE_SHIFT 2U + +/*------------------------------------------------------------------------------ + * LSR_FE: + * FE field of register LSR. + *------------------------------------------------------------------------------ + * Framing Error indicator Indicates that the received byte did not have a + * valid Stop bit. FE is cleared when the CPU reads the Line Status Register. + * The UART will try to re-synchronize after a framing error. To do this, it + * assumes that the framing error was due to the next start bit, so it samples + * this start bit twice, and then starts receiving the data. This error is + * revealed to the CPU when its associated character is at the top of the FIFO. + */ +#define LSR_FE_OFFSET 0x14U +#define LSR_FE_MASK 0x08U +#define LSR_FE_SHIFT 3U + +/*------------------------------------------------------------------------------ + * LSR_BI: + * BI field of register LSR. + *------------------------------------------------------------------------------ + * Break Interrupt indicator Indicates that the received data is at 0 longer + * than a full word transmission time (start bit + data bits + parity + stop + * bits). BI is cleared when the CPU reads the Line Status Register. This error + * is revealed to the CPU when its associated character is at the top of the + * FIFO. When break occurs, only one zero character is loaded into the FIFO. + */ +#define LSR_BI_OFFSET 0x14U +#define LSR_BI_MASK 0x10U +#define LSR_BI_SHIFT 4U + +/*------------------------------------------------------------------------------ + * LSR_THRE: + * THRE field of register LSR. + *------------------------------------------------------------------------------ + * Transmitter Holding Register Empty indicator Indicates that the UART is + * ready to transmit a new data byte. THRE causes an interrupt to the CPU when + * bit 1 (ETBEI) in the Interrupt Enable Register is 1. This bit is set when + * the TX FIFO is empty. It is cleared when at least one byte is written to the + * TX FIFO. + */ +#define LSR_THRE_OFFSET 0x14U +#define LSR_THRE_MASK 0x20U +#define LSR_THRE_SHIFT 5U + +/*------------------------------------------------------------------------------ + * LSR_TEMT: + * TEMT field of register LSR. + *------------------------------------------------------------------------------ + * Transmitter Empty indicator This bit is set to 1 when both the transmitter + * FIFO and shift registers are empty. + */ +#define LSR_TEMT_OFFSET 0x14U +#define LSR_TEMT_MASK 0x40U +#define LSR_TEMT_SHIFT 6U + +/*------------------------------------------------------------------------------ + * LSR_FIER: + * FIER field of register LSR. + *------------------------------------------------------------------------------ + * This bit is set when there is at least one parity error, framing error, or + * break indication in the FIFO. FIER is cleared when the CPU reads the LSR if + * there are no subsequent errors in the FIFO. + */ +#define LSR_FIER_OFFSET 0x14U +#define LSR_FIER_MASK 0x80U +#define LSR_FIER_SHIFT 7U + +/******************************************************************************* + * MSR register: + *------------------------------------------------------------------------------ + * Modem Status Register + */ +#define MSR_REG_OFFSET 0x18U + +/*------------------------------------------------------------------------------ + * MSR_DCTS: + * DCTS field of register MSR. + *------------------------------------------------------------------------------ + * Delta Clear to Send indicator. Indicates that the CTSn input has changed + * state since the last time it was read by the CPU. + */ +#define MSR_DCTS_OFFSET 0x18U +#define MSR_DCTS_MASK 0x01U +#define MSR_DCTS_SHIFT 0U + +/*------------------------------------------------------------------------------ + * MSR_DDSR: + * DDSR field of register MSR. + *------------------------------------------------------------------------------ + * Delta Data Set Ready indicator Indicates that the DSRn input has changed + * state since the last time it was read by the CPU. + */ +#define MSR_DDSR_OFFSET 0x18U +#define MSR_DDSR_MASK 0x02U +#define MSR_DDSR_SHIFT 1U + +/*------------------------------------------------------------------------------ + * MSR_TERI: + * TERI field of register MSR. + *------------------------------------------------------------------------------ + * Trailing Edge of Ring Indicator detector. Indicates that RI input has + * changed from 0 to 1. + */ +#define MSR_TERI_OFFSET 0x18U +#define MSR_TERI_MASK 0x04U +#define MSR_TERI_SHIFT 2U + +/*------------------------------------------------------------------------------ + * MSR_DDCD: + * DDCD field of register MSR. + *------------------------------------------------------------------------------ + * Delta Data Carrier Detect indicator Indicates that DCD input has changed + * state. NOTE: Whenever bit 0, 1, 2, or 3 is set to 1, a Modem Status + * Interrupt is generated. + */ +#define MSR_DDCD_OFFSET 0x18U +#define MSR_DDCD_MASK 0x08U +#define MSR_DDCD_SHIFT 3U + +/*------------------------------------------------------------------------------ + * MSR_CTS: + * CTS field of register MSR. + *------------------------------------------------------------------------------ + * Clear to Send The complement of the CTSn input. When bit 4 of the Modem + * Control Register (MCR) is set to 1 (loop), this bit is equivalent to DTR in + * the MCR. + */ +#define MSR_CTS_OFFSET 0x18U +#define MSR_CTS_MASK 0x10U +#define MSR_CTS_SHIFT 4U + +/*------------------------------------------------------------------------------ + * MSR_DSR: + * DSR field of register MSR. + *------------------------------------------------------------------------------ + * Data Set Ready The complement of the DSR input. When bit 4 of the MCR is set + * to 1 (loop), this bit is equivalent to RTSn in the MCR. + */ +#define MSR_DSR_OFFSET 0x18U +#define MSR_DSR_MASK 0x20U +#define MSR_DSR_SHIFT 5U + +/*------------------------------------------------------------------------------ + * MSR_RI: + * RI field of register MSR. + *------------------------------------------------------------------------------ + * Ring Indicator The complement of the RIn input. When bit 4 of the MCR is set + * to 1 (loop), this bit is equivalent to OUT1 in the MCR. + */ +#define MSR_RI_OFFSET 0x18U +#define MSR_RI_MASK 0x40U +#define MSR_RI_SHIFT 6U + +/*------------------------------------------------------------------------------ + * MSR_DCD: + * DCD field of register MSR. + *------------------------------------------------------------------------------ + * Data Carrier Detect The complement of DCDn input. When bit 4 of the MCR is + * set to 1 (loop), this bit is equivalent to OUT2 in the MCR. + */ +#define MSR_DCD_OFFSET 0x18U +#define MSR_DCD_MASK 0x80U +#define MSR_DCD_SHIFT 7U + +/******************************************************************************* + * SR register: + *------------------------------------------------------------------------------ + * Scratch Register + */ +#define SR_REG_OFFSET 0x1CU + +#ifdef __cplusplus +} +#endif + +#endif /* CORE_16550_REGISTERS_H_*/ diff --git a/FreeRTOS/Demo/RISC-V_IGLOO2_Creative_SoftConsole/drivers/Core16550/core_16550.c b/FreeRTOS/Demo/RISC-V_IGLOO2_Creative_SoftConsole/drivers/Core16550/core_16550.c new file mode 100644 index 000000000..ca735e63a --- /dev/null +++ b/FreeRTOS/Demo/RISC-V_IGLOO2_Creative_SoftConsole/drivers/Core16550/core_16550.c @@ -0,0 +1,865 @@ +/******************************************************************************* + * (c) Copyright 2007-2015 Microsemi SoC Products Group. All rights reserved. + * + * Core16550 driver implementation. See file "core_16550.h" for a + * description of the functions implemented in this file. + * + * SVN $Revision: 7963 $ + * SVN $Date: 2015-10-09 17:58:21 +0530 (Fri, 09 Oct 2015) $ + */ +#include "hal.h" +#include "core_16550.h" +#include "core16550_regs.h" +#include "hal_assert.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/******************************************************************************* + * Definitions for transmitter states + */ +#define TX_COMPLETE 0x00U + +/******************************************************************************* + * Definition for transmitter FIFO size + */ +#define TX_FIFO_SIZE 16U + +/******************************************************************************* + * Default receive interrupt trigger level + */ +#define DEFAULT_RX_TRIG_LEVEL ((uint8_t)UART_16550_FIFO_SINGLE_BYTE) + +/******************************************************************************* + * Receiver error status mask and shift offset + */ +#define STATUS_ERROR_MASK ( LSR_OE_MASK | LSR_PE_MASK | \ + LSR_FE_MASK | LSR_BI_MASK | LSR_FIER_MASK) + +/******************************************************************************* + * Definitions for invalid parameters with proper type + */ +#define INVALID_INTERRUPT 0U +#define INVALID_IRQ_HANDLER ( (uart_16550_irq_handler_t) 0 ) + +/******************************************************************************* + * Possible values for Interrupt Identification Register Field. + */ +#define IIRF_MODEM_STATUS 0x00U +#define IIRF_THRE 0x02U +#define IIRF_RX_DATA 0x04U +#define IIRF_RX_LINE_STATUS 0x06U +#define IIRF_DATA_TIMEOUT 0x0CU + +/******************************************************************************* + * Null parameters with appropriate type definitions + */ +#define NULL_ADDR ( ( addr_t ) 0 ) +#define NULL_INSTANCE ( ( uart_16550_instance_t * ) 0 ) +#define NULL_BUFF ( ( uint8_t * ) 0 ) + +/******************************************************************************* + * Possible states for different register bit fields + */ +enum { + DISABLE = 0U, + ENABLE = 1U +}; + +/******************************************************************************* + * Static function declarations + */ +static void default_tx_handler(uart_16550_instance_t * this_uart); + +/******************************************************************************* + * Public function definitions + */ + +/***************************************************************************//** + * UART_16550_init. + * See core_16550.h for details of how to use this function. + */ +void +UART_16550_init +( + uart_16550_instance_t* this_uart, + addr_t base_addr, + uint16_t baud_value, + uint8_t line_config +) +{ +#ifndef NDEBUG + uint8_t dbg1; + uint8_t dbg2; +#endif + uint8_t fifo_config; + uint8_t temp; + + HAL_ASSERT( base_addr != NULL_ADDR ); + HAL_ASSERT( this_uart != NULL_INSTANCE ); + + if( ( base_addr != NULL_ADDR ) && ( this_uart != NULL_INSTANCE ) ) + { + /* disable interrupts */ + HAL_set_8bit_reg(base_addr, IER, DISABLE); + + /* reset divisor latch */ + HAL_set_8bit_reg_field(base_addr, LCR_DLAB, ENABLE); +#ifndef NDEBUG + dbg1 = HAL_get_8bit_reg_field(base_addr, LCR_DLAB ); + HAL_ASSERT( dbg1 == ENABLE ); +#endif + /* MSB of baud value */ + temp = (uint8_t)(baud_value >> 8); + HAL_set_8bit_reg(base_addr, DMR, temp ); + /* LSB of baud value */ + HAL_set_8bit_reg(base_addr, DLR, ( (uint8_t)baud_value ) ); +#ifndef NDEBUG + dbg1 = HAL_get_8bit_reg(base_addr, DMR ); + dbg2 = HAL_get_8bit_reg(base_addr, DLR ); + HAL_ASSERT( ( ( ( (uint16_t) dbg1 ) << 8 ) | dbg2 ) == baud_value ); +#endif + /* reset divisor latch */ + HAL_set_8bit_reg_field(base_addr, LCR_DLAB, DISABLE); +#ifndef NDEBUG + dbg1 = HAL_get_8bit_reg_field(base_addr, LCR_DLAB ); + HAL_ASSERT( dbg1 == DISABLE ); +#endif + /* set the line control register (bit length, stop bits, parity) */ + HAL_set_8bit_reg( base_addr, LCR, line_config ); +#ifndef NDEBUG + dbg1 = HAL_get_8bit_reg(base_addr, LCR ); + HAL_ASSERT( dbg1 == line_config) +#endif + /* Enable and configure the RX and TX FIFOs. */ + fifo_config = ((uint8_t)(DEFAULT_RX_TRIG_LEVEL << FCR_TRIG_LEVEL_SHIFT) | + FCR_RDYN_EN_MASK | FCR_CLEAR_RX_MASK | + FCR_CLEAR_TX_MASK | FCR_ENABLE_MASK ); + HAL_set_8bit_reg( base_addr, FCR, fifo_config ); + + /* disable loopback */ + HAL_set_8bit_reg_field( base_addr, MCR_LOOP, DISABLE ); +#ifndef NDEBUG + dbg1 = HAL_get_8bit_reg_field(base_addr, MCR_LOOP); + HAL_ASSERT( dbg1 == DISABLE ); +#endif + + /* Instance setup */ + this_uart->base_address = base_addr; + this_uart->tx_buffer = NULL_BUFF; + this_uart->tx_buff_size = TX_COMPLETE; + this_uart->tx_idx = 0U; + this_uart->tx_handler = default_tx_handler; + + this_uart->rx_handler = ( (uart_16550_irq_handler_t) 0 ); + this_uart->linests_handler = ( (uart_16550_irq_handler_t) 0 ); + this_uart->modemsts_handler = ( (uart_16550_irq_handler_t) 0 ); + this_uart->status = 0U; + } +} + +/***************************************************************************//** + * UART_16550_polled_tx. + * See core_16550.h for details of how to use this function. + */ +void +UART_16550_polled_tx +( + uart_16550_instance_t * this_uart, + const uint8_t * pbuff, + uint32_t tx_size +) +{ + uint32_t char_idx = 0U; + uint32_t size_sent; + uint8_t status; + + HAL_ASSERT( this_uart != NULL_INSTANCE ); + HAL_ASSERT( pbuff != NULL_BUFF ); + HAL_ASSERT( tx_size > 0U ); + + if( ( this_uart != NULL_INSTANCE ) && + ( pbuff != NULL_BUFF ) && + ( tx_size > 0U ) ) + { + /* Remain in this loop until the entire input buffer + * has been transferred to the UART. + */ + do { + /* Read the Line Status Register and update the sticky record */ + status = HAL_get_8bit_reg( this_uart->base_address, LSR ); + this_uart->status |= status; + + /* Check if TX FIFO is empty. */ + if( status & LSR_THRE_MASK ) + { + uint32_t fill_size = TX_FIFO_SIZE; + + /* Calculate the number of bytes to transmit. */ + if ( tx_size < TX_FIFO_SIZE ) + { + fill_size = tx_size; + } + + /* Fill the TX FIFO with the calculated the number of bytes. */ + for ( size_sent = 0U; size_sent < fill_size; ++size_sent ) + { + /* Send next character in the buffer. */ + HAL_set_8bit_reg( this_uart->base_address, THR, + (uint_fast8_t)pbuff[char_idx++]); + } + + /* Calculate the number of untransmitted bytes remaining. */ + tx_size -= size_sent; + } + } while ( tx_size ); + } +} + +/***************************************************************************//** + * UART_16550_polled_tx_string. + * See core_16550.h for details of how to use this function. + */ +void +UART_16550_polled_tx_string +( + uart_16550_instance_t * this_uart, + const uint8_t * p_sz_string +) +{ + uint32_t char_idx = 0U; + uint32_t fill_size; + uint_fast8_t data_byte; + uint8_t status; + + HAL_ASSERT( this_uart != NULL_INSTANCE ); + HAL_ASSERT( p_sz_string != NULL_BUFF ); + + if( ( this_uart != NULL_INSTANCE ) && ( p_sz_string != NULL_BUFF ) ) + { + char_idx = 0U; + + /* Get the first data byte from the input buffer */ + data_byte = (uint_fast8_t)p_sz_string[char_idx]; + + /* First check for the NULL terminator byte. + * Then remain in this loop until the entire string in the input buffer + * has been transferred to the UART. + */ + while ( 0U != data_byte ) + { + /* Wait until TX FIFO is empty. */ + do { + status = HAL_get_8bit_reg( this_uart->base_address,LSR); + this_uart->status |= status; + } while ( !( status & LSR_THRE_MASK ) ); + + /* Send bytes from the input buffer until the TX FIFO is full + * or we reach the NULL terminator byte. + */ + fill_size = 0U; + while ( (0U != data_byte) && (fill_size < TX_FIFO_SIZE) ) + { + /* Send the data byte */ + HAL_set_8bit_reg( this_uart->base_address, THR, data_byte ); + ++fill_size; + char_idx++; + /* Get the next data byte from the input buffer */ + data_byte = (uint_fast8_t)p_sz_string[char_idx]; + } + } + } +} + + +/***************************************************************************//** + * UART_16550_irq_tx. + * See core_16550.h for details of how to use this function. + */ +void +UART_16550_irq_tx +( + uart_16550_instance_t * this_uart, + const uint8_t * pbuff, + uint32_t tx_size +) +{ + HAL_ASSERT( this_uart != NULL_INSTANCE ) + HAL_ASSERT( pbuff != NULL_BUFF ) + HAL_ASSERT( tx_size > 0U ) + + if( ( this_uart != NULL_INSTANCE ) && + ( pbuff != NULL_BUFF ) && + ( tx_size > 0U ) ) + { + /*Initialize the UART instance with + parameters required for transmission.*/ + this_uart->tx_buffer = pbuff; + this_uart->tx_buff_size = tx_size; + /* char_idx; */ + this_uart->tx_idx = 0U; + /* assign handler for default data transmission */ + this_uart->tx_handler = default_tx_handler; + + /* enables TX interrupt */ + HAL_set_8bit_reg_field(this_uart->base_address, IER_ETBEI, ENABLE); + } +} + +/***************************************************************************//** + * UART_16550_tx_complete. + * See core_16550.h for details of how to use this function. + */ +int8_t +UART_16550_tx_complete +( + uart_16550_instance_t * this_uart +) +{ + int8_t returnvalue = 0; + uint8_t status = 0U; + + HAL_ASSERT( this_uart != NULL_INSTANCE ) + + if( this_uart != NULL_INSTANCE ) + { + status = HAL_get_8bit_reg(this_uart->base_address,LSR); + this_uart->status |= status; + + if( ( this_uart->tx_buff_size == TX_COMPLETE ) && + ( status & LSR_TEMT_MASK ) ) + { + returnvalue = (int8_t)1; + } + } + return returnvalue; +} + + +/***************************************************************************//** + * UART_16550_get_rx. + * See core_16550.h for details of how to use this function. + */ +size_t +UART_16550_get_rx +( + uart_16550_instance_t * this_uart, + uint8_t * rx_buff, + size_t buff_size +) +{ + uint8_t status; + size_t rx_size = 0U; + + HAL_ASSERT( this_uart != NULL_INSTANCE ) + HAL_ASSERT( rx_buff != (uint8_t *)0 ) + HAL_ASSERT( buff_size > 0U ) + + if( ( this_uart != NULL_INSTANCE ) && + ( rx_buff != (uint8_t *)0 ) && + ( buff_size > 0U ) ) + { + status = HAL_get_8bit_reg( this_uart->base_address, LSR ); + this_uart->status |= status; + while ( ((status & LSR_DR_MASK) != 0U) && ( rx_size < buff_size ) ) + { + rx_buff[rx_size] = HAL_get_8bit_reg( this_uart->base_address, RBR ); + rx_size++; + status = HAL_get_8bit_reg( this_uart->base_address, LSR ); + this_uart->status |= status; + } + } + return rx_size; +} + +/***************************************************************************//** + * UART_16550_isr. + * See core_16550.h for details of how to use this function. + */ +void +UART_16550_isr +( + uart_16550_instance_t * this_uart +) +{ + uint8_t iirf; + + HAL_ASSERT( this_uart != NULL_INSTANCE ) + + if(this_uart != NULL_INSTANCE ) + { + iirf = HAL_get_8bit_reg_field( this_uart->base_address, IIR_IIR ); + + switch ( iirf ) + { + /* Modem status interrupt */ + case IIRF_MODEM_STATUS: + { + if( INVALID_IRQ_HANDLER != this_uart->modemsts_handler ) + { + HAL_ASSERT( INVALID_IRQ_HANDLER != this_uart->modemsts_handler ); + if( INVALID_IRQ_HANDLER != this_uart->modemsts_handler ) + { + (*(this_uart->modemsts_handler))(this_uart); + } + } + } + break; + /* Transmitter Holding Register Empty interrupt */ + case IIRF_THRE: + { + HAL_ASSERT( INVALID_IRQ_HANDLER != this_uart->tx_handler ); + if ( INVALID_IRQ_HANDLER != this_uart->tx_handler ) + { + (*(this_uart->tx_handler))(this_uart); + } + } + break; + /* Received Data Available interrupt */ + case IIRF_RX_DATA: + case IIRF_DATA_TIMEOUT: + { + HAL_ASSERT( INVALID_IRQ_HANDLER != this_uart->rx_handler ); + if ( INVALID_IRQ_HANDLER != this_uart->rx_handler ) + { + (*(this_uart->rx_handler))(this_uart); + } + } + break; + /* Line status interrupt */ + case IIRF_RX_LINE_STATUS: + { + HAL_ASSERT( INVALID_IRQ_HANDLER != this_uart->linests_handler ); + if ( INVALID_IRQ_HANDLER != this_uart->linests_handler ) + { + (*(this_uart->linests_handler))(this_uart); + } + } + break; + /* Unidentified interrupt */ + default: + { + HAL_ASSERT( INVALID_INTERRUPT ) + } + } + } +} + +/***************************************************************************//** + * UART_16550_set_rx_handler. + * See core_16550.h for details of how to use this function. + */ +void +UART_16550_set_rx_handler +( + uart_16550_instance_t * this_uart, + uart_16550_irq_handler_t handler, + uart_16550_rx_trig_level_t trigger_level +) +{ + HAL_ASSERT( this_uart != NULL_INSTANCE ) + HAL_ASSERT( handler != INVALID_IRQ_HANDLER) + HAL_ASSERT( trigger_level < UART_16550_FIFO_INVALID_TRIG_LEVEL) + + if( ( this_uart != NULL_INSTANCE ) && + ( handler != INVALID_IRQ_HANDLER) && + ( trigger_level < UART_16550_FIFO_INVALID_TRIG_LEVEL) ) + { + this_uart->rx_handler = handler; + + /* Set the receive interrupt trigger level. */ + HAL_set_8bit_reg_field( this_uart->base_address, + FCR_TRIG_LEVEL, trigger_level ); + + /* Enable receive interrupt. */ + HAL_set_8bit_reg_field( this_uart->base_address, IER_ERBFI, ENABLE ); + } +} + +/***************************************************************************//** + * UART_16550_set_loopback. + * See core_16550.h for details of how to use this function. + */ +void +UART_16550_set_loopback +( + uart_16550_instance_t * this_uart, + uart_16550_loopback_t loopback +) +{ + HAL_ASSERT( this_uart != NULL_INSTANCE ); + HAL_ASSERT( loopback < UART_16550_INVALID_LOOPBACK ); + + if( ( this_uart != NULL_INSTANCE ) && + ( loopback < UART_16550_INVALID_LOOPBACK ) ) + { + if ( loopback == UART_16550_LOOPBACK_OFF ) + { + HAL_set_8bit_reg_field( this_uart->base_address, + MCR_LOOP, + DISABLE ); + } + else + { + HAL_set_8bit_reg_field( this_uart->base_address, + MCR_LOOP, + ENABLE ); + } + } +} + +/***************************************************************************//** + * UART_16550_get_rx_status. + * See core_16550.h for details of how to use this function. + */ +uint8_t +UART_16550_get_rx_status +( + uart_16550_instance_t * this_uart +) +{ + uint8_t status = UART_16550_INVALID_PARAM; + HAL_ASSERT( this_uart != NULL_INSTANCE ); + + if( ( this_uart != NULL_INSTANCE ) ) + { + /* + * Bit 1 - Overflow error status + * Bit 2 - Parity error status + * Bit 3 - Frame error status + * Bit 4 - Break interrupt indicator + * Bit 7 - FIFO data error status + */ + this_uart->status |= HAL_get_8bit_reg( this_uart->base_address, LSR ); + status = ( this_uart->status & STATUS_ERROR_MASK ); + /* + * Clear the sticky status for this instance. + */ + this_uart->status = (uint8_t)0; + } + return status; +} + +/***************************************************************************//** + * UART_16550_get_modem_status. + * See core_16550.h for details of how to use this function. + */ +uint8_t +UART_16550_get_modem_status +( + uart_16550_instance_t * this_uart +) +{ + uint8_t status = UART_16550_NO_ERROR; + HAL_ASSERT( this_uart != NULL_INSTANCE ) + + if( ( this_uart != NULL_INSTANCE ) ) + { + /* + * Extract UART error status and place in lower bits of "status". + * Bit 0 - Delta Clear to Send Indicator + * Bit 1 - Delta Clear to Receive Indicator + * Bit 2 - Trailing edge of Ring Indicator detector + * Bit 3 - Delta Data Carrier Detect indicator + * Bit 4 - Clear To Send + * Bit 5 - Data Set Ready + * Bit 6 - Ring Indicator + * Bit 7 - Data Carrier Detect + */ + status = HAL_get_8bit_reg( this_uart->base_address, MSR ); + } + return status; +} + +/***************************************************************************//** + * Default TX interrupt handler to automatically transmit data from + * user assgined TX buffer. + */ +static void +default_tx_handler +( + uart_16550_instance_t * this_uart +) +{ + uint8_t status; + + HAL_ASSERT( NULL_INSTANCE != this_uart ) + + if ( this_uart != NULL_INSTANCE ) + { + HAL_ASSERT( NULL_BUFF != this_uart->tx_buffer ) + HAL_ASSERT( 0U != this_uart->tx_buff_size ) + + if ( ( this_uart->tx_buffer != NULL_BUFF ) && + ( 0U != this_uart->tx_buff_size ) ) + { + /* Read the Line Status Register and update the sticky record. */ + status = HAL_get_8bit_reg( this_uart->base_address,LSR); + this_uart->status |= status; + + /* + * This function should only be called as a result of a THRE interrupt. + * Verify that this is true before proceeding to transmit data. + */ + if ( status & LSR_THRE_MASK ) + { + uint32_t size_sent = 0U; + uint32_t fill_size = TX_FIFO_SIZE; + uint32_t tx_remain = this_uart->tx_buff_size - this_uart->tx_idx; + + /* Calculate the number of bytes to transmit. */ + if ( tx_remain < TX_FIFO_SIZE ) + { + fill_size = tx_remain; + } + + /* Fill the TX FIFO with the calculated the number of bytes. */ + for ( size_sent = 0U; size_sent < fill_size; ++size_sent ) + { + /* Send next character in the buffer. */ + HAL_set_8bit_reg( this_uart->base_address, THR, + (uint_fast8_t)this_uart->tx_buffer[this_uart->tx_idx]); + ++this_uart->tx_idx; + } + } + + /* Flag Tx as complete if all data has been pushed into the Tx FIFO. */ + if ( this_uart->tx_idx == this_uart->tx_buff_size ) + { + this_uart->tx_buff_size = TX_COMPLETE; + /* disables TX interrupt */ + HAL_set_8bit_reg_field( this_uart->base_address, + IER_ETBEI, DISABLE); + } + } + } +} + +/***************************************************************************//** + * UART_16550_enable_irq. + * See core_16550.h for details of how to use this function. + */ +void +UART_16550_enable_irq +( + uart_16550_instance_t * this_uart, + uint8_t irq_mask +) +{ + HAL_ASSERT( this_uart != NULL_INSTANCE ) + + if( this_uart != NULL_INSTANCE ) + { + /* irq_mask encoding: 1- enable + * bit 0 - Receive Data Available Interrupt + * bit 1 - Transmitter Holding Register Empty Interrupt + * bit 2 - Receiver Line Status Interrupt + * bit 3 - Modem Status Interrupt + */ + /* read present interrupts for enabled ones*/ + irq_mask |= HAL_get_8bit_reg( this_uart->base_address, IER ); + /* Enable interrupts */ + HAL_set_8bit_reg( this_uart->base_address, IER, irq_mask ); + } +} + +/***************************************************************************//** + * UART_16550_disable_irq. + * See core_16550.h for details of how to use this function. + */ +void +UART_16550_disable_irq +( + uart_16550_instance_t * this_uart, + uint8_t irq_mask +) +{ + HAL_ASSERT( this_uart != NULL_INSTANCE ) + + if( this_uart != NULL_INSTANCE ) + { + /* irq_mask encoding: 1 - disable + * bit 0 - Receive Data Available Interrupt + * bit 1 - Transmitter Holding Register Empty Interrupt + * bit 2 - Receiver Line Status Interrupt + * bit 3 - Modem Status Interrupt + */ + /* read present interrupts for enabled ones */ + irq_mask = (( (uint8_t)~irq_mask ) & + HAL_get_8bit_reg( this_uart->base_address, IER )); + /* Disable interrupts */ + HAL_set_8bit_reg( this_uart->base_address, IER, irq_mask ); + } +} + +/***************************************************************************//** + * UART_16550_set_rxstatus_handler. + * See core_16550.h for details of how to use this function. + */ +void +UART_16550_set_rxstatus_handler +( + uart_16550_instance_t * this_uart, + uart_16550_irq_handler_t handler +) +{ + HAL_ASSERT( this_uart != NULL_INSTANCE ) + HAL_ASSERT( handler != INVALID_IRQ_HANDLER) + + if( ( this_uart != NULL_INSTANCE ) && + ( handler != INVALID_IRQ_HANDLER) ) + { + this_uart->linests_handler = handler; + /* Enable receiver line status interrupt. */ + HAL_set_8bit_reg_field( this_uart->base_address, IER_ELSI, ENABLE ); + } +} + +/***************************************************************************//** + * UART_16550_set_tx_handler. + * See core_16550.h for details of how to use this function. + */ +void +UART_16550_set_tx_handler +( + uart_16550_instance_t * this_uart, + uart_16550_irq_handler_t handler +) +{ + HAL_ASSERT( this_uart != NULL_INSTANCE ) + HAL_ASSERT( handler != INVALID_IRQ_HANDLER) + + if( ( this_uart != NULL_INSTANCE ) && + ( handler != INVALID_IRQ_HANDLER) ) + { + this_uart->tx_handler = handler; + + /* Make TX buffer info invalid */ + this_uart->tx_buffer = NULL_BUFF; + this_uart->tx_buff_size = 0U; + + /* Enable transmitter holding register Empty interrupt. */ + HAL_set_8bit_reg_field( this_uart->base_address, IER_ETBEI, ENABLE ); + } +} + +/***************************************************************************//** + * UART_16550_set_modemstatus_handler. + * See core_16550.h for details of how to use this function. + */ +void +UART_16550_set_modemstatus_handler +( + uart_16550_instance_t * this_uart, + uart_16550_irq_handler_t handler +) +{ + HAL_ASSERT( this_uart != NULL_INSTANCE ) + HAL_ASSERT( handler != INVALID_IRQ_HANDLER) + + if( ( this_uart != NULL_INSTANCE ) && + ( handler != INVALID_IRQ_HANDLER) ) + { + this_uart->modemsts_handler = handler; + /* Enable modem status interrupt. */ + HAL_set_8bit_reg_field( this_uart->base_address, IER_EDSSI, ENABLE ); + } +} + +/***************************************************************************//** + * UART_16550_fill_tx_fifo. + * See core_16550.h for details of how to use this function. + */ +size_t +UART_16550_fill_tx_fifo +( + uart_16550_instance_t * this_uart, + const uint8_t * tx_buffer, + size_t tx_size +) +{ + uint8_t status; + size_t size_sent = 0U; + + HAL_ASSERT( this_uart != NULL_INSTANCE ) + HAL_ASSERT( tx_buffer != NULL_BUFF ) + HAL_ASSERT( tx_size > 0U ) + + /* Fill the UART's Tx FIFO until the FIFO is full or the complete input + * buffer has been written. */ + if( (this_uart != NULL_INSTANCE) && + (tx_buffer != NULL_BUFF) && + (tx_size > 0U) ) + { + /* Read the Line Status Register and update the sticky record. */ + status = HAL_get_8bit_reg( this_uart->base_address, LSR ); + this_uart->status |= status; + + /* Check if TX FIFO is empty. */ + if( status & LSR_THRE_MASK ) + { + uint32_t fill_size = TX_FIFO_SIZE; + + /* Calculate the number of bytes to transmit. */ + if ( tx_size < TX_FIFO_SIZE ) + { + fill_size = tx_size; + } + + /* Fill the TX FIFO with the calculated the number of bytes. */ + for ( size_sent = 0U; size_sent < fill_size; ++size_sent ) + { + /* Send next character in the buffer. */ + HAL_set_8bit_reg( this_uart->base_address, THR, + (uint_fast8_t)tx_buffer[size_sent]); + } + } + } + return size_sent; +} + +/***************************************************************************//** + * UART_16550_get_tx_status. + * See core_16550.h for details of how to use this function. + */ +uint8_t +UART_16550_get_tx_status +( + uart_16550_instance_t * this_uart +) +{ + uint8_t status = UART_16550_TX_BUSY; + HAL_ASSERT( this_uart != NULL_INSTANCE ); + + if( ( this_uart != NULL_INSTANCE ) ) + { + /* Read the Line Status Register and update the sticky record. */ + status = HAL_get_8bit_reg( this_uart->base_address, LSR ); + this_uart->status |= status; + /* + * Extract the transmit status bits from the UART's Line Status Register. + * Bit 5 - Transmitter Holding Register/FIFO Empty (THRE) status. (If = 1, TX FIFO is empty) + * Bit 6 - Transmitter Empty (TEMT) status. (If = 1, both TX FIFO and shift register are empty) + */ + status &= ( LSR_THRE_MASK | LSR_TEMT_MASK ); + } + return status; +} + + +#ifdef __cplusplus +} +#endif + + + + + + + + + + + + diff --git a/FreeRTOS/Demo/RISC-V_IGLOO2_Creative_SoftConsole/drivers/Core16550/core_16550.h b/FreeRTOS/Demo/RISC-V_IGLOO2_Creative_SoftConsole/drivers/Core16550/core_16550.h new file mode 100644 index 000000000..98b1f16ea --- /dev/null +++ b/FreeRTOS/Demo/RISC-V_IGLOO2_Creative_SoftConsole/drivers/Core16550/core_16550.h @@ -0,0 +1,1264 @@ +/******************************************************************************* + * (c) Copyright 2007-2015 Microsemi SoC Products Group. All rights reserved. + * + * This file contains the application programming interface for the Core16550 + * bare metal driver. + * + * SVN $Revision: 7963 $ + * SVN $Date: 2015-10-09 17:58:21 +0530 (Fri, 09 Oct 2015) $ + */ +/*=========================================================================*//** + @mainpage Core16550 Bare Metal Driver. + + @section intro_sec Introduction + The Core16550 is an implementation of the Universal Asynchronous + Receiver/Transmitter aimed at complete compliance to standard 16550 UART. + The Core16550 bare metal software driver is designed for use in systems + with no operating system. + + The Core16550 driver provides functions for polled and interrupt driven + transmitting and receiving. It also provides functions for reading the + values from different status registers, enabling and disabling interrupts + at Core16550 level. The Core16550 driver is provided as C source code. + + @section driver_configuration Driver Configuration + Your application software should configure the Core16550 driver through + calls to the UART_16550_init() function for each Core16550 instance in + the hardware design. The configuration parameters include the Core16550 + hardware instance base address and other runtime parameters, such as baud + value, bit width, and parity. + + No Core16550 hardware configuration parameters are needed by the driver, + apart from the Core16550 hardware instance base address. Hence, no + additional configuration files are required to use the driver. + + @section theory_op Theory of Operation + The Core16550 software driver is designed to allow the control of multiple + instances of Core16550. Each instance of Core16550 in the hardware design + is associated with a single instance of the uart_16550_instance_t structure + in the software. You need to allocate memory for one unique + uart_16550_instance_t structure instance for each Core16550 hardware instance. + The contents of these data structures are initialized during calls to + function UART_16550_init(). A pointer to the structure is passed to + subsequent driver functions in order to identify the Core16550 hardware + instance you wish to perform the requested operation on. + + Note: Do not attempt to directly manipulate the content of + uart_16550_instance_t structures. This structure is only intended to be + modified by the driver function. + + Initialization + The Core16550 driver is initialized through a call to the UART_16550_init() + function. This function takes the UART’s configuration as parameters. + The UART_16550_init() function must be called before any other Core16550 + driver functions can be called. + + Polled Transmission and Reception + The driver can be used to transmit and receive data once initialized. Polled + operations where the driver constantly polls the state of the UART registers + in order to control data transmit or data receive are performed using these + functions: + • UART_16550_polled_tx() + • UART_16550_polled_tx_string + • UART_16550_fill_tx_fifo() + • UART_16550_get_rx() + + Data is transmitted using the UART_16550_polled_tx() function. This function + is blocking, meaning that it will only return once the data passed to the + function has been sent to the Core16550 hardware. Data received by the + Core16550 hardware can be read by the UART_16550_get_rx() function. + + The UART_16550_polled_tx_string() function is provided to transmit a NULL (‘\0’) + terminated string in polled mode. This function is blocking, meaning that it + will only return once the data passed to the function has been sent to the + Core16550 hardware. + + The UART_16550_fill_tx_fifo() function fills the Core16550 hardware transmit + FIFO with data from a buffer passed as a parameter and returns the number of + bytes transferred to the FIFO. If the transmit FIFO is not empty when the + UART_16550_fill_tx_fifo() function is called it returns immediately without + transferring any data to the FIFO. + + Interrupt Driven Operations + The driver can also transmit or receive data under interrupt control, freeing + your application to perform other tasks until an interrupt occurs indicating + that the driver’s attention is required. Interrupt controlled UART operations + are performed using these functions: + • UART_16550_isr() + • UART_16550_irq_tx() + • UART_16550_tx_complete() + • UART_16550_set_tx_handler() + • UART_16550_set_rx_handler() + • UART_16550_set_rxstatus_handler() + • UART_16550_set_modemstatus_handler() + • UART_16550_enable_irq() + • UART_16550_disable_irq() + + Interrupt Handlers + The UART_16550_isr() function is the top level interrupt handler function for + the Core16550 driver. You must call it from the system level + (CoreInterrupt and NVIC level) interrupt service routine (ISR) assigned to the + interrupt triggered by the Core16550 INTR signal. The UART_16550_isr() function + identifies the source of the Core16550 interrupt and calls the corresponding + handler function previously registered with the driver through calls to the + UART_16550_set_rx_handler(), UART_16550_set_tx_handler(), + UART_16550_set_rxstatus_handler(), and UART_16550_set_modemstatus_handler() + functions. You are responsible for creating these lower level interrupt handlers + as part of your application program and registering them with the driver. + The UART_16550_enable_irq() and UART_16550_disable_irq() functions are used to + enable or disable the received line status, received data available/character + timeout, transmit holding register empty and modem status interrupts at the + Core16550 level. + + Transmitting Data + Interrupt-driven transmit is initiated by a call to UART_16550_irq_tx(), + specifying the block of data to transmit. Your application is then free to + perform other tasks and inquire later whether transmit has completed by calling + the UART_16550_tx_complete() function. The UART_16550_irq_tx() function enables + the UART’s transmit holding register empty (THRE) interrupt and then, when the + interrupt goes active, the driver’s default THRE interrupt handler transfers + the data block to the UART until the entire block is transmitted. + + Note: You can use the UART_16550_set_tx_handler() function to assign an + alternative handler to the THRE interrupt. In this case, you must not use the + UART_16550_irq_tx() function to initiate the transmit, as this will re-assign + the driver’s default THRE interrupt handler to the THRE interrupt. Instead, + your alternative THRE interrupt handler must include a call to the + UART_16550_fill_tx_fifo() function to transfer the data to the UART. + + Receiving Data + Interrupt-driven receive is performed by first calling UART_16550_set_rx_handler() + to register a receive handler function that will be called by the driver whenever + receive data is available. You must provide this receive handler function which + must include a call to the UART_16550_get_rx() function to actually read the + received data. + + UART Status + The function UART_16550_get_rx_status() is used to read the receiver error status. + This function returns the overrun, parity, framing, break, and FIFO error status + of the receiver. + The function UART_16550_get_tx_status() is used to read the transmitter status. + This function returns the transmit empty (TEMT) and transmit holding register + empty (THRE) status of the transmitter. + The function UART_16550_get_modem_status() is used to read the modem status flags. + This function returns the current value of the modem status register. + + Loopback + The function UART_16550_set_loopback() is used to enable or disable loopback + between Tx and Rx lines internal to Core16550. +*//*=========================================================================*/ +#ifndef __CORE_16550_H +#define __CORE_16550_H 1 + +#include "cpu_types.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/***************************************************************************//** + * Receiver Error Status + * The following defines are used to determine the UART receiver error type. + * These bit mask constants are used with the return value of the + * UART_16550_get_rx_status() function to find out if any errors occurred + * while receiving data. + */ +#define UART_16550_NO_ERROR ( (uint8_t) 0x00 ) +#define UART_16550_OVERRUN_ERROR ( (uint8_t) 0x02 ) +#define UART_16550_PARITY_ERROR ( (uint8_t) 0x04 ) +#define UART_16550_FRAMING_ERROR ( (uint8_t) 0x08 ) +#define UART_16550_BREAK_ERROR ( (uint8_t) 0x10 ) +#define UART_16550_FIFO_ERROR ( (uint8_t) 0x80 ) +#define UART_16550_INVALID_PARAM ( (uint8_t) 0xFF ) + +/***************************************************************************//** + * Modem Status + * The following defines are used to determine the modem status. These bit + * mask constants are used with the return value of the + * UART_16550_get_modem_status() function to find out the modem status of + * the UART. + */ +#define UART_16550_DCTS ( (uint8_t) 0x01 ) +#define UART_16550_DDSR ( (uint8_t) 0x02 ) +#define UART_16550_TERI ( (uint8_t) 0x04 ) +#define UART_16550_DDCD ( (uint8_t) 0x08 ) +#define UART_16550_CTS ( (uint8_t) 0x10 ) +#define UART_16550_DSR ( (uint8_t) 0x20 ) +#define UART_16550_RI ( (uint8_t) 0x40 ) +#define UART_16550_DCD ( (uint8_t) 0x80 ) + +/***************************************************************************//** + * Transmitter Status + * The following definitions are used to determine the UART transmitter status. + * These bit mask constants are used with the return value of the + * UART_16550_get_tx_status() function to find out the status of the + * transmitter. + */ +#define UART_16550_TX_BUSY ( (uint8_t) 0x00 ) +#define UART_16550_THRE ( (uint8_t) 0x20 ) +#define UART_16550_TEMT ( (uint8_t) 0x40 ) + +/***************************************************************************//** + * Core16550 Interrupts + * The following defines are used to enable and disable Core16550 interrupts. + * They are used to build the value of the irq_mask parameter for the + * UART_16550_enable_irq() and UART_16550_disable_irq() functions. A bitwise + * OR of these constants is used to enable or disable multiple interrupts. + */ +#define UART_16550_RBF_IRQ ( (uint8_t) 0x01 ) +#define UART_16550_TBE_IRQ ( (uint8_t) 0x02 ) +#define UART_16550_LS_IRQ ( (uint8_t) 0x04 ) +#define UART_16550_MS_IRQ ( (uint8_t) 0x08 ) + +/***************************************************************************//** + * Data Width + * The following defines are used to build the value of the UART_16550_init() + * function line_config parameter. + */ +#define UART_16550_DATA_5_BITS ( (uint8_t) 0x00 ) +#define UART_16550_DATA_6_BITS ( (uint8_t) 0x01 ) +#define UART_16550_DATA_7_BITS ( (uint8_t) 0x02 ) +#define UART_16550_DATA_8_BITS ( (uint8_t) 0x03 ) + +/***************************************************************************//** + * Parity Control + * The following defines are used to build the value of the UART_16550_init() + * function line_config parameter. + */ +#define UART_16550_NO_PARITY ( (uint8_t) 0x00 ) +#define UART_16550_ODD_PARITY ( (uint8_t) 0x08 ) +#define UART_16550_EVEN_PARITY ( (uint8_t) 0x18 ) +#define UART_16550_STICK_PARITY_1 ( (uint8_t) 0x28 ) +#define UART_16550_STICK_PARITY_0 ( (uint8_t) 0x38 ) + +/***************************************************************************//** + * Number of Stop Bits + * The following defines are used to build the value of the UART_16550_init() + * function line_config parameter. + */ +#define UART_16550_ONE_STOP_BIT ( (uint8_t) 0x00 ) +/*only when data bits is 5*/ +#define UART_16550_ONEHALF_STOP_BIT ( (uint8_t) 0x04 ) +/*only when data bits is not 5*/ +#define UART_16550_TWO_STOP_BITS ( (uint8_t) 0x04 ) + +/***************************************************************************//** + This enumeration specifies the receiver FIFO trigger level. This is the number + of bytes that must be received before the UART generates a receive data + available interrupt. It provides the allowed values for the + UART_16550_set_rx_handler() function’s trigger_level parameter. + */ +typedef enum { + UART_16550_FIFO_SINGLE_BYTE = 0, + UART_16550_FIFO_FOUR_BYTES = 1, + UART_16550_FIFO_EIGHT_BYTES = 2, + UART_16550_FIFO_FOURTEEN_BYTES = 3, + UART_16550_FIFO_INVALID_TRIG_LEVEL +} uart_16550_rx_trig_level_t; + +/***************************************************************************//** + This enumeration specifies the Loopback configuration of the UART. It provides + the allowed values for the UART_16550_set_loopback() function’s loopback + parameter. + */ +typedef enum { + UART_16550_LOOPBACK_OFF = 0, + UART_16550_LOOPBACK_ON = 1, + UART_16550_INVALID_LOOPBACK +} uart_16550_loopback_t; + +/***************************************************************************//** + This is type definition for Core16550 instance. You need to create and + maintain a record of this type. This holds all data regarding the Core16550 + instance. + */ +typedef struct uart_16550_instance uart_16550_instance_t; + +/***************************************************************************//** + This typedef specifies the function prototype for Core16550 interrupt handlers. + All interrupt handlers registered with the Core16550 driver must be of this + type. The interrupt handlers are registered with the driver through the + UART_16550_set_rx_handler(), UART_16550_set_tx_handler(), + UART_16550_set_rxstatus_handler(), and UART_16550_set_modemstatus_handler() + functions. + + The this_uart parameter is a pointer to a uart_16550_instance_t structure that + holds all data regarding this instance of the Core16550. + */ +typedef void (*uart_16550_irq_handler_t)(uart_16550_instance_t * this_uart); + +/***************************************************************************//** + uart_16550_instance. + This structure is used to identify the various Core16550 hardware instances + in your system. Your application software should declare one instance of this + structure for each instance of Core16550 in your system. The function + UART_16550_init() initializes this structure. A pointer to an initialized + instance of the structure should be passed as the first parameter to the + Core16550 driver functions, to identify which Core16550 hardware instance + should perform the requested operation. + */ +struct uart_16550_instance{ + /* Core16550 instance base address: */ + addr_t base_address; + /* Accumulated status: */ + uint8_t status; + + /* transmit related info: */ + const uint8_t* tx_buffer; + uint32_t tx_buff_size; + uint32_t tx_idx; + + /* line status (OE, PE, FE & BI) interrupt handler:*/ + uart_16550_irq_handler_t linests_handler; + /* receive interrupt handler:*/ + uart_16550_irq_handler_t rx_handler; + /* transmitter holding register interrupt handler:*/ + uart_16550_irq_handler_t tx_handler; + /* modem status interrupt handler:*/ + uart_16550_irq_handler_t modemsts_handler; +}; + +/***************************************************************************//** + * The UART_16550_init() function initializes the driver’s data structures and + * the Core16550 hardware with the configuration passed as parameters.. The + * configuration parameters are the baud_value used to generate the baud rate, + * and the line_config used to specify the line configuration (bit length, + * stop bits and parity). + * + * @param this_uart The this_uart parameter is a pointer to a + * uart_16550_instance_t structure that holds all data + * regarding this instance of the Core16550. This pointer + * is used to identify the target Core16550 hardware + * instance in subsequent calls to the Core16550 driver + * functions. + * @param base_addr The base_address parameter is the base address in the + * processor's memory map for the registers of the + * Core16550 instance being initialized. + * @param baud_value The baud_value parameter is used to select the baud rate + * for the UART. The baud value is calculated from the + * frequency of the system clock in Hertz and the desired + * baud rate using the following equation: + * + * baud_value = (clock /(baud_rate * 16)) + * + * The baud_value parameter must be a value in the range 0 + * to 65535 (or 0x0000 to 0xFFFF). + * @param line_config This parameter is the line configuration specifying the + * bit length, number of stop bits and parity settings. This + * is a bitwise OR of one value from each of the following + * groups of allowed values: + * • Data lengths: + * UART_16550_DATA_5_BITS + * UART_16550_DATA_6_BITS + * UART_16550_DATA_7_BITS + * UART_16550_DATA_8_BITS + * • Parity types: + * UART_16550_NO_PARITY + * UART_16550_EVEN_PARITY + * UART_16550_ODD_PARITY + * UART_16550_STICK_PARITY_0 + * UART_16550_STICK_PARITY_1 + * • Number of stop bits: + * UART_16550_ONE_STOP_BIT + * UART_16550_ONEHALF_STOP_BIT + * UART_16550_TWO_STOP_BITS + * @return This function does not return a value. + * + * Example: + * @code + * #define UART_16550_BASE_ADDR 0x2A000000 + * #define BAUD_VALUE_57600 26 + * + * uart_16550_instance_t g_uart; + * + * UART_16550_init( &g_uart, UART_16550_BASE_ADDR, BAUD_VALUE_57600, + * (UART_16550_DATA_8_BITS | + * UART_16550_EVEN_PARITY | + * UART_16550_ONE_STOP_BIT) ); + * @endcode + */ +void +UART_16550_init +( + uart_16550_instance_t* this_uart, + addr_t base_addr, + uint16_t baud_value, + uint8_t line_config +); + +/***************************************************************************//** + * The UART_16550_polled_tx() function is used to transmit data. It transfers + * the contents of the transmitter data buffer, passed as a function parameter, + * into the UART's hardware transmitter FIFO. It returns when the full content + * of the transmitter data buffer has been transferred to the UART's transmitter + * FIFO. It is safe to release or reuse the memory used as the transmitter data + * buffer once this function returns. + * + * Note: This function reads the UART’s line status register (LSR) to poll + * for the active state of the transmitter holding register empty (THRE) bit + * before transferring data from the data buffer to the transmitter FIFO. It + * transfers data to the transmitter FIFO in blocks of 16 bytes or less and + * allows the FIFO to empty before transferring the next block of data. + * + * Note: The actual transmission over the serial connection will still be in + * progress when this function returns. Use the UART_16550_get_tx_status() + * function if you need to know when the transmitter is empty. + * + * @param this_uart The this_uart parameter is a pointer to a + * uart_16550_instance_t structure that holds all + * data regarding this instance of the Core16550. + * @param pbuff The pbuff parameter is a pointer to a buffer containing + * the data to be transmitted. + * @param tx_size The tx_size parameter is the size, in bytes, of the + * data to be transmitted. + * @return This function does not return a value. + * + * Example: + * @code + * uint8_t testmsg1[] = {"\n\r\n\r\n\rUART_16550_polled_tx() test message 1"}; + * UART_16550_polled_tx(&g_uart,(const uint8_t *)testmsg1,sizeof(testmsg1)); + * @endcode + */ +void +UART_16550_polled_tx +( + uart_16550_instance_t * this_uart, + const uint8_t * pbuff, + uint32_t tx_size +); +/***************************************************************************//** + * The UART_16550_polled_tx_string() function is used to transmit a NULL ('\0') + * terminated string. It transfers the text string, from the buffer starting at + * the address pointed to by p_sz_string, into the UART’s hardware transmitter + * FIFO. It returns when the complete string has been transferred to the UART's + * transmit FIFO. It is safe to release or reuse the memory used as the string + * buffer once this function returns. + * + * Note: This function reads the UART’s line status register (LSR) to poll + * for the active state of the transmitter holding register empty (THRE) bit + * before transferring data from the data buffer to the transmitter FIFO. It + * transfers data to the transmitter FIFO in blocks of 16 bytes or less and + * allows the FIFO to empty before transferring the next block of data. + * + * Note: The actual transmission over the serial connection will still be + * in progress when this function returns. Use the UART_16550_get_tx_status() + * function if you need to know when the transmitter is empty. + * + * @param this_uart The this_uart parameter is a pointer to a + * uart_16550_instance_t structure that holds all data + * regarding this instance of the Core16550. + * @param p_sz_string The p_sz_string parameter is a pointer to a buffer + * containing the NULL ('\0') terminated string to be + * transmitted. + * @return This function does not return a value. + * + * Example: + * @code + * uint8_t testmsg1[] = {"\r\n\r\nUART_16550_polled_tx_string() test message 1\0"}; + * UART_16550_polled_tx_string(&g_uart,(const uint8_t *)testmsg1); + * @endcode + */ +void +UART_16550_polled_tx_string +( + uart_16550_instance_t * this_uart, + const uint8_t * p_sz_string +); + +/***************************************************************************//** + * The UART_16550_irq_tx() function is used to initiate an interrupt driven + * transmit. It returns immediately after making a note of the transmit buffer + * location and enabling the transmitter holding register empty (THRE) interrupt + * at the Core16550 level. This function takes a pointer via the pbuff parameter + * to a memory buffer containing the data to transmit. The memory buffer + * specified through this pointer must remain allocated and contain the data to + * transmit until the transmit completion has been detected through calls to + * function UART_16550_tx_complete().The actual transmission over the serial + * connection is still in progress until calls to the UART_16550_tx_complete() + * function indicate transmit completion. + * + * Note: It is your responsibility to call UART_16550_isr(), the driver’s + * top level interrupt handler function, from the system level (CoreInterrupt + * and NVIC level) interrupt handler assigned to the interrupt triggered by the + * Core16550 INTR signal. You must do this before using the UART_16550_irq_tx() + * function. + * + * Note: It is also your responsibility to enable the system level + * (CoreInterrupt and NVIC level) interrupt connected to the Core16550 INTR + * interrupt signal. + * + * Note: The UART_16550_irq_tx() function assigns an internal default transmit + * interrupt handler function to the UART’s THRE interrupt. This interrupt handler + * overrides any custom interrupt handler that you may have previously registered + * using the UART_16550_set_tx_handler() function. + * + * Note: The UART_16550_irq_tx() function’s default transmit interrupt handler + * disables the UART’s THRE interrupt when all of the data has been transferred + * to the UART's transmit FIFO. + * + * @param this_uart The this_uart parameter is a pointer to a + * uart_16550_instance_t structure that holds all data + * regarding this instance of the Core16550. + * @param pbuff The pbuff parameter is a pointer to a buffer containing + * the data to be transmitted. + * @param tx_size The tx_size parameter specifies the size, in bytes, of + * the data to be transmitted. + * @return This function does not return a value. + * + * Example: + * @code + * uint8_t tx_buff[10] = "abcdefghi"; + * + * UART_16550_irq_tx( &g_uart, tx_buff, sizeof(tx_buff)); + * while ( 0 == UART_16550_tx_complete( &g_uart ) ) + * { ; } + * @endcode + */ +void +UART_16550_irq_tx +( + uart_16550_instance_t * this_uart, + const uint8_t * pbuff, + uint32_t tx_size +); + +/***************************************************************************//** + * The UART_16550_tx_complete() function is used to find out if the interrupt + * driven transmit previously initiated through a call to UART_16550_irq_tx() + * is complete. This function is typically used to find out when it is safe + * to reuse or release the memory buffer holding the transmit data. + * + * Note: The transfer of all of the data from the memory buffer to the UART’s + * transmit FIFO and the actual transmission over the serial connection are both + * complete when a call to the UART_16550_tx_complete() function indicate + * transmit completion. + * + * @param this_uart The this_uart parameter is a pointer to a + * uart_16550_instance_t structure that holds all data + * regarding this instance of the Core16550. + * @return This function returns a non-zero value if transmit has + * completed, otherwise it returns zero. + * Example: + * See the UART_16550_irq_tx() function for an example that uses the + * UART_16550_tx_complete() function. + */ +int8_t +UART_16550_tx_complete +( + uart_16550_instance_t * this_uart +); + +/***************************************************************************//** + * The UART_16550_get_rx() function reads the content of the Core16550 + * receiver’s FIFO and stores it in the receive buffer that is passed via the + * rx_buff function parameter. It copies either the full contents of the FIFO + * into the receive buffer, or just enough data from the FIFO to fill the receive + * buffer, dependent upon the size of the receive buffer passed by the buff_size + * parameter. The UART_16550_get_rx() function returns the number of bytes copied + * into the receive buffer .This function is non-blocking and will return 0 + * immediately if no data has been received. + * + * Note: The UART_16550_get_rx() function reads and accumulates the receiver + * status of the Core16550 instance before reading each byte from the receiver's + * data register/FIFO. This allows the driver to maintain a sticky record of any + * receiver errors that occur as the UART receives each data byte; receiver errors + * would otherwise be lost after each read from the receiver's data register. A call + * to the UART_16550_get_rx_status() function returns any receiver errors accumulated + * during the execution of the UART_16550_get_rx() function. + * + * Note: If you need to read the error status for each byte received, set the + * buff_size to 1 and read the receive line error status for each byte using the + * UART_16550_get_rx_status() function. + * The UART_16550_get_rx() function can be used in polled mode, where it is called + * at regular intervals to find out if any data has been received, or in interrupt + * driven-mode, where it is called as part of a receive handler that is called by + * the driver as a result of data being received. + * + * Note: In interrupt driven mode you should call the UART_16550_get_rx() + * function as part of the receive handler function that you register with the + * Core16550 driver through a call to UART_16550_set_rx_handler(). + * + * @param this_uart The this_uart parameter is a pointer to a + * uart_16550_instance_t structure that holds all data + * regarding this instance of the Core16550. + * @param rx_buff The rx_buff parameter is a pointer to a memory buffer + * where the received data is copied. + * @param buff_size The buff_size parameter is the size of the receive + * buffer in bytes. + * @return This function returns the number of bytes copied into + * the receive buffer. + * Example: + * @code + * #define MAX_RX_DATA_SIZE 256 + * + * uint8_t rx_data[MAX_RX_DATA_SIZE]; + * uint8_t rx_size = 0; + * + * rx_size = UART_16550_get_rx( &g_uart, rx_data, sizeof(rx_data) ); + * @endcode + */ +size_t +UART_16550_get_rx +( + uart_16550_instance_t * this_uart, + uint8_t * rx_buff, + size_t buff_size +); + +/***************************************************************************//** + * The UART_16550_isr() function is the top level interrupt handler function for + * the Core16550 driver. You must call UART_16550_isr() from the system level + * (CoreInterrupt and NVIC level) interrupt handler assigned to the interrupt + * triggered by the Core16550 INTR signal. Your system level interrupt handler + * must also clear the system level interrupt triggered by the Core16550 INTR + * signal before returning, to prevent a re-assertion of the same interrupt. + * + * Note: This function supports all types of interrupt triggered by Core16550. + * It is not a complete interrupt handler by itself; rather, it is a top level + * wrapper that abstracts Core16550 interrupt handling by calling lower level + * handler functions specific to each type of Core16550 interrupt. You must + * create the lower level handler functions to suit your application and + * register them with the driver through calls to the UART_16550_set_rx_handler(), + * UART_16550_set_tx_handler(), UART_16550_set_rxstatus_handler() and + * UART_16550_set_modemstatus_handler() functions. + * + * @param this_uart The this_uart parameter is a pointer to a + * uart_16550_instance_t structure that holds all data + * regarding this instance of the Core16550. + * + * @return This function does not return a value. + * + * Example: + * @code + * void CIC_irq1_handler(void) + * { + * UART_16550_isr( &g_uart ); + * } + * @endcode + */ +void +UART_16550_isr +( + uart_16550_instance_t * this_uart +); + +/***************************************************************************//** + * The UART_16550_set_rx_handler() function is used to register a receive handler + * function that is called by the driver when a UART receive data available (RDA) + * interrupt occurs. The UART_16550_set_rx_handler() function also enables the + * RDA interrupt at the Core16550 level. You must create and register the receive + * handler function to suit your application and it must include a call to the + * UART_16550_get_rx() function to actually read the received data. + * + * Note: The driver’s top level interrupt handler function UART_16550_isr() + * will call your receive handler function in response to an RDA interrupt from + * the Core16550. + * + * Note: You can disable the RDA interrupt once the data is received by calling + * the UART_16550_disable_irq() function. This is your choice and is dependent + * upon your application. + * + * @param this_uart The this_uart parameter is a pointer to a + * uart_16550_instance_t structure that holds all data + * regarding this instance of the Core16550. + * @param handler The handler parameter is a pointer to a receive interrupt + * handler function provided by your application that will be + * called as a result of a UART RDA interrupt. This handler + * function must be of type uart_16550_irq_handler_t. + * @param trigger_level The trigger_level parameter is the receive FIFO + * trigger level. This specifies the number of bytes that + * must be received before the UART triggers an RDA + * interrupt. + * @return This function does not return a value. + * + * Example: + * @code + * #include "core_16550.h" + * + * #define RX_BUFF_SIZE 64 + * #define UART_57600_BAUD 26 + * + * uint8_t g_rx_buff[RX_BUFF_SIZE]; + * uart_16550_instance_t g_uart; + * void uart_rx_handler( uart_16550_instance_t * this_uart ) + * { + * UART_16550_get_rx( this_uart, g_rx_buff, RX_BUFF_SIZE ); + * } + * + * int main(void) + * { + * UART_16550_init( &g_uart, UART_57600_BAUD, + * ( UART_16550_DATA_8_BITS | UART_16550_NO_PARITY ) ); + * UART_16550_set_rx_handler( &g_uart, uart_rx_handler, + * UART_16550_FIFO_SINGLE_BYTE); + * while ( 1 ) + * { + * ; + * } + * return(0); + * } + * @endcode + */ +void +UART_16550_set_rx_handler +( + uart_16550_instance_t * this_uart, + uart_16550_irq_handler_t handler, + uart_16550_rx_trig_level_t trigger_level +); + +/***************************************************************************//** + * The UART_16550_set_loopback() function is used to locally loopback the Tx + * and Rx lines of a Core16550 UART. + * + * @param this_uart The this_uart parameter is a pointer to a + * uart_16550_instance_t structure that holds all data + * regarding this instance of the Core16550. + * @param loopback The loopback parameter indicates whether or not the + * UART's transmit and receive lines should be looped back. + * Allowed values are as follows: + * • UART_16550_LOOPBACK_ON + * • UART_16550_LOOPBACK_OFF + * @return This function does not return a value. + * + * Example: + * @code + * #include "core_16550.h" + * + * #define UART_57600_BAUD 26 + * #define DATA_SIZE 4 + * + * uart_16550_instance_t g_uart; + * + * int main(void) + * { + * uint8_t txbuf[DATA_SIZE] = "abc"; + * uint8_t rxbuf[DATA_SIZE]; + * UART_16550_init( &g_uart, UART_57600_BAUD, + * ( UART_16550_DATA_8_BITS | UART_16550_NO_PARITY | + * UART_16550_ONE_STOP_BIT) ); + * UART_16550_set_loopback( &g_uart, UART_16550_LOOPBACK_ON ); + * + * while(1) + * { + * UART_16550_polled_tx( &g_uart, txbuf, DATA_SIZE); + * delay(100); + * UART_16550_get_rx( &g_uart, rxbuf, DATA_SIZE); + * } + * } + * @endcode + */ +void +UART_16550_set_loopback +( + uart_16550_instance_t * this_uart, + uart_16550_loopback_t loopback +); + +/***************************************************************************//** + * The UART_16550_get_rx_status() function returns the receiver error status of + * the Core16550 instance. It reads both the current error status of the receiver + * from the UART’s line status register (LSR) and the accumulated error status + * from preceding calls to the UART_16550_get_rx() function, and it combines + * them using a bitwise OR. It returns the cumulative overrun, parity, framing, + * break and FIFO error status of the receiver, since the previous call to + * UART_16550_get_rx_status(), as an 8-bit encoded value. + * + * Note: The UART_16550_get_rx() function reads and accumulates the receiver + * status of the Core16550 instance before reading each byte from the receiver’s + * data register/FIFO. The driver maintains a sticky record of the cumulative + * receiver error status, which persists after the UART_16550_get_rx() function + * returns. The UART_16550_get_rx_status() function clears the driver’s sticky + * receiver error record before returning. + * + * Note: The driver’s transmit functions also read the line status register + * (LSR) as part of their implementation. When the driver reads the LSR, the + * UART clears any active receiver error bits in the LSR. This could result in + * the driver losing receiver errors. To avoid any loss of receiver errors, the + * transmit functions also update the driver’s sticky record of the cumulative + * receiver error status whenever they read the LSR. + * + * @param this_uart The this_uart parameter is a pointer to a + * uart_16550_instance_t structure that holds all data + * regarding this instance of the Core16550. + * @return This function returns the UART’s receiver error status + * as an 8-bit unsigned integer. The returned value is 0 + * if no receiver errors occurred. The driver provides a + * set of bit mask constants that should be compared with + * and/or used to mask the returned value to determine the + * receiver error status. + * When the return value is compared to the following bit + * masks, a non-zero result indicates that the + * corresponding error occurred: + * • UART_16550_OVERRUN_ERROR (bit mask = 0x02) + * • UART_16550_PARITY_ERROR (bit mask = 0x04) + * • UART_16550_FRAMING_ERROR (bit mask = 0x08) + * • UART_16550_BREAK_ERROR (bit mask = 0x10) + * • UART_16550_FIFO_ERROR (bit mask = 0x80) + * When the return value is compared to the following bit + * mask, a non-zero result indicates that no error occurred: + * • UART_16550_NO_ERROR (bit mask = 0x00) + * Upon unsuccessful execution, this function returns: + * • UART_16550_INVALID_PARAM (bit mask = 0xFF) + * + * Example: + * @code + * uart_16550_instance_t g_uart; + * uint8_t rx_data[MAX_RX_DATA_SIZE]; + * uint8_t err_status; + * + * err_status = UART_16550_get_rx_status(&g_uart); + * if(UART_16550_NO_ERROR == err_status ) + * { + * rx_size = UART_16550_get_rx( &g_uart, rx_data, MAX_RX_DATA_SIZE ); + * } + * @endcode + */ +uint8_t +UART_16550_get_rx_status +( + uart_16550_instance_t * this_uart +); +/***************************************************************************//** + * The UART_16550_enable_irq() function enables the Core16550 interrupts + * specified by the irq_mask parameter. The irq_mask parameter identifies the + * Core16550 interrupts by bit position, as defined in the interrupt enable + * register (IER) of Core16550. The Core16550 interrupts and their identifying + * irq_mask bit positions are as follows: + * • Receive data available interrupt (RDA) (irq_mask bit 0) + * • Transmit holding register empty interrupt (THRE) (irq_mask bit 1) + * • Receiver line status interrupt (LS) (irq_mask bit 2) + * • Modem status interrupt (MS) (irq_mask bit 3) + * When an irq_mask bit position is set to 1, this function enables the + * corresponding Core16550 interrupt in the IER register. When an irq_mask + * bit position is set to 0, the corresponding interrupt’s state remains + * unchanged in the IER register. + * + * @param this_uart The this_uart parameter is a pointer to a + * uart_16550_instance_t structure that holds all data + * regarding this instance of the Core16550. + * @param irq_mask The irq_mask parameter is used to select which of the + * Core16550’s interrupts you want to enable. The allowed + * value for the irq_mask parameter is one of the + * following constants or a bitwise OR of more than one: + * • UART_16550_RBF_IRQ (bit mask = 0x01) + * • UART_16550_TBE_IRQ (bit mask = 0x02) + * • UART_16550_LS_IRQ (bit mask = 0x04) + * • UART_16550_MS_IRQ (bit mask = 0x08) + * @return This function does not return a value. + * + * Example: + * @code + * UART_16550_enable_irq( &g_uart,( UART_16550_RBF_IRQ | UART_16550_TBE_IRQ ) ); + * @endcode + */ +void +UART_16550_enable_irq +( + uart_16550_instance_t * this_uart, + uint8_t irq_mask +); + +/***************************************************************************//** + * The UART_16550_disable_irq() function disables the Core16550 interrupts + * specified by the irq_mask parameter. The irq_mask parameter identifies the + * Core16550 interrupts by bit position, as defined in the interrupt enable + * register (IER) of Core16550. The Core16550 interrupts and their identifying + * bit positions are as follows: + * • Receive data available interrupt (RDA) (irq_mask bit 0) + * • Transmit holding register empty interrupt (THRE) (irq_mask bit 1) + * • Receiver line status interrupt (LS) (irq_mask bit 2) + * • Modem status interrupt (MS) (irq_mask bit 3) + * When an irq_mask bit position is set to 1, this function disables the + * corresponding Core16550 interrupt in the IER register. When an irq_mask bit + * position is set to 0, the corresponding interrupt’s state remains unchanged + * in the IER register. + * + * @param this_uart The this_uart parameter is a pointer to a + * uart_16550_instance_t structure that holds all data + * regarding this instance of the Core16550. + * @param irq_mask The irq_mask parameter is used to select which of the + * Core16550’s interrupts you want to disable. The allowed + * value for the irq_mask parameter is one of the + * following constants or a bitwise OR of more than one: + * • UART_16550_RBF_IRQ (bit mask = 0x01) + * • UART_16550_TBE_IRQ (bit mask = 0x02) + * • UART_16550_LS_IRQ (bit mask = 0x04) + * • UART_16550_MS_IRQ (bit mask = 0x08) + * @return This function does not return a value. + * + * Example: + * @code + * UART_16550_disable_irq( &g_uart, ( UART_16550_RBF_IRQ | UART_16550_TBE_IRQ ) ); + * @endcode + */ +void +UART_16550_disable_irq +( + uart_16550_instance_t * this_uart, + uint8_t irq_mask +); + +/***************************************************************************//** + * The UART_16550_get_modem_status() function returns the modem status of the + * Core16550 instance. It reads the modem status register (MSR) and returns the + * 8 bit value. The bit encoding of the returned value is exactly the same as + * the definition of the bits in the MSR. + * + * @param this_uart The this_uart parameter is a pointer to a + * uart_16550_instance_t structure that holds all data + * regarding this instance of the Core16550. + * @return This function returns current state of the UART's MSR + * as an 8 bit unsigned integer. The driver provides the + * following set of bit mask constants that should be + * compared with and/or used to mask the returned value + * to determine the modem status: + * • UART_16550_DCTS (bit mask = 0x01) + * • UART_16550_DDSR (bit mask = 0x02) + * • UART_16550_TERI (bit mask = 0x04) + * • UART_16550_DDCD (bit mask = 0x08) + * • UART_16550_CTS (bit mask = 0x10) + * • UART_16550_DSR (bit mask = 0x20) + * • UART_16550_RI (bit mask = 0x40) + * • UART_16550_DCD (bit mask = 0x80) + * Example: + * @code + * void uart_modem_status_isr(uart_16550_instance_t * this_uart) + * { + * uint8_t status; + * status = UART_16550_get_modem_status( this_uart ); + * if( status & UART_16550_DCTS ) + * { + * uart_dcts_handler(); + * } + * if( status & UART_16550_CTS ) + * { + * uart_cts_handler(); + * } + * } + * @endcode + */ +uint8_t +UART_16550_get_modem_status +( + uart_16550_instance_t * this_uart +); + +/***************************************************************************//** + * The UART_16550_set_rxstatus_handler() function is used to register a receiver + * status handler function that is called by the driver when a UART receiver + * line status (RLS) interrupt occurs. The UART_16550_set_rxstatus_handler() + * function also enables the RLS interrupt at the Core16550 level. You must + * create and register the receiver status handler function to suit your + * application. + * + * Note: The driver’s top level interrupt handler function UART_16550_isr() + * will call your receive status handler function in response to an RLS + * interrupt from the Core16550. + * + * Note: You can disable the RLS interrupt when required by calling the + * UART_16550_disable_irq() function. This is your choice and is dependent + * upon your application. + * + * @param this_uart The this_uart parameter is a pointer to a + * uart_16550_instance_t structure that holds all data + * regarding this instance of the Core16550. + * @param handler The handler parameter is a pointer to a receiver line + * status interrupt handler function provided by your + * application that will be called as a result of a + * UART RLS interrupt. This handler function must be + * of type uart_16550_irq_handler_t. + * Example: + * @code + * #include "core_16550.h" + * + * #define UART_57600_BAUD 26 + * + * uart_16550_instance_t g_uart; + * + * void uart_rxsts_handler( uart_16550_instance_t * this_uart ) + * { + * uint8_t status; + * status = UART_16550_get_rx_status( this_uart ); + * if( status & UART_16550_OVERUN_ERROR ) + * { + * discard_rx_data(); + * } + * } + * + * int main(void) + * { + * UART_16550_init( &g_uart, UART_57600_BAUD, + * UART_16550_DATA_8_BITS | UART_16550_NO_PARITY | + * UART_16550_ONE_STOP_BIT ); + * UART_16550_set_rxstatus_handler( &g_uart, uart_rxsts_handler ); + * + * while ( 1 ) + * { + * ; + * } + * return(0); + * } + * @endcode + */ +void +UART_16550_set_rxstatus_handler +( + uart_16550_instance_t * this_uart, + uart_16550_irq_handler_t handler +); + +/***************************************************************************//** + * The UART_16550_set_tx_handler() function is used to register a transmit + * handler function that is called by the driver when a UART transmit holding + * register empty (THRE) interrupt occurs. The UART_16550_set_tx_handler() + * function also enables the THRE interrupt at the Core16550 level. You must + * create and register the transmit handler function to suit your application. + * You can use the UART_16550_fill_tx_fifo() function in your transmit handler + * function to write data to the transmitter. + * + * Note: The driver’s top level interrupt handler function UART_16550_isr() + * will call your transmit handler function in response to an THRE interrupt + * from the Core16550. + * + * Note: You can disable the THRE interrupt when required by calling the + * UART_16550_disable_irq() function. This is your choice and is dependent + * upon your application. + * + * Note: The UART_16550_irq_tx() function does not use the transmit handler + * function that you register with the UART_16550_set_tx_handler() function. + * It uses its own internal THRE interrupt handler function that overrides any + * custom interrupt handler that you register using the + * UART_16550_set_tx_handler() function. + * + * @param this_uart The this_uart parameter is a pointer to a + * uart_16550_instance_t structure that holds all data + * regarding this instance of the Core16550. + * @param handler The handler parameter is a pointer to a transmitter + * interrupt handler function provided by your application, + * which will be called as a result of a UART THRE interrupt. + * This handler is of uart_16550_irq_handler_t type. + * @return This function does not return a value. + * + * Example: + * @code + * #include "core_16550.h" + * + * #define UART_57600_BAUD 26 + * + * uart_16550_instance_t g_uart; + * + * uint8_t * g_tx_buffer; + * size_t g_tx_size = 0; + * + * void uart_tx_handler( uart_16550_instance_t * this_uart ) + * { + * size_t size_in_fifo; + * + * size_in_fifo = UART_16550_fill_tx_fifo( this_uart, + * (const uint8_t *)g_tx_buffer, + * g_tx_size ); + * + * if(size_in_fifo == g_tx_size) + * { + * g_tx_size = 0; + * UART_16550_disable_irq( this_uart, UART_16550_TBE_IRQ ); + * } + * else + * { + * g_tx_buffer = &g_tx_buffer[size_in_fifo]; + * g_tx_size = g_tx_size - size_in_fifo; + * } + * } + * + * int main(void) + * { + * uint8_t message[12] = "Hello world"; + * + * UART_16550_init( &g_uart, UART_57600_BAUD, + * UART_16550_DATA_8_BITS | UART_16550_NO_PARITY | + * UART_16550_ONE_STOP_BIT ); + * + * g_tx_buffer = message; + * g_tx_size = sizeof(message); + * + * UART_16550_set_tx_handler( &g_uart, uart_tx_handler); + * + * while ( 1 ) + * { + * ; + * } + * return(0); + * } + * + * @endcode + */ +void +UART_16550_set_tx_handler +( + uart_16550_instance_t * this_uart, + uart_16550_irq_handler_t handler +); + +/***************************************************************************//** + * The UART_16550_set_modemstatus_handler() function is used to register a + * modem status handler function that is called by the driver when a UART modem + * status (MS) interrupt occurs. The UART_16550_set_modemstatus_handler() + * function also enables the MS interrupt at the Core16550 level. You must + * create and register the modem status handler function to suit your + * application. + * + * Note: The driver’s top level interrupt handler function UART_16550_isr() + * will call your receive status handler function in response to an MS interrupt + * from the Core16550. + * + * Note: You can disable the MS interrupt when required by calling the + * UART_16550_disable_irq() function. This is your choice and is dependent + * upon your application. + * + * @param this_uart The this_uart parameter is a pointer to a + * uart_16550_instance_t structure that holds all data + * regarding this instance of the Core16550. + * @param handler The handler parameter is a pointer to a modem status + * interrupt handler function provided by your application + * that will be called as a result of a UART MS interrupt. + * This handler function must be of type + * uart_16550_irq_handler_t. + * @return This function does not return a value. + * + * Example: + * @code + * #include "core_16550.h" + * + * #define UART_57600_BAUD 26 + * + * uart_16550_instance_t g_uart; + * + * void uart_modem_handler( uart_16550_instance_t * this_uart ) + * { + * uint8_t status; + * status = UART_16550_get_modem_status( this_uart ); + * if( status & UART_16550_CTS ) + * { + * uart_cts_handler(); + * } + * } + * + * int main(void) + * { + * UART_16550_init( &g_uart, UART_57600_BAUD, + * UART_16550_DATA_8_BITS | UART_16550_NO_PARITY | + UART_16550_ONE_STOP_BIT); + * UART_16550_set_modemstatus_handler( &g_uart, uart_modem_handler); + * + * while ( 1 ) + * { + * ; + * } + * return(0); + * } + * @endcode + */ +void +UART_16550_set_modemstatus_handler +( + uart_16550_instance_t * this_uart, + uart_16550_irq_handler_t handler +); + +/***************************************************************************//** + * The UART_16550_fill_tx_fifo() function fills the UART's hardware transmitter + * FIFO with the data found in the transmitter buffer that is passed via the + * tx_buffer function parameter. If the transmitter FIFO is not empty when the + * function is called, the function returns immediately without transferring + * any data to the FIFO; otherwise, the function transfers data from the + * transmitter buffer to the FIFO until it is full or until the complete + * contents of the transmitter buffer have been copied into the FIFO. The + * function returns the number of bytes copied into the UART's transmitter FIFO. + * + * Note: This function reads the UART’s line status register (LSR) to check + * for the active state of the transmitter holding register empty (THRE) bit + * before transferring data from the data buffer to the transmitter FIFO. If + * THRE is 0, the function returns immediately, without transferring any data + * to the FIFO. If THRE is 1, the function transfers up to 16 bytes of data to + * the FIFO and then returns. + * + * Note: The actual transmission over the serial connection will still be in + * progress when this function returns. Use the UART_16550_get_tx_status() + * function if you need to know when the transmitter is empty. + * + * @param this_uart The this_uart parameter is a pointer to a + * uart_16550_instance_t structure that holds all data + * regarding this instance of the Core16550. + * @param tx_buffer The tx_buffer parameter is a pointer to a buffer + * containing the data to be transmitted. + * @param tx_size The tx_size parameter is the size in bytes, of the data + * to be transmitted. + * @return This function returns the number of bytes copied + * into the UART's transmitter FIFO. + * + * Example: + * @code + * void send_using_interrupt(uint8_t * pbuff, size_t tx_size) + * { + * size_t size_in_fifo; + * size_in_fifo = UART_16550_fill_tx_fifo( &g_uart, pbuff, tx_size ); + * } + * @endcode + */ +size_t +UART_16550_fill_tx_fifo +( + uart_16550_instance_t * this_uart, + const uint8_t * tx_buffer, + size_t tx_size +); + +/***************************************************************************//** + * The UART_16550_get_tx_status() function returns the transmitter status of + * the Core16550 instance. It reads both the UART’s line status register (LSR) + * and returns the status of the transmit holding register empty (THRE) and + * transmitter empty (TEMT) bits. + * + * @param this_uart The this_uart parameter is a pointer to a + * uart_16550_instance_t structure that holds all data + * regarding this instance of the Core16550. + * @return This function returns the UART’s transmitter status + * as an 8-bit unsigned integer. The returned value is 0 + * if the transmitter status bits are not set or the + * function execution failed. The driver provides a set + * of bit mask constants that should be compared with + * and/or used to mask the returned value to determine + * the transmitter status. + * When the return value is compared to the following + * bitmasks, a non-zero result indicates that the + * corresponding transmitter status bit is set: + * • UART_16550_THRE (bit mask = 0x20) + * • UART_16550_TEMT (bit mask = 0x40) + * When the return value is compared to the following + * bit mask, a non-zero result indicates that the + * transmitter is busy or the function execution failed. + * • UART_16550_TX_BUSY (bit mask = 0x00) + * Example: + * @code + * uint8_t tx_buff[10] = "abcdefghi"; + * + * UART_16550_polled_tx( &g_uart, tx_buff, sizeof(tx_buff)); + * + * while ( ! (UART_16550_TEMT & UART_16550_get_tx_status( &g_uart ) ) ) + * { + * ; + * } + * @endcode + */ +uint8_t +UART_16550_get_tx_status +( + uart_16550_instance_t * this_uart +); + +#ifdef __cplusplus +} +#endif + +#endif /* __CORE_16550_H */ diff --git a/FreeRTOS/Demo/RISC-V_IGLOO2_Creative_SoftConsole/drivers/CoreGPIO/core_gpio.c b/FreeRTOS/Demo/RISC-V_IGLOO2_Creative_SoftConsole/drivers/CoreGPIO/core_gpio.c new file mode 100644 index 000000000..e5dbd7edf --- /dev/null +++ b/FreeRTOS/Demo/RISC-V_IGLOO2_Creative_SoftConsole/drivers/CoreGPIO/core_gpio.c @@ -0,0 +1,461 @@ +/******************************************************************************* + * (c) Copyright 2008-2015 Microsemi SoC Products Group. All rights reserved. + * + * CoreGPIO bare metal driver implementation. + * + * SVN $Revision: 7964 $ + * SVN $Date: 2015-10-09 18:26:53 +0530 (Fri, 09 Oct 2015) $ + */ +#include "core_gpio.h" +#include "hal.h" +#include "hal_assert.h" +#include "coregpio_regs.h" + +/*-------------------------------------------------------------------------*//** + * + */ +#define GPIO_INT_ENABLE_MASK (uint32_t)0x00000008UL +#define OUTPUT_BUFFER_ENABLE_MASK 0x00000004UL + + +#define NB_OF_GPIO 32 + +#define CLEAR_ALL_IRQ32 (uint32_t)0xFFFFFFFF +#define CLEAR_ALL_IRQ16 (uint16_t)0xFFFF +#define CLEAR_ALL_IRQ8 (uint8_t)0xFF + +/*-------------------------------------------------------------------------*//** + * GPIO_init() + * See "core_gpio.h" for details of how to use this function. + */ +void GPIO_init +( + gpio_instance_t * this_gpio, + addr_t base_addr, + gpio_apb_width_t bus_width +) +{ + uint8_t i = 0; + addr_t cfg_reg_addr = base_addr; + + this_gpio->base_addr = base_addr; + this_gpio->apb_bus_width = bus_width; + + /* Clear configuration. */ + for( i = 0, cfg_reg_addr = base_addr; i < NB_OF_GPIO; ++i ) + { + HW_set_8bit_reg( cfg_reg_addr, 0 ); + cfg_reg_addr += 4; + } + /* Clear any pending interrupts */ + switch( this_gpio->apb_bus_width ) + { + case GPIO_APB_32_BITS_BUS: + HAL_set_32bit_reg( this_gpio->base_addr, IRQ, CLEAR_ALL_IRQ32 ); + break; + + case GPIO_APB_16_BITS_BUS: + HAL_set_16bit_reg( this_gpio->base_addr, IRQ0, (uint16_t)CLEAR_ALL_IRQ16 ); + HAL_set_16bit_reg( this_gpio->base_addr, IRQ1, (uint16_t)CLEAR_ALL_IRQ16 ); + break; + + case GPIO_APB_8_BITS_BUS: + HAL_set_8bit_reg( this_gpio->base_addr, IRQ0, (uint8_t)CLEAR_ALL_IRQ8 ); + HAL_set_8bit_reg( this_gpio->base_addr, IRQ1, (uint8_t)CLEAR_ALL_IRQ8 ); + HAL_set_8bit_reg( this_gpio->base_addr, IRQ2, (uint8_t)CLEAR_ALL_IRQ8 ); + HAL_set_8bit_reg( this_gpio->base_addr, IRQ3, (uint8_t)CLEAR_ALL_IRQ8 ); + break; + + default: + HAL_ASSERT(0); + break; + } +} + +/*-------------------------------------------------------------------------*//** + * GPIO_config + * See "core_gpio.h" for details of how to use this function. + */ +void GPIO_config +( + gpio_instance_t * this_gpio, + gpio_id_t port_id, + uint32_t config +) +{ + HAL_ASSERT( port_id < NB_OF_GPIO ); + + if ( port_id < NB_OF_GPIO ) + { + uint32_t cfg_reg_addr = this_gpio->base_addr; + cfg_reg_addr += (port_id * 4); + HW_set_32bit_reg( cfg_reg_addr, config ); + + /* + * Verify that the configuration was correctly written. Failure to read + * back the expected value may indicate that the GPIO port was configured + * as part of the hardware flow and cannot be modified through software. + * It may also indicate that the base address passed as parameter to + * GPIO_init() was incorrect. + */ + HAL_ASSERT( HW_get_32bit_reg( cfg_reg_addr ) == config ); + } +} + +/*-------------------------------------------------------------------------*//** + * GPIO_set_outputs + * See "core_gpio.h" for details of how to use this function. + */ +void GPIO_set_outputs +( + gpio_instance_t * this_gpio, + uint32_t value +) +{ + switch( this_gpio->apb_bus_width ) + { + case GPIO_APB_32_BITS_BUS: + HAL_set_32bit_reg( this_gpio->base_addr, GPIO_OUT, value ); + break; + + case GPIO_APB_16_BITS_BUS: + HAL_set_16bit_reg( this_gpio->base_addr, GPIO_OUT0, (uint16_t)value ); + HAL_set_16bit_reg( this_gpio->base_addr, GPIO_OUT1, (uint16_t)(value >> 16) ); + break; + + case GPIO_APB_8_BITS_BUS: + HAL_set_8bit_reg( this_gpio->base_addr, GPIO_OUT0, (uint8_t)value ); + HAL_set_8bit_reg( this_gpio->base_addr, GPIO_OUT1, (uint8_t)(value >> 8) ); + HAL_set_8bit_reg( this_gpio->base_addr, GPIO_OUT2, (uint8_t)(value >> 16) ); + HAL_set_8bit_reg( this_gpio->base_addr, GPIO_OUT3, (uint8_t)(value >> 24) ); + break; + + default: + HAL_ASSERT(0); + break; + } + + /* + * Verify that the output register was correctly written. Failure to read back + * the expected value may indicate that some of the GPIOs may not exist due to + * the number of GPIOs selected in the CoreGPIO hardware flow configuration. + * It may also indicate that the base address or APB bus width passed as + * parameter to the GPIO_init() function do not match the hardware design. + */ + HAL_ASSERT( GPIO_get_outputs( this_gpio ) == value ); +} + +/*-------------------------------------------------------------------------*//** + * GPIO_get_inputs + * See "core_gpio.h" for details of how to use this function. + */ +uint32_t GPIO_get_inputs +( + gpio_instance_t * this_gpio +) +{ + uint32_t gpio_in = 0; + + switch( this_gpio->apb_bus_width ) + { + case GPIO_APB_32_BITS_BUS: + gpio_in = HAL_get_32bit_reg( this_gpio->base_addr, GPIO_IN ); + break; + + case GPIO_APB_16_BITS_BUS: + gpio_in |= HAL_get_16bit_reg( this_gpio->base_addr, GPIO_IN0 ); + gpio_in |= (HAL_get_16bit_reg( this_gpio->base_addr, GPIO_IN1 ) << 16); + break; + + case GPIO_APB_8_BITS_BUS: + gpio_in |= HAL_get_8bit_reg( this_gpio->base_addr, GPIO_IN0 ); + gpio_in |= (HAL_get_8bit_reg( this_gpio->base_addr, GPIO_IN1 ) << 8); + gpio_in |= (HAL_get_8bit_reg( this_gpio->base_addr, GPIO_IN2 ) << 16); + gpio_in |= (HAL_get_8bit_reg( this_gpio->base_addr, GPIO_IN3 ) << 24); + break; + + default: + HAL_ASSERT(0); + break; + } + + return gpio_in; +} + +/*-------------------------------------------------------------------------*//** + * GPIO_get_outputs + * See "core_gpio.h" for details of how to use this function. + */ +uint32_t GPIO_get_outputs +( + gpio_instance_t * this_gpio +) +{ + uint32_t gpio_out = 0; + + switch( this_gpio->apb_bus_width ) + { + case GPIO_APB_32_BITS_BUS: + gpio_out = HAL_get_32bit_reg( this_gpio->base_addr, GPIO_OUT ); + break; + + case GPIO_APB_16_BITS_BUS: + gpio_out |= HAL_get_16bit_reg( this_gpio->base_addr, GPIO_OUT0 ); + gpio_out |= (HAL_get_16bit_reg( this_gpio->base_addr, GPIO_OUT1 ) << 16); + break; + + case GPIO_APB_8_BITS_BUS: + gpio_out |= HAL_get_16bit_reg( this_gpio->base_addr, GPIO_OUT0 ); + gpio_out |= (HAL_get_16bit_reg( this_gpio->base_addr, GPIO_OUT1 ) << 8); + gpio_out |= (HAL_get_16bit_reg( this_gpio->base_addr, GPIO_OUT2 ) << 16); + gpio_out |= (HAL_get_16bit_reg( this_gpio->base_addr, GPIO_OUT3 ) << 24); + break; + + default: + HAL_ASSERT(0); + break; + } + + return gpio_out; +} + +/*-------------------------------------------------------------------------*//** + * GPIO_set_output + * See "core_gpio.h" for details of how to use this function. + */ +void GPIO_set_output +( + gpio_instance_t * this_gpio, + gpio_id_t port_id, + uint8_t value +) +{ + HAL_ASSERT( port_id < NB_OF_GPIO ); + + + switch( this_gpio->apb_bus_width ) + { + case GPIO_APB_32_BITS_BUS: + { + uint32_t outputs_state; + + outputs_state = HAL_get_32bit_reg( this_gpio->base_addr, GPIO_OUT ); + if ( 0 == value ) + { + outputs_state &= ~(1 << port_id); + } + else + { + outputs_state |= 1 << port_id; + } + HAL_set_32bit_reg( this_gpio->base_addr, GPIO_OUT, outputs_state ); + + /* + * Verify that the output register was correctly written. Failure to read back + * the expected value may indicate that some of the GPIOs may not exist due to + * the number of GPIOs selected in the CoreGPIO hardware flow configuration. + * It may also indicate that the base address or APB bus width passed as + * parameter to the GPIO_init() function do not match the hardware design. + */ + HAL_ASSERT( HAL_get_32bit_reg( this_gpio->base_addr, GPIO_OUT ) == outputs_state ); + } + break; + + case GPIO_APB_16_BITS_BUS: + { + uint16_t outputs_state; + uint32_t gpio_out_reg_addr = this_gpio->base_addr + GPIO_OUT_REG_OFFSET + ((port_id >> 4) * 4); + + outputs_state = HW_get_16bit_reg( gpio_out_reg_addr ); + if ( 0 == value ) + { + outputs_state &= ~(1 << (port_id & 0x0F)); + } + else + { + outputs_state |= 1 << (port_id & 0x0F); + } + HW_set_16bit_reg( gpio_out_reg_addr, outputs_state ); + + /* + * Verify that the output register was correctly written. Failure to read back + * the expected value may indicate that some of the GPIOs may not exist due to + * the number of GPIOs selected in the CoreGPIO hardware flow configuration. + * It may also indicate that the base address or APB bus width passed as + * parameter to the GPIO_init() function do not match the hardware design. + */ + HAL_ASSERT( HW_get_16bit_reg( gpio_out_reg_addr ) == outputs_state ); + } + break; + + case GPIO_APB_8_BITS_BUS: + { + uint8_t outputs_state; + uint32_t gpio_out_reg_addr = this_gpio->base_addr + GPIO_OUT_REG_OFFSET + ((port_id >> 3) * 4); + + outputs_state = HW_get_8bit_reg( gpio_out_reg_addr ); + if ( 0 == value ) + { + outputs_state &= ~(1 << (port_id & 0x07)); + } + else + { + outputs_state |= 1 << (port_id & 0x07); + } + HW_set_8bit_reg( gpio_out_reg_addr, outputs_state ); + + /* + * Verify that the output register was correctly written. Failure to read back + * the expected value may indicate that some of the GPIOs may not exist due to + * the number of GPIOs selected in the CoreGPIO hardware flow configuration. + * It may also indicate that the base address or APB bus width passed as + * parameter to the GPIO_init() function do not match the hardware design. + */ + HAL_ASSERT( HW_get_8bit_reg( gpio_out_reg_addr ) == outputs_state ); + } + break; + + default: + HAL_ASSERT(0); + break; + } +} + +/*-------------------------------------------------------------------------*//** + * GPIO_drive_inout + * See "core_gpio.h" for details of how to use this function. + */ +void GPIO_drive_inout +( + gpio_instance_t * this_gpio, + gpio_id_t port_id, + gpio_inout_state_t inout_state +) +{ + uint32_t config; + uint32_t cfg_reg_addr = this_gpio->base_addr; + + HAL_ASSERT( port_id < NB_OF_GPIO ); + + switch( inout_state ) + { + case GPIO_DRIVE_HIGH: + /* Set output high */ + GPIO_set_output( this_gpio, port_id, 1 ); + + /* Enable output buffer */ + cfg_reg_addr = this_gpio->base_addr + (port_id * 4); + config = HW_get_8bit_reg( cfg_reg_addr ); + config |= OUTPUT_BUFFER_ENABLE_MASK; + HW_set_8bit_reg( cfg_reg_addr, config ); + break; + + case GPIO_DRIVE_LOW: + /* Set output low */ + GPIO_set_output( this_gpio, port_id, 0 ); + + /* Enable output buffer */ + cfg_reg_addr = this_gpio->base_addr + (port_id * 4); + config = HW_get_8bit_reg( cfg_reg_addr ); + config |= OUTPUT_BUFFER_ENABLE_MASK; + HW_set_8bit_reg( cfg_reg_addr, config ); + break; + + case GPIO_HIGH_Z: + /* Disable output buffer */ + cfg_reg_addr = this_gpio->base_addr + (port_id * 4); + config = HW_get_8bit_reg( cfg_reg_addr ); + config &= ~OUTPUT_BUFFER_ENABLE_MASK; + HW_set_8bit_reg( cfg_reg_addr, config ); + break; + + default: + HAL_ASSERT(0); + break; + } +} + +/*-------------------------------------------------------------------------*//** + * GPIO_enable_irq + * See "core_gpio.h" for details of how to use this function. + */ +void GPIO_enable_irq +( + gpio_instance_t * this_gpio, + gpio_id_t port_id +) +{ + uint32_t cfg_value; + uint32_t cfg_reg_addr = this_gpio->base_addr; + + HAL_ASSERT( port_id < NB_OF_GPIO ); + + if ( port_id < NB_OF_GPIO ) + { + cfg_reg_addr += (port_id * 4); + cfg_value = HW_get_8bit_reg( cfg_reg_addr ); + cfg_value |= GPIO_INT_ENABLE_MASK; + HW_set_8bit_reg( cfg_reg_addr, cfg_value ); + } +} + +/*-------------------------------------------------------------------------*//** + * GPIO_disable_irq + * See "core_gpio.h" for details of how to use this function. + */ +void GPIO_disable_irq +( + gpio_instance_t * this_gpio, + gpio_id_t port_id +) +{ + uint32_t cfg_value; + uint32_t cfg_reg_addr = this_gpio->base_addr; + + HAL_ASSERT( port_id < NB_OF_GPIO ); + + if ( port_id < NB_OF_GPIO ) + { + cfg_reg_addr += (port_id * 4); + cfg_value = HW_get_8bit_reg( cfg_reg_addr ); + cfg_value &= ~GPIO_INT_ENABLE_MASK; + HW_set_8bit_reg( cfg_reg_addr, cfg_value ); + } +} + +/*-------------------------------------------------------------------------*//** + * GPIO_clear_irq + * See "core_gpio.h" for details of how to use this function. + */ +void GPIO_clear_irq +( + gpio_instance_t * this_gpio, + gpio_id_t port_id +) +{ + uint32_t irq_clr_value = ((uint32_t)1) << ((uint32_t)port_id); + + switch( this_gpio->apb_bus_width ) + { + case GPIO_APB_32_BITS_BUS: + HAL_set_32bit_reg( this_gpio->base_addr, IRQ, irq_clr_value ); + break; + + case GPIO_APB_16_BITS_BUS: + HAL_set_16bit_reg( this_gpio->base_addr, IRQ0, irq_clr_value ); + HAL_set_16bit_reg( this_gpio->base_addr, IRQ1, irq_clr_value >> 16 ); + break; + + case GPIO_APB_8_BITS_BUS: + HAL_set_8bit_reg( this_gpio->base_addr, IRQ0, irq_clr_value ); + HAL_set_8bit_reg( this_gpio->base_addr, IRQ1, irq_clr_value >> 8 ); + HAL_set_8bit_reg( this_gpio->base_addr, IRQ2, irq_clr_value >> 16 ); + HAL_set_8bit_reg( this_gpio->base_addr, IRQ3, irq_clr_value >> 24 ); + break; + + default: + HAL_ASSERT(0); + break; + } +} + diff --git a/FreeRTOS/Demo/RISC-V_IGLOO2_Creative_SoftConsole/drivers/CoreGPIO/core_gpio.h b/FreeRTOS/Demo/RISC-V_IGLOO2_Creative_SoftConsole/drivers/CoreGPIO/core_gpio.h new file mode 100644 index 000000000..68799be27 --- /dev/null +++ b/FreeRTOS/Demo/RISC-V_IGLOO2_Creative_SoftConsole/drivers/CoreGPIO/core_gpio.h @@ -0,0 +1,552 @@ +/******************************************************************************* + * (c) Copyright 2008-2015 Microsemi SoC Products Group. All rights reserved. + * + * CoreGPIO bare metal driver public API. + * + * SVN $Revision: 7964 $ + * SVN $Date: 2015-10-09 18:26:53 +0530 (Fri, 09 Oct 2015) $ + */ + +/*=========================================================================*//** + @mainpage CoreGPIO Bare Metal Driver. + + @section intro_sec Introduction + The CoreGPIO hardware IP includes up to 32 general purpose input output GPIOs. + This driver provides a set of functions for controlling the GPIOs as part of a + bare metal system where no operating system is available. These drivers + can be adapted for use as part of an operating system but the implementation + of the adaptation layer between this driver and the operating system's driver + model is outside the scope of this driver. + + @section driver_configuration Driver Configuration + The CoreGPIO individual IOs can be configured either in the hardware flow or + as part of the software application through calls to the GPIO_config() function. + GPIOs configured as as part of the hardware is fixed and cannot be modified + using a call to the GPI_config() function. + + @section theory_op Theory of Operation + The CoreGPIO driver uses the Actel Hardware Abstraction Layer (HAL) to access + hardware registers. You must ensure that the Actel HAL is included as part of + your software project. The Actel HAL is available through the Actel Firmware + Catalog. + + The CoreGPIO driver functions are logically grouped into the following groups: + - Initiliazation + - Configuration + - Reading and writing GPIO state + - Interrupt control + + The CoreGPIO driver is initialized through a call to the GPIO_init() function. + The GPIO_init() function must be called before any other GPIO driver functions + can be called. + + Each GPIO port is individually configured through a call to the + GPIO_config() function. Configuration includes deciding if a GPIO port + will be used as input, output or both. GPIO ports configured as inputs can be + further configured to generate interrupts based on the input's state. + Interrupts can be level or edge sensitive. + Please note that a CoreGPIO hardware instance can be generated, as part of the + hardware flow, with a fixed configuration for some or all of its IOs. Attempting + to modify the configuration of such a hardware configured IO using the + GPIO_config() function has no effect. + + The state of the GPIO ports can be read and written using the following + functions: + - GPIO_get_inputs() + - GPIO_get_outputs() + - GPIO_set_outputs() + - GPIO_drive_inout() + + Interrupts generated by GPIO ports configured as inputs are controlled using + the following functions: + - GPIO_enable_irq() + - GPIO_disable_irq() + - GPIO_clear_irq() + + *//*=========================================================================*/ +#ifndef CORE_GPIO_H_ +#define CORE_GPIO_H_ + +#include +#include "cpu_types.h" + +/*-------------------------------------------------------------------------*//** + The gpio_id_t enumeration is used to identify GPIOs as part of the + parameter to functions: + - GPIO_config(), + - GPIO_drive_inout(), + - GPIO_enable_int(), + - GPIO_disable_int(), + - GPIO_clear_int() + */ +typedef enum __gpio_id_t +{ + GPIO_0 = 0, + GPIO_1 = 1, + GPIO_2 = 2, + GPIO_3 = 3, + GPIO_4 = 4, + GPIO_5 = 5, + GPIO_6 = 6, + GPIO_7 = 7, + GPIO_8 = 8, + GPIO_9 = 9, + GPIO_10 = 10, + GPIO_11 = 11, + GPIO_12 = 12, + GPIO_13 = 13, + GPIO_14 = 14, + GPIO_15 = 15, + GPIO_16 = 16, + GPIO_17 = 17, + GPIO_18 = 18, + GPIO_19 = 19, + GPIO_20 = 20, + GPIO_21 = 21, + GPIO_22 = 22, + GPIO_23 = 23, + GPIO_24 = 24, + GPIO_25 = 25, + GPIO_26 = 26, + GPIO_27 = 27, + GPIO_28 = 28, + GPIO_29 = 29, + GPIO_30 = 30, + GPIO_31 = 31 +} gpio_id_t; + +typedef enum __gpio_apb_width_t +{ + GPIO_APB_8_BITS_BUS = 0, + GPIO_APB_16_BITS_BUS = 1, + GPIO_APB_32_BITS_BUS = 2, + GPIO_APB_UNKNOWN_BUS_WIDTH = 3 +} gpio_apb_width_t; + +/*-------------------------------------------------------------------------*//** + */ +typedef struct __gpio_instance_t +{ + addr_t base_addr; + gpio_apb_width_t apb_bus_width; +} gpio_instance_t; + +/*-------------------------------------------------------------------------*//** + GPIO ports definitions used to identify GPIOs as part of the parameter to + function GPIO_set_outputs(). + These definitions can also be used to identity GPIO through logical + operations on the return value of function GPIO_get_inputs(). + */ +#define GPIO_0_MASK 0x00000001UL +#define GPIO_1_MASK 0x00000002UL +#define GPIO_2_MASK 0x00000004UL +#define GPIO_3_MASK 0x00000008UL +#define GPIO_4_MASK 0x00000010UL +#define GPIO_5_MASK 0x00000020UL +#define GPIO_6_MASK 0x00000040UL +#define GPIO_7_MASK 0x00000080UL +#define GPIO_8_MASK 0x00000100UL +#define GPIO_9_MASK 0x00000200UL +#define GPIO_10_MASK 0x00000400UL +#define GPIO_11_MASK 0x00000800UL +#define GPIO_12_MASK 0x00001000UL +#define GPIO_13_MASK 0x00002000UL +#define GPIO_14_MASK 0x00004000UL +#define GPIO_15_MASK 0x00008000UL +#define GPIO_16_MASK 0x00010000UL +#define GPIO_17_MASK 0x00020000UL +#define GPIO_18_MASK 0x00040000UL +#define GPIO_19_MASK 0x00080000UL +#define GPIO_20_MASK 0x00100000UL +#define GPIO_21_MASK 0x00200000UL +#define GPIO_22_MASK 0x00400000UL +#define GPIO_23_MASK 0x00800000UL +#define GPIO_24_MASK 0x01000000UL +#define GPIO_25_MASK 0x02000000UL +#define GPIO_26_MASK 0x04000000UL +#define GPIO_27_MASK 0x08000000UL +#define GPIO_28_MASK 0x10000000UL +#define GPIO_29_MASK 0x20000000UL +#define GPIO_30_MASK 0x40000000UL +#define GPIO_31_MASK 0x80000000UL + +/*-------------------------------------------------------------------------*//** + * GPIO modes + */ +#define GPIO_INPUT_MODE 0x0000000002UL +#define GPIO_OUTPUT_MODE 0x0000000005UL +#define GPIO_INOUT_MODE 0x0000000003UL + +/*-------------------------------------------------------------------------*//** + * Possible GPIO inputs interrupt configurations. + */ +#define GPIO_IRQ_LEVEL_HIGH 0x0000000000UL +#define GPIO_IRQ_LEVEL_LOW 0x0000000020UL +#define GPIO_IRQ_EDGE_POSITIVE 0x0000000040UL +#define GPIO_IRQ_EDGE_NEGATIVE 0x0000000060UL +#define GPIO_IRQ_EDGE_BOTH 0x0000000080UL + +/*-------------------------------------------------------------------------*//** + * Possible states for GPIO configured as INOUT. + */ +typedef enum gpio_inout_state +{ + GPIO_DRIVE_LOW = 0, + GPIO_DRIVE_HIGH, + GPIO_HIGH_Z +} gpio_inout_state_t; + +/*-------------------------------------------------------------------------*//** + The GPIO_init() function initialises a CoreGPIO hardware instance and the data + structure associated with the CoreGPIO hardware instance. + Please note that a CoreGPIO hardware instance can be generated with a fixed + configuration for some or all of its IOs as part of the hardware flow. Attempting + to modify the configuration of such a hardware configured IO using the + GPIO_config() function has no effect. + + @param this_gpio + Pointer to the gpio_instance_t data structure instance holding all data + regarding the CoreGPIO hardware instance being initialized. A pointer to the + same data structure will be used in subsequent calls to the CoreGPIO driver + functions in order to identify the CoreGPIO instance that should perform the + operation implemented by the called driver function. + + @param base_addr + The base_addr parameter is the base address in the processor's memory map for + the registers of the GPIO instance being initialized. + + @param bus_width + The bus_width parameter informs the driver of the APB bus width selected during + the hardware flow configuration of the CoreGPIO hardware instance. It indicates + to the driver whether the CoreGPIO hardware registers will be visible as 8, 16 + or 32 bits registers. Allowed value are: + - GPIO_APB_8_BITS_BUS + - GPIO_APB_16_BITS_BUS + - GPIO_APB_32_BITS_BUS + + @return + none. + + Example: + @code + #define COREGPIO_BASE_ADDR 0xC2000000 + + gpio_instance_t g_gpio; + + void system_init( void ) + { + GPIO_init( &g_gpio, COREGPIO_BASE_ADDR, GPIO_APB_32_BITS_BUS ); + } + @endcode + */ +void GPIO_init +( + gpio_instance_t * this_gpio, + addr_t base_addr, + gpio_apb_width_t bus_width +); + +/*-------------------------------------------------------------------------*//** + The GPIO_config() function is used to configure an individual GPIO port. + + @param this_gpio + The this_gpio parameter is a pointer to the gpio_instance_t structure holding + all data regarding the CoreGPIO instance controlled through this function call. + + @param port_id + The port_id parameter identifies the GPIO port to be configured. + An enumeration item of the form GPIO_n where n is the number of the GPIO + port is used to identify the GPIO port. For example GPIO_0 identifies the + first GPIO port and GPIO_31 the last one. + + @param config + The config parameter specifies the configuration to be applied to the GPIO + port identified by the first parameter. It is a logical OR of GPIO mode and + the interrupt mode. The interrupt mode is only relevant if the GPIO is + configured as input. + Possible modes are: + - GPIO_INPUT_MODE, + - GPIO_OUTPUT_MODE, + - GPIO_INOUT_MODE. + Possible interrupt modes are: + - GPIO_IRQ_LEVEL_HIGH, + - GPIO_IRQ_LEVEL_LOW, + - GPIO_IRQ_EDGE_POSITIVE, + - GPIO_IRQ_EDGE_NEGATIVE, + - GPIO_IRQ_EDGE_BOTH + + @return + none. + + For example the following call will configure GPIO 4 as an input generating + interrupts on a low to high transition of the input: + @code + GPIO_config( &g_gpio, GPIO_4, GPIO_INPUT_MODE | GPIO_IRQ_EDGE_POSITIVE ); + @endcode + */ +void GPIO_config +( + gpio_instance_t * this_gpio, + gpio_id_t port_id, + uint32_t config +); + +/*-------------------------------------------------------------------------*//** + The GPIO_set_outputs() function is used to set the state of the GPIO ports + configured as outputs. + + @param this_gpio + The this_gpio parameter is a pointer to the gpio_instance_t structure holding + all data regarding the CoreGPIO instance controlled through this function call. + + @param value + The value parameter specifies the state of the GPIO ports configured as + outputs. It is a bit mask of the form (GPIO_n_MASK | GPIO_m_MASK) where n + and m are numbers identifying GPIOs. + For example (GPIO_0_MASK | GPIO_1_MASK | GPIO_2_MASK ) specifies that the + first, second and third GPIOs' must be set high and all other outputs set + low. + + @return + none. + + Example 1: + Set GPIOs outputs 0 and 8 high and all other GPIO outputs low. + @code + GPIO_set_outputs( &g_gpio, GPIO_0_MASK | GPIO_8_MASK ); + @endcode + + Example 2: + Set GPIOs outputs 2 and 4 low without affecting other GPIO outputs. + @code + uint32_t gpio_outputs; + gpio_outputs = GPIO_get_outputs( &g_gpio ); + gpio_outputs &= ~( GPIO_2_MASK | GPIO_4_MASK ); + GPIO_set_outputs( &g_gpio, gpio_outputs ); + @endcode + + @see GPIO_get_outputs() + */ +void GPIO_set_outputs +( + gpio_instance_t * this_gpio, + uint32_t value +); + +/*-------------------------------------------------------------------------*//** + The GPIO_set_output() function is used to set the state of a single GPIO + port configured as output. + + @param this_gpio + The this_gpio parameter is a pointer to the gpio_instance_t structure holding + all data regarding the CoreGPIO instance controlled through this function call. + + @param port_id + The port_id parameter specifies the GPIO port that will have its output set + by a call to this function. + + @param value + The value parameter specifies the desired state for the GPIO output. A value + of 0 will set the output low and a value of 1 will set the port high. + + @return + none. + */ +void GPIO_set_output +( + gpio_instance_t * this_gpio, + gpio_id_t port_id, + uint8_t value +); + +/*-------------------------------------------------------------------------*//** + The GPIO_get_inputs() function is used to read the state of all GPIOs + confgured as inputs. + + @param this_gpio + The this_gpio parameter is a pointer to the gpio_instance_t structure holding + all data regarding the CoreGPIO instance controlled through this function call. + + @return + This function returns a 32 bit unsigned integer where each bit represents + the state of an input. The least significant bit representing the state of + GPIO 0 and the most significant bit the state of GPIO 31. + */ +uint32_t GPIO_get_inputs +( + gpio_instance_t * this_gpio +); + +/*-------------------------------------------------------------------------*//** + The GPIO_get_outputs() function is used to read the current state of all + GPIO outputs. + + @param this_gpio + The this_gpio parameter is a pointer to the gpio_instance_t structure holding + all data regarding the CoreGPIO instance controlled through this function call. + + @return + This function returns a 32 bit unsigned integer where each bit represents + the state of an output. The least significant bit representing the state + of GPIO 0 and the most significant bit the state of GPIO 31. + */ +uint32_t GPIO_get_outputs +( + gpio_instance_t * this_gpio +); + +/*-------------------------------------------------------------------------*//** + The GPIO_drive_inout() function is used to set the output state of a + GPIO configured as INOUT. An INOUT GPIO can be in one of three states: + - high + - low + - high impedance + An INOUT output would typically be used where several devices can drive the + state of a signal. The high and low states are equivalent to the high and low + states of a GPIO configured as output. The high impedance state is used to + prevent the GPIO from driving the state of the output and therefore allow + reading the state of the GPIO as an input. + Please note that the GPIO port you wish to use as INOUT through this function + must be configurable through software. Therefore the GPIO ports used as INOUT + must not have a fixed configuration selected as part of the hardware flow. + + @param this_gpio + The this_gpio parameter is a pointer to the gpio_instance_t structure holding + all data regarding the CoreGPIO instance controlled through this function call. + + @param port_id + The port_id parameter identifies the GPIO for whcih this function will + change the output state. + An enumeration item of the form GPIO_n where n is the number of the GPIO + port is used to identify the GPIO port. For example GPIO_0 identifies the + first GPIO port and GPIO_31 the last one. + + @param inout_state + The inout_state parameter specifies the state of the I/O identified by the + first parameter. Possible states are: + - GPIO_DRIVE_HIGH, + - GPIO_DRIVE_LOW, + - GPIO_HIGH_Z (high impedance) + + @return + none. + + Example: + The call to GPIO_drive_inout() below will set the GPIO 7 output to + high impedance state. + @code + GPIO_drive_inout( &g_gpio, GPIO_7, GPIO_HIGH_Z ); + @endcode + */ +void GPIO_drive_inout +( + gpio_instance_t * this_gpio, + gpio_id_t port_id, + gpio_inout_state_t inout_state +); + +/*-------------------------------------------------------------------------*//** + The GPIO_enable_irq() function is used to enable an interrupt to be + generated based on the state of the input identified as parameter. + + @param this_gpio + The this_gpio parameter is a pointer to the gpio_instance_t structure holding + all data regarding the CoreGPIO instance controlled through this function call. + + @param port_id + The port_id parameter identifies the GPIO input the call to + GPIO_enable_irq() will enable to generate interrupts. + An enumeration item of the form GPIO_n where n is the number of the GPIO + port is used to identify the GPIO port. For example GPIO_0 identifies the + first GPIO port and GPIO_31 the last one. + + @return + none. + + Example: + The call to GPIO_enable_irq() below will allow GPIO 8 to generate + interrupts. + @code + GPIO_enable_irq( &g_gpio, GPIO_8 ); + @endcode + */ +void GPIO_enable_irq +( + gpio_instance_t * this_gpio, + gpio_id_t port_id +); + +/*-------------------------------------------------------------------------*//** + The GPIO_disable_irq() function is used to disable interrupt from being + generated based on the state of the input specified as parameter. + + @param this_gpio + The this_gpio parameter is a pointer to the gpio_instance_t structure holding + all data regarding the CoreGPIO instance controlled through this function call. + + @param port_id + The port_id parameter identifies the GPIO input the call to + GPIO_disable_irq() will disable from generating interrupts. + An enumeration item of the form GPIO_n where n is the number of the GPIO + port is used to identify the GPIO port. For example GPIO_0 identifies the + first GPIO port and GPIO_31 the last one. + + @return + none. + + Example: + The call to GPIO_disable_irq() below will prevent GPIO 8 from generating + interrupts. + @code + GPIO_disable_irq( &g_gpio, GPIO_8 ); + @endcode + */ +void GPIO_disable_irq +( + gpio_instance_t * this_gpio, + gpio_id_t port_id +); + +/*-------------------------------------------------------------------------*//** + The GPIO_clear_irq() function is used to clear the interrupt generated by + the GPIO specified as parameter. The GPIO_clear_irq() function must be + called as part of a GPIO interrupt service routine (ISR) in order to prevent + the same interrupt event retriggering a call to the GPIO ISR. + Please note that interrupts may also need to be cleared in the processor's + interrupt controller. + + @param this_gpio + The this_gpio parameter is a pointer to the gpio_instance_t structure holding + all data regarding the CoreGPIO instance controlled through this function call. + + @param port_id + The port_id parameter identifies the GPIO input for which to clear the + interrupt. + An enumeration item of the form GPIO_n where n is the number of the GPIO + port is used to identify the GPIO port. For example GPIO_0 identifies the + first GPIO port and GPIO_31 the last one. + + @return + none. + + Example: + The example below demonstrates the use of the GPIO_clear_irq() function as + part of the GPIO 9 interrupt service routine on a Cortex-M processor. + @code + void GPIO9_IRQHandler( void ) + { + do_interrupt_processing(); + + GPIO_clear_irq( &g_gpio, GPIO_9 ); + + NVIC_ClearPendingIRQ( GPIO9_IRQn ); + } + @endcode + */ +void GPIO_clear_irq +( + gpio_instance_t * this_gpio, + gpio_id_t port_id +); + +#endif /* CORE_GPIO_H_ */ diff --git a/FreeRTOS/Demo/RISC-V_IGLOO2_Creative_SoftConsole/drivers/CoreGPIO/coregpio_regs.h b/FreeRTOS/Demo/RISC-V_IGLOO2_Creative_SoftConsole/drivers/CoreGPIO/coregpio_regs.h new file mode 100644 index 000000000..afbbfbcb8 --- /dev/null +++ b/FreeRTOS/Demo/RISC-V_IGLOO2_Creative_SoftConsole/drivers/CoreGPIO/coregpio_regs.h @@ -0,0 +1,40 @@ +/******************************************************************************* + * (c) Copyright 2009-2015 Microsemi SoC Products Group. All rights reserved. + * + * SVN $Revision: 7964 $ + * SVN $Date: 2015-10-09 18:26:53 +0530 (Fri, 09 Oct 2015) $ + */ +#ifndef __CORE_GPIO_REGISTERS_H +#define __CORE_GPIO_REGISTERS_H 1 + +/*------------------------------------------------------------------------------ + * + */ +#define IRQ_REG_OFFSET 0x80 + +#define IRQ0_REG_OFFSET 0x80 +#define IRQ1_REG_OFFSET 0x84 +#define IRQ2_REG_OFFSET 0x88 +#define IRQ3_REG_OFFSET 0x8C + +/*------------------------------------------------------------------------------ + * + */ +#define GPIO_IN_REG_OFFSET 0x90 + +#define GPIO_IN0_REG_OFFSET 0x90 +#define GPIO_IN1_REG_OFFSET 0x94 +#define GPIO_IN2_REG_OFFSET 0x98 +#define GPIO_IN3_REG_OFFSET 0x9C + +/*------------------------------------------------------------------------------ + * + */ +#define GPIO_OUT_REG_OFFSET 0xA0 + +#define GPIO_OUT0_REG_OFFSET 0xA0 +#define GPIO_OUT1_REG_OFFSET 0xA4 +#define GPIO_OUT2_REG_OFFSET 0xA8 +#define GPIO_OUT3_REG_OFFSET 0xAC + +#endif /* __CORE_GPIO_REGISTERS_H */ diff --git a/FreeRTOS/Demo/RISC-V_IGLOO2_Creative_SoftConsole/drivers/CoreI2C/core_i2c.c b/FreeRTOS/Demo/RISC-V_IGLOO2_Creative_SoftConsole/drivers/CoreI2C/core_i2c.c new file mode 100644 index 000000000..daa18879d --- /dev/null +++ b/FreeRTOS/Demo/RISC-V_IGLOO2_Creative_SoftConsole/drivers/CoreI2C/core_i2c.c @@ -0,0 +1,1563 @@ +/******************************************************************************* + * (c) Copyright 2009-2015 Microsemi SoC Products Group. All rights reserved. + * + * CoreI2C software driver implementation. + * + * SVN $Revision: 7984 $ + * SVN $Date: 2015-10-12 12:07:40 +0530 (Mon, 12 Oct 2015) $ + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "cpu_types.h" +#include "core_smbus_regs.h" +#include "core_i2c.h" +#include "hal.h" +#include "hal_assert.h" + + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/*------------------------------------------------------------------------------ + * I2C transaction direction. + */ +#define WRITE_DIR 0u +#define READ_DIR 1u + +/* -- TRANSACTIONS TYPES -- */ +#define NO_TRANSACTION 0u +#define MASTER_WRITE_TRANSACTION 1u +#define MASTER_READ_TRANSACTION 2u +#define MASTER_RANDOM_READ_TRANSACTION 3u +#define WRITE_SLAVE_TRANSACTION 4u +#define READ_SLAVE_TRANSACTION 5u + +/* -- SMBUS H/W STATES -- */ +/* -- MASTER STATES -- */ +#define ST_BUS_ERROR 0x00u /* Bus error during MST or selected slave modes */ +#define ST_I2C_IDLE 0xF8u /* No activity and no interrupt either... */ +#define ST_START 0x08u /* start condition sent */ +#define ST_RESTART 0x10u /* repeated start */ +#define ST_SLAW_ACK 0x18u /* SLA+W sent, ack received */ +#define ST_SLAW_NACK 0x20u /* SLA+W sent, nack received */ +#define ST_TX_DATA_ACK 0x28u /* Data sent, ACK'ed */ +#define ST_TX_DATA_NACK 0x30u /* Data sent, NACK'ed */ +#define ST_LOST_ARB 0x38u /* Master lost arbitration */ +#define ST_SLAR_ACK 0x40u /* SLA+R sent, ACK'ed */ +#define ST_SLAR_NACK 0x48u /* SLA+R sent, NACK'ed */ +#define ST_RX_DATA_ACK 0x50u /* Data received, ACK sent */ +#define ST_RX_DATA_NACK 0x58u /* Data received, NACK sent */ +#define ST_RESET_ACTIVATED 0xD0u /* Master reset is activated */ +#define ST_STOP_TRANSMIT 0xE0u /* Stop has been transmitted */ + +/* -- SLAVE STATES -- */ +#define ST_SLAVE_SLAW 0x60u /* SLA+W received */ +#define ST_SLAVE_SLAR_ACK 0xA8u /* SLA+R received, ACK returned */ +#define ST_SLV_LA 0x68u /* Slave lost arbitration */ +#define ST_GCA 0x70u /* GCA received */ +#define ST_GCA_LA 0x78u /* GCA lost arbitration */ +#define ST_RDATA 0x80u /* Data received */ +#define ST_SLA_NACK 0x88u /* Slave addressed, NACK returned */ +#define ST_GCA_ACK 0x90u /* Previously addresses with GCA, data ACKed */ +#define ST_GCA_NACK 0x98u /* GCA addressed, NACK returned */ +#define ST_RSTOP 0xA0u /* Stop received */ +#define ST_SLARW_LA 0xB0u /* Arbitration lost */ +#define ST_RACK 0xB8u /* Byte sent, ACK received */ +#define ST_SLAVE_RNACK 0xC0u /* Byte sent, NACK received */ +#define ST_FINAL 0xC8u /* Final byte sent, ACK received */ +#define ST_SLV_RST 0xD8u /* Slave reset state */ + + +/* I2C Channel base offset */ +#define CHANNEL_BASE_SHIFT 5u +#define CHANNEL_MASK 0x1E0u + +/* + * Maximum address offset length in slave write-read transactions. + * A maximum of two bytes will be interpreted as address offset within the slave + * tx buffer. + */ +#define MAX_OFFSET_LENGTH 2u + +/*------------------------------------------------------------------------------ + * I2C interrupts control functions implemented "i2c_interrupt.c". + * the implementation of these functions depend on the underlying hardware + * design and how the CoreI2C interrupt line is connected to the system's + * interrupt controller. + */ +void I2C_enable_irq( i2c_instance_t * this_i2c ); +void I2C_disable_irq( i2c_instance_t * this_i2c ); +static void enable_slave_if_required(i2c_instance_t * this_i2c); + +/*------------------------------------------------------------------------------ + * I2C_init() + * See "core_i2c.h" for details of how to use this function. + */ +void I2C_init +( + i2c_instance_t * this_i2c, + addr_t base_address, + uint8_t ser_address, + i2c_clock_divider_t ser_clock_speed +) +{ + psr_t saved_psr; + uint_fast16_t clock_speed = (uint_fast16_t)ser_clock_speed; + + /* + * We need to disable ints while doing this as there is no guarantee we + * have not been called already and the ISR is active. + */ + + saved_psr=HAL_disable_interrupts(); + + /* + * Initialize all items of the this_i2c data structure to zero. This + * initializes all state variables to their init value. It relies on + * the fact that NO_TRANSACTION, I2C_SUCCESS and I2C_RELEASE_BUS all + * have an actual value of zero. + */ + memset(this_i2c, 0, sizeof(i2c_instance_t)); + + /* + * Set base address of I2C hardware used by this instance. + */ + this_i2c->base_address = base_address; + + /* + * Update Serial address of the device + */ + this_i2c->ser_address = ((uint_fast8_t)ser_address << 1u); + + /* + * Configure hardware. + */ + HAL_set_8bit_reg_field(this_i2c->base_address, ENS1, 0x00); /* Reset I2C hardware. */ + HAL_set_8bit_reg_field(this_i2c->base_address, ENS1, 0x01); /* set enable bit */ + HAL_set_8bit_reg_field(this_i2c->base_address, CR2, ( (clock_speed >> 2) & 0x01) ); + HAL_set_8bit_reg_field(this_i2c->base_address, CR1, ( (clock_speed >> 1) & 0x01) ); + HAL_set_8bit_reg_field(this_i2c->base_address, CR0, ( clock_speed & 0x01) ); + + HAL_set_8bit_reg(this_i2c->base_address, ADDRESS, this_i2c->ser_address); + HAL_set_8bit_reg(this_i2c->base_address, ADDRESS1, this_i2c->ser_address); + + /* + * Finally safe to enable interrupts. + */ + + HAL_restore_interrupts( saved_psr ); +} +/*------------------------------------------------------------------------------ + * I2C_channel_init() + * See "core_i2c.h" for details of how to use this function. + */ +void I2C_channel_init +( + i2c_instance_t * this_i2c_channel, + i2c_instance_t * this_i2c, + i2c_channel_number_t channel_number, + i2c_clock_divider_t ser_clock_speed +) +{ + psr_t saved_psr; + uint_fast16_t clock_speed = (uint_fast16_t)ser_clock_speed; + + HAL_ASSERT(channel_number < I2C_MAX_CHANNELS); + HAL_ASSERT(I2C_CHANNEL_0 != channel_number); + + /* + * Cannot allow channel 0 in this function as we will trash the hardware + * base address and slave address. + */ + if ((channel_number < I2C_MAX_CHANNELS) && + (I2C_CHANNEL_0 != channel_number)) + { + /* + * We need to disable ints while doing this as the hardware should already + * be active at this stage. + */ + + saved_psr=HAL_disable_interrupts(); + /* + * Initialize channel data. + */ + memset(this_i2c_channel, 0, sizeof(i2c_instance_t)); + + this_i2c_channel->base_address = + ((this_i2c->base_address) & ~((addr_t)CHANNEL_MASK)) + | (((addr_t)channel_number) << CHANNEL_BASE_SHIFT); + + this_i2c_channel->ser_address = this_i2c->ser_address; + + HAL_set_8bit_reg_field(this_i2c_channel->base_address, ENS1, 0x00); /* Reset I2C channel hardware. */ + HAL_set_8bit_reg_field(this_i2c_channel->base_address, ENS1, 0x01); /* set enable bit */ + HAL_set_8bit_reg_field(this_i2c_channel->base_address, CR2, ( (clock_speed >> 2) & 0x01) ); + HAL_set_8bit_reg_field(this_i2c_channel->base_address, CR1, ( (clock_speed >> 1) & 0x01) ); + HAL_set_8bit_reg_field(this_i2c_channel->base_address, CR0, ( clock_speed & 0x01) ); + /* + * Finally safe to enable interrupts. + */ + + HAL_restore_interrupts( saved_psr ); + } +} + +/*------------------------------------------------------------------------------ + * I2C_write() + * See "core_i2c.h" for details of how to use this function. + */ +void I2C_write +( + i2c_instance_t * this_i2c, + uint8_t serial_addr, + const uint8_t * write_buffer, + uint16_t write_size, + uint8_t options +) +{ + psr_t saved_psr; + volatile uint8_t stat_ctrl; + + + saved_psr=HAL_disable_interrupts(); + + /* Update the transaction only when there is no transaction going on I2C */ + if( this_i2c->transaction == NO_TRANSACTION) + { + this_i2c->transaction = MASTER_WRITE_TRANSACTION; + } + + /* Update the Pending transaction information so that transaction can restarted */ + this_i2c->pending_transaction = MASTER_WRITE_TRANSACTION ; + + /* Update target address */ + this_i2c->target_addr = (uint_fast8_t)serial_addr << 1u; + this_i2c->dir = WRITE_DIR; + this_i2c->master_tx_buffer = write_buffer; + this_i2c->master_tx_size = write_size; + this_i2c->master_tx_idx = 0u; + + /* Set I2C status in progress */ + this_i2c->master_status = I2C_IN_PROGRESS; + this_i2c->options = options; + + if(I2C_IN_PROGRESS == this_i2c->slave_status) + { + this_i2c->is_transaction_pending = 1u; + } + else + { + HAL_set_8bit_reg_field(this_i2c->base_address, STA, 0x01u); + } + + /* + * Clear interrupts if required (depends on repeated starts). + * Since the Bus is on hold, only then prior status needs to + * be cleared. + */ + if ( I2C_HOLD_BUS == this_i2c->bus_status ) + { + HAL_set_8bit_reg_field(this_i2c->base_address, SI, 0x00u); + } + + stat_ctrl = HAL_get_8bit_reg( this_i2c->base_address, STATUS); + stat_ctrl = stat_ctrl; /* Avoids lint warning. */ + + /* Enable the interrupt. ( Re-enable) */ + I2C_enable_irq( this_i2c ); + + + HAL_restore_interrupts(saved_psr); +} + +/*------------------------------------------------------------------------------ + * I2C_read() + * See "core_i2c.h" for details of how to use this function. + */ +void I2C_read +( + i2c_instance_t * this_i2c, + uint8_t serial_addr, + uint8_t * read_buffer, + uint16_t read_size, + uint8_t options +) +{ + psr_t saved_psr; + volatile uint8_t stat_ctrl; + + + saved_psr=HAL_disable_interrupts(); + + /* Update the transaction only when there is no transaction going on I2C */ + if( this_i2c->transaction == NO_TRANSACTION) + { + this_i2c->transaction = MASTER_READ_TRANSACTION; + } + + /* Update the Pending transaction information so that transaction can restarted */ + this_i2c->pending_transaction = MASTER_READ_TRANSACTION ; + + /* Update target address */ + this_i2c->target_addr = (uint_fast8_t)serial_addr << 1u; + + this_i2c->dir = READ_DIR; + + this_i2c->master_rx_buffer = read_buffer; + this_i2c->master_rx_size = read_size; + this_i2c->master_rx_idx = 0u; + + /* Set I2C status in progress */ + this_i2c->master_status = I2C_IN_PROGRESS; + + this_i2c->options = options; + + if(I2C_IN_PROGRESS == this_i2c->slave_status) + { + this_i2c->is_transaction_pending = 1u; + } + else + { + HAL_set_8bit_reg_field(this_i2c->base_address, STA, 0x01u); + } + + /* + * Clear interrupts if required (depends on repeated starts). + * Since the Bus is on hold, only then prior status needs to + * be cleared. + */ + if ( I2C_HOLD_BUS == this_i2c->bus_status ) + { + HAL_set_8bit_reg_field(this_i2c->base_address, SI, 0x00u); + } + + stat_ctrl = HAL_get_8bit_reg( this_i2c->base_address, STATUS); + stat_ctrl = stat_ctrl; /* Avoids lint warning. */ + + /* Enable the interrupt. ( Re-enable) */ + I2C_enable_irq( this_i2c ); + + HAL_restore_interrupts( saved_psr ); + +} + +/*------------------------------------------------------------------------------ + * I2C_write_read() + * See "core_i2c.h" for details of how to use this function. + */ +void I2C_write_read +( + i2c_instance_t * this_i2c, + uint8_t serial_addr, + const uint8_t * addr_offset, + uint16_t offset_size, + uint8_t * read_buffer, + uint16_t read_size, + uint8_t options +) +{ + HAL_ASSERT(offset_size > 0u); + HAL_ASSERT(addr_offset != (uint8_t *)0); + HAL_ASSERT(read_size > 0u); + HAL_ASSERT(read_buffer != (uint8_t *)0); + + this_i2c->master_status = I2C_FAILED; + + if((read_size > 0u) && (offset_size > 0u)) + { + psr_t saved_psr; + volatile uint8_t stat_ctrl; + + + saved_psr=HAL_disable_interrupts(); + + /* Update the transaction only when there is no transaction going on I2C */ + if( this_i2c->transaction == NO_TRANSACTION) + { + this_i2c->transaction = MASTER_RANDOM_READ_TRANSACTION; + } + + /* Update the Pending transaction information so that transaction can restarted */ + this_i2c->pending_transaction = MASTER_RANDOM_READ_TRANSACTION ; + + /* Update target address */ + this_i2c->target_addr = (uint_fast8_t)serial_addr << 1u; + + this_i2c->dir = WRITE_DIR; + + this_i2c->master_tx_buffer = addr_offset; + this_i2c->master_tx_size = offset_size; + this_i2c->master_tx_idx = 0u; + + this_i2c->master_rx_buffer = read_buffer; + this_i2c->master_rx_size = read_size; + this_i2c->master_rx_idx = 0u; + + /* Set I2C status in progress */ + this_i2c->master_status = I2C_IN_PROGRESS; + this_i2c->options = options; + + if(I2C_IN_PROGRESS == this_i2c->slave_status) + { + this_i2c->is_transaction_pending = 1u; + } + else + { + HAL_set_8bit_reg_field(this_i2c->base_address, STA, 0x01u); + } + + /* + * Clear interrupts if required (depends on repeated starts). + * Since the Bus is on hold, only then prior status needs to + * be cleared. + */ + if ( I2C_HOLD_BUS == this_i2c->bus_status ) + { + HAL_set_8bit_reg_field(this_i2c->base_address, SI, 0x00u); + } + + stat_ctrl = HAL_get_8bit_reg( this_i2c->base_address, STATUS); + stat_ctrl = stat_ctrl; /* Avoids lint warning. */ + + /* Enable the interrupt. ( Re-enable) */ + I2C_enable_irq( this_i2c ); + + + HAL_restore_interrupts( saved_psr ); + } +} + +/*------------------------------------------------------------------------------ + * I2C_get_status() + * See "core_i2c.h" for details of how to use this function. + */ +i2c_status_t I2C_get_status +( + i2c_instance_t * this_i2c +) +{ + i2c_status_t i2c_status ; + + i2c_status = this_i2c->master_status ; + + return i2c_status; +} + +/*------------------------------------------------------------------------------ + * I2C_wait_complete() + * See "core_i2c.h" for details of how to use this function. + */ +i2c_status_t I2C_wait_complete +( + i2c_instance_t * this_i2c, + uint32_t timeout_ms +) +{ + i2c_status_t i2c_status; + psr_t saved_psr; + /* + * Because we have no idea of what CPU we are supposed to be running on + * we need to guard this write to the timeout value to avoid ISR/user code + * interaction issues. Checking the status below should be fine as only a + * single byte should change in that. + */ + + saved_psr=HAL_disable_interrupts(); + this_i2c->master_timeout_ms = timeout_ms; + + HAL_restore_interrupts( saved_psr ); + + /* Run the loop until state returns I2C_FAILED or I2C_SUCESS*/ + do { + i2c_status = this_i2c->master_status; + } while(I2C_IN_PROGRESS == i2c_status); + return i2c_status; +} + +/*------------------------------------------------------------------------------ + * I2C_system_tick() + * See "core_i2c.h" for details of how to use this function. + */ +void I2C_system_tick +( + i2c_instance_t * this_i2c, + uint32_t ms_since_last_tick +) +{ + if(this_i2c->master_timeout_ms != I2C_NO_TIMEOUT) + { + if(this_i2c->master_timeout_ms > ms_since_last_tick) + { + this_i2c->master_timeout_ms -= ms_since_last_tick; + } + else + { + psr_t saved_psr; + /* + * We need to disable interrupts here to ensure we can update the + * shared data without the I2C ISR interrupting us. + */ + + saved_psr=HAL_disable_interrupts(); + + /* + * Mark current transaction as having timed out. + */ + this_i2c->master_status = I2C_TIMED_OUT; + this_i2c->transaction = NO_TRANSACTION; + this_i2c->is_transaction_pending = 0; + + + HAL_restore_interrupts( saved_psr ); + + /* + * Make sure we do not incorrectly signal a timeout for subsequent + * transactions. + */ + this_i2c->master_timeout_ms = I2C_NO_TIMEOUT; + } + } +} + +/*------------------------------------------------------------------------------ + * I2C_set_slave_tx_buffer() + * See "core_i2c.h" for details of how to use this function. + */ +void I2C_set_slave_tx_buffer +( + i2c_instance_t * this_i2c, + const uint8_t * tx_buffer, + uint16_t tx_size +) +{ + psr_t saved_psr; + + /* + * We need to disable interrupts here to ensure we can update the + * shared data without the I2C ISR interrupting us. + */ + + saved_psr=HAL_disable_interrupts(); + + this_i2c->slave_tx_buffer = tx_buffer; + this_i2c->slave_tx_size = tx_size; + this_i2c->slave_tx_idx = 0u; + + + HAL_restore_interrupts( saved_psr ); +} + +/*------------------------------------------------------------------------------ + * I2C_set_slave_rx_buffer() + * See "core_i2c.h" for details of how to use this function. + */ +void I2C_set_slave_rx_buffer +( + i2c_instance_t * this_i2c, + uint8_t * rx_buffer, + uint16_t rx_size +) +{ + psr_t saved_psr; + + /* + * We need to disable interrupts here to ensure we can update the + * shared data without the I2C ISR interrupting us. + */ + + saved_psr=HAL_disable_interrupts(); + + this_i2c->slave_rx_buffer = rx_buffer; + this_i2c->slave_rx_size = rx_size; + this_i2c->slave_rx_idx = 0u; + + + HAL_restore_interrupts( saved_psr ); +} + +/*------------------------------------------------------------------------------ + * I2C_set_slave_mem_offset_length() + * See "core_i2c.h" for details of how to use this function. + */ +void I2C_set_slave_mem_offset_length +( + i2c_instance_t * this_i2c, + uint8_t offset_length +) +{ + HAL_ASSERT(offset_length <= MAX_OFFSET_LENGTH); + + /* + * Single byte update, should be interrupt safe + */ + if(offset_length > MAX_OFFSET_LENGTH) + { + this_i2c->slave_mem_offset_length = MAX_OFFSET_LENGTH; + } + else + { + this_i2c->slave_mem_offset_length = offset_length; + } +} + +/*------------------------------------------------------------------------------ + * I2C_register_write_handler() + * See "core_i2c.h" for details of how to use this function. + */ +void I2C_register_write_handler +( + i2c_instance_t * this_i2c, + i2c_slave_wr_handler_t handler +) +{ + psr_t saved_psr; + + /* + * We need to disable interrupts here to ensure we can update the + * shared data without the I2C ISR interrupting us. + */ + + saved_psr=HAL_disable_interrupts(); + + this_i2c->slave_write_handler = handler; + + + HAL_restore_interrupts( saved_psr ); +} + +/*------------------------------------------------------------------------------ + * I2C_enable_slave() + * See "core_i2c.h" for details of how to use this function. + */ +void I2C_enable_slave +( + i2c_instance_t * this_i2c +) +{ + psr_t saved_psr; + + /* + * We need to disable interrupts here to ensure we can update the + * hardware register and slave mode flag without the I2C ISR interrupting + * us. + */ + + saved_psr=HAL_disable_interrupts(); + + /* Set the Assert Acknowledge bit. */ + HAL_set_8bit_reg_field(this_i2c->base_address, AA, 0x01u); + + /* Enable slave mode */ + this_i2c->is_slave_enabled = 1u; + + + HAL_restore_interrupts( saved_psr ); + + /* Enable I2C IRQ*/ + I2C_enable_irq( this_i2c ); +} + +/*------------------------------------------------------------------------------ + * I2C_disable_slave() + * See "core_i2c.h" for details of how to use this function. + */ +void I2C_disable_slave +( + i2c_instance_t * this_i2c +) +{ + psr_t saved_psr; + + /* + * We need to disable interrupts here to ensure we can update the + * hardware register without the I2C ISR interrupting us. + */ + + saved_psr=HAL_disable_interrupts(); + + /* Reset the assert acknowledge bit. */ + HAL_set_8bit_reg_field(this_i2c->base_address, AA, 0x00u); + + /* Disable slave mode with IRQ blocked to make whole change atomic */ + this_i2c->is_slave_enabled = 0u; + + + HAL_restore_interrupts( saved_psr ); +} + +/*------------------------------------------------------------------------------ + * + */ +static void enable_slave_if_required +( + i2c_instance_t * this_i2c +) +{ + /* + * This function is only called from within the ISR and so does not need + * guarding on the register access. + */ + if( 0 != this_i2c->is_slave_enabled ) + { + HAL_set_8bit_reg_field( this_i2c->base_address, AA, 0x01u ); + } +} +/*------------------------------------------------------------------------------ + * I2C_set_slave_second_addr() + * See "i2c.h" for details of how to use this function. + */ +void I2C_set_slave_second_addr +( + i2c_instance_t * this_i2c, + uint8_t second_slave_addr +) +{ + uint8_t second_slave_address; + + /* + This function does not support CoreI2C hardware configured with a fixed + second slave address. The current implementation of the ADDR1[0] register + bit makes it difficult for the driver to support both programmable and + fixed second slave address, so we choose to support programmable only. + With the programmable configuration, ADDR1[0] and ADDR0[0] both control + enable/disable of GCA recognition, as an effective OR of the 2 bit fields. + Therefore we set ADDR1[0] to 0 here, so that only ADDR0[0] controls GCA. + */ + second_slave_address = (uint8_t)((second_slave_addr << 1u) & (~SLAVE1_EN_MASK)); + + /* + * Single byte register write, should be interrupt safe + */ + HAL_set_8bit_reg(this_i2c->base_address, ADDRESS1, second_slave_address); +} + +/*------------------------------------------------------------------------------ + * I2C_disable_slave_second_addr() + * See "i2c.h" for details of how to use this function. + */ +void I2C_disable_slave_second_addr +( + i2c_instance_t * this_i2c +) +{ + /* + We are disabling the second slave address by setting the value of the 2nd + slave address to the primary slave address. The reason for using this method + of disabling 2nd slave address is that ADDRESS1[0] has different meaning + depending on hardware configuration. Its use would likely interfere with + the intended GCA setting. + */ + /* + * Single byte register write, should be interrupt safe + */ + HAL_set_8bit_reg(this_i2c->base_address, ADDRESS1, this_i2c->ser_address); +} + +/*------------------------------------------------------------------------------ + * i2C_set_gca() + * See "i2c.h" for details of how to use this function. + */ + +void I2C_set_gca +( + i2c_instance_t * this_i2c +) +{ + /* + * This read modify write access should be interrupt safe as the address + * register is not written to in the ISR. + */ + /* accept GC addressing. */ + HAL_set_8bit_reg_field(this_i2c->base_address, GC, 0x01u); +} + +/*------------------------------------------------------------------------------ + * I2C_clear_gca() + * See "i2c.h" for details of how to use this function. + */ +void I2C_clear_gca +( + i2c_instance_t * this_i2c +) +{ + /* + * This read modify write access should be interrupt safe as the address + * register is not written to in the ISR. + */ + /* Clear GC addressing. */ + HAL_set_8bit_reg_field(this_i2c->base_address, GC, 0x00u); +} + +/*------------------------------------------------------------------------------ + * I2C_isr() + * See "core_i2c.h" for details of how to use this function. + */ +void I2C_isr +( + i2c_instance_t * this_i2c +) +{ + volatile uint8_t status; + uint8_t data; + uint8_t hold_bus; + uint8_t clear_irq = 1u; + + status = HAL_get_8bit_reg( this_i2c->base_address, STATUS); + + switch( status ) + { + /************** MASTER TRANSMITTER / RECEIVER *******************/ + + case ST_START: /* start has been xmt'd */ + case ST_RESTART: /* repeated start has been xmt'd */ + //write_hex(STDOUT_FILENO, status); + HAL_set_8bit_reg_field( this_i2c->base_address, STA, 0x00u); + HAL_set_8bit_reg( this_i2c->base_address, DATA, this_i2c->target_addr); /* write call address */ + HAL_set_8bit_reg_field( this_i2c->base_address, DIR, this_i2c->dir); /* set direction bit */ + if(this_i2c->dir == WRITE_DIR) + { + this_i2c->master_tx_idx = 0u; + } + else + { + this_i2c->master_rx_idx = 0u; + } + + /* + * Clear the pending transaction. This condition will be true if the slave + * has acquired the bus to carry out pending master transaction which + * it had received during its slave transmission or reception mode. + */ + if(this_i2c->is_transaction_pending) + { + this_i2c->is_transaction_pending = 0u; + } + + /* + * Make sure to update proper transaction after master START + * or RESTART + */ + if(this_i2c->transaction != this_i2c->pending_transaction) + { + this_i2c->transaction = this_i2c->pending_transaction; + } + break; + + case ST_LOST_ARB: + /* Set start bit. Let's keep trying! Don't give up! */ + HAL_set_8bit_reg_field(this_i2c->base_address, STA, 0x01u); + break; + + case ST_STOP_TRANSMIT: + /* Stop has been transmitted. Do nothing */ + break; + + /******************* MASTER TRANSMITTER *************************/ + case ST_SLAW_NACK: + //write_hex(STDOUT_FILENO, status); + /* SLA+W has been transmitted; not ACK has been received - let's stop. */ + HAL_set_8bit_reg_field(this_i2c->base_address, STO, 0x01u); + this_i2c->master_status = I2C_FAILED; + this_i2c->transaction = NO_TRANSACTION; + enable_slave_if_required(this_i2c); + break; + + case ST_SLAW_ACK: + case ST_TX_DATA_ACK: + //write_hex(STDOUT_FILENO, status); + /* data byte has been xmt'd with ACK, time to send stop bit or repeated start. */ + if (this_i2c->master_tx_idx < this_i2c->master_tx_size) + { + HAL_set_8bit_reg(this_i2c->base_address, DATA, (uint_fast8_t)this_i2c->master_tx_buffer[this_i2c->master_tx_idx++]); + } + else if ( this_i2c->transaction == MASTER_RANDOM_READ_TRANSACTION ) + { + /* We are finished sending the address offset part of a random read transaction. + * It is is time to send a restart in order to change direction. */ + this_i2c->dir = READ_DIR; + HAL_set_8bit_reg_field(this_i2c->base_address, STA, 0x01u); + } + else /* done sending. let's stop */ + { + /* + * Set the transaction back to NO_TRANSACTION to allow user to do further + * transaction + */ + this_i2c->transaction = NO_TRANSACTION; + hold_bus = this_i2c->options & I2C_HOLD_BUS; + + /* Store the information of current I2C bus status in the bus_status*/ + this_i2c->bus_status = hold_bus; + if ( hold_bus == 0u ) + { + HAL_set_8bit_reg_field(this_i2c->base_address, STO, 0x01u); /*xmt stop condition */ + enable_slave_if_required(this_i2c); + } + else + { + I2C_disable_irq( this_i2c ); + clear_irq = 0u; + } + this_i2c->master_status = I2C_SUCCESS; + } + break; + + case ST_TX_DATA_NACK: + //write_hex(STDOUT_FILENO, status); + /* data byte SENT, ACK to be received + * In fact, this means we've received a NACK (This may not be + * obvious, but if we've rec'd an ACK then we would be in state + * 0x28!) hence, let's send a stop bit + */ + HAL_set_8bit_reg_field(this_i2c->base_address, STO, 0x01u);/* xmt stop condition */ + this_i2c->master_status = I2C_FAILED; + + /* + * Set the transaction back to NO_TRANSACTION to allow user to do further + * transaction + */ + this_i2c->transaction = NO_TRANSACTION; + enable_slave_if_required(this_i2c); + break; + + /********************* MASTER (or slave?) RECEIVER *************************/ + + /* STATUS codes 08H, 10H, 38H are all covered in MTX mode */ + case ST_SLAR_ACK: /* SLA+R tx'ed. */ +// //write_hex(STDOUT_FILENO, status); + /* Let's make sure we ACK the first data byte received (set AA bit in CTRL) unless + * the next byte is the last byte of the read transaction. + */ + if(this_i2c->master_rx_size > 1u) + { + HAL_set_8bit_reg_field(this_i2c->base_address, AA, 0x01u); + } + else if(1u == this_i2c->master_rx_size) + { + HAL_set_8bit_reg_field(this_i2c->base_address, AA, 0x00u); + } + else /* this_i2c->master_rx_size == 0u */ + { + HAL_set_8bit_reg_field(this_i2c->base_address, AA, 0x01u); + HAL_set_8bit_reg_field(this_i2c->base_address, STO, 0x01u); + this_i2c->master_status = I2C_SUCCESS; + this_i2c->transaction = NO_TRANSACTION; + } + break; + + case ST_SLAR_NACK: /* SLA+R tx'ed; let's release the bus (send a stop condition) */ +// //write_hex(STDOUT_FILENO, status); + HAL_set_8bit_reg_field(this_i2c->base_address, STO, 0x01u); + this_i2c->master_status = I2C_FAILED; + + /* + * Set the transaction back to NO_TRANSACTION to allow user to do further + * transaction + */ + this_i2c->transaction = NO_TRANSACTION; + enable_slave_if_required(this_i2c); + break; + + case ST_RX_DATA_ACK: /* Data byte received, ACK returned */ +// //write_hex(STDOUT_FILENO, status); + /* First, get the data */ + this_i2c->master_rx_buffer[this_i2c->master_rx_idx++] = HAL_get_8bit_reg(this_i2c->base_address, DATA); + if( this_i2c->master_rx_idx >= (this_i2c->master_rx_size - 1u)) + { + /* If we're at the second last byte, let's set AA to 0 so + * we return a NACK at the last byte. */ + HAL_set_8bit_reg_field(this_i2c->base_address, AA, 0x00u); + } + break; + + case ST_RX_DATA_NACK: /* Data byte received, NACK returned */ +// //write_hex(STDOUT_FILENO, status); + /* Get the data, then send a stop condition */ + this_i2c->master_rx_buffer[this_i2c->master_rx_idx] = HAL_get_8bit_reg(this_i2c->base_address, DATA); + + hold_bus = this_i2c->options & I2C_HOLD_BUS; + + /* Store the information of current I2C bus status in the bus_status*/ + this_i2c->bus_status = hold_bus; + if ( hold_bus == 0u ) + { + HAL_set_8bit_reg_field(this_i2c->base_address, STO, 0x01u); /*xmt stop condition */ + + /* Bus is released, now we can start listening to bus, if it is slave */ + enable_slave_if_required(this_i2c); + } + else + { + I2C_disable_irq( this_i2c ); + clear_irq = 0u; + } + /* + * Set the transaction back to NO_TRANSACTION to allow user to do further + * transaction + */ + this_i2c->transaction = NO_TRANSACTION; + this_i2c->master_status = I2C_SUCCESS; + break; + + /******************** SLAVE RECEIVER **************************/ + case ST_GCA_NACK: /* NACK after, GCA addressing */ + case ST_SLA_NACK: /* Re-enable AA (assert ack) bit for future transmissions */ + //write_hex(STDOUT_FILENO, status); + HAL_set_8bit_reg_field(this_i2c->base_address, AA, 0x01u); + + this_i2c->transaction = NO_TRANSACTION; + this_i2c->slave_status = I2C_SUCCESS; + + /* Check if transaction was pending. If yes, set the START bit */ + if(this_i2c->is_transaction_pending) + { + HAL_set_8bit_reg_field(this_i2c->base_address, STA, 0x01u); + } + break; + + case ST_GCA_LA: /* Arbitr. lost (GCA rec'd) */ + case ST_SLV_LA: /* Arbitr. lost (SLA rec'd) */ + //write_hex(STDOUT_FILENO, status); + /* + * We lost arbitration and either the GCE or our address was the + * one received so pend the master operation we were starting. + */ + this_i2c->is_transaction_pending = 1u; + /* Fall through to normal ST processing as we are now in slave mode */ + + case ST_GCA: /* General call address received, ACK returned */ + case ST_SLAVE_SLAW: /* SLA+W received, ACK returned */ + //write_hex(STDOUT_FILENO, status); + this_i2c->transaction = WRITE_SLAVE_TRANSACTION; + this_i2c->slave_rx_idx = 0u; + this_i2c->random_read_addr = 0u; + /* + * If Start Bit is set clear it, but store that information since it is because of + * pending transaction + */ + if(HAL_get_8bit_reg_field(this_i2c->base_address, STA)) + { + HAL_set_8bit_reg_field(this_i2c->base_address, STA, 0x00u); + this_i2c->is_transaction_pending = 1u; + } + this_i2c->slave_status = I2C_IN_PROGRESS; +#ifdef INCLUDE_SLA_IN_RX_PAYLOAD + /* Fall through to put address as first byte in payload buffer */ +#else + /* Only break from this case if the slave address must NOT be included at the + * beginning of the received write data. */ + break; +#endif + case ST_GCA_ACK: /* DATA received; ACK sent after GCA */ + case ST_RDATA: /* DATA received; must clear DATA register */ + //write_hex(STDOUT_FILENO, status); + if((this_i2c->slave_rx_buffer != (uint8_t *)0) + && (this_i2c->slave_rx_idx < this_i2c->slave_rx_size)) + { + data = HAL_get_8bit_reg(this_i2c->base_address, DATA); + this_i2c->slave_rx_buffer[this_i2c->slave_rx_idx++] = data; + +#ifdef INCLUDE_SLA_IN_RX_PAYLOAD + if((ST_RDATA == status) || (ST_GCA_ACK == status)) + { + /* Ignore the slave address byte in the random read address + computation in the case where INCLUDE_SLA_IN_RX_PAYLOAD + is defined. */ +#endif + this_i2c->random_read_addr = (this_i2c->random_read_addr << 8) + data; +#ifdef INCLUDE_SLA_IN_RX_PAYLOAD + } +#endif + } + + if(this_i2c->slave_rx_idx >= this_i2c->slave_rx_size) + { + /* Rx buffer is full. NACK next received byte. */ + HAL_set_8bit_reg_field(this_i2c->base_address, AA, 0x00u); + } + break; + + case ST_RSTOP: + //write_hex(STDOUT_FILENO, status); + /* STOP or repeated START occurred. */ + /* We cannot be sure if the transaction has actually completed as + * this hardware state reports that either a STOP or repeated START + * condition has occurred. We assume that this is a repeated START + * if the transaction was a write from the master to this point.*/ + if ( this_i2c->transaction == WRITE_SLAVE_TRANSACTION ) + { + if ( this_i2c->slave_rx_idx == this_i2c->slave_mem_offset_length ) + { + this_i2c->slave_tx_idx = this_i2c->random_read_addr; + } + /* Call the slave's write transaction handler if it exists. */ + if ( this_i2c->slave_write_handler != 0u ) + { + i2c_slave_handler_ret_t h_ret; + h_ret = this_i2c->slave_write_handler( this_i2c, this_i2c->slave_rx_buffer, (uint16_t)this_i2c->slave_rx_idx ); + if ( I2C_REENABLE_SLAVE_RX == h_ret ) + { + /* There is a small risk that the write handler could + * call I2C_disable_slave() but return + * I2C_REENABLE_SLAVE_RX in error so we only enable + * ACKs if still in slave mode. */ + enable_slave_if_required(this_i2c); + } + else + { + HAL_set_8bit_reg_field( this_i2c->base_address, AA, 0x0u ); + /* Clear slave mode flag as well otherwise in mixed + * master/slave applications, the AA bit will get set by + * subsequent master operations. */ + this_i2c->is_slave_enabled = 0u; + } + } + else + { + /* Re-enable address acknowledge in case we were ready to nack the next received byte. */ + HAL_set_8bit_reg_field( this_i2c->base_address, AA, 0x01u ); + } + } + else /* A stop or repeated start outside a write/read operation */ + { + /* + * Reset slave_tx_idx so that a subsequent read will result in the slave's + * transmit buffer being sent from the first byte. + */ + this_i2c->slave_tx_idx = 0u; + /* + * See if we need to re-enable acknowledgement as some error conditions, such + * as a master prematurely ending a transfer, can see us get here with AA set + * to 0 which will disable slave operation if we are not careful. + */ + enable_slave_if_required(this_i2c); + } + + /* Mark any previous master write transaction as complete. */ + this_i2c->slave_status = I2C_SUCCESS; + + /* Check if transaction was pending. If yes, set the START bit */ + if(this_i2c->is_transaction_pending) + { + HAL_set_8bit_reg_field(this_i2c->base_address, STA, 0x01u); + } + + /* + * Set the transaction back to NO_TRANSACTION to allow user to do further + * transaction + */ + this_i2c->transaction = NO_TRANSACTION; + + break; + + case ST_SLV_RST: /* SMBUS ONLY: timeout state. must clear interrupt */ + //write_hex(STDOUT_FILENO, status); + /* + * Set the transaction back to NO_TRANSACTION to allow user to do further + * transaction. + */ + this_i2c->transaction = NO_TRANSACTION; + /* + * Reset slave_tx_idx so that a subsequent read will result in the slave's + * transmit buffer being sent from the first byte. + */ + this_i2c->slave_tx_idx = 0u; + /* + * Clear status to I2C_FAILED only if there was an operation in progress. + */ + if(I2C_IN_PROGRESS == this_i2c->slave_status) + { + this_i2c->slave_status = I2C_FAILED; + } + + enable_slave_if_required(this_i2c); /* Make sure AA is set correctly */ + + break; + + /****************** SLAVE TRANSMITTER **************************/ + case ST_SLAVE_SLAR_ACK: /* SLA+R received, ACK returned */ + case ST_SLARW_LA: /* Arbitration lost, and: */ + case ST_RACK: /* Data tx'ed, ACK received */ + //write_hex(STDOUT_FILENO, status); + if ( status == ST_SLAVE_SLAR_ACK ) + { + this_i2c->transaction = READ_SLAVE_TRANSACTION; + this_i2c->random_read_addr = 0u; + this_i2c->slave_status = I2C_IN_PROGRESS; + /* If Start Bit is set clear it, but store that information since it is because of + * pending transaction + */ + if(HAL_get_8bit_reg_field(this_i2c->base_address, STA)) + { + HAL_set_8bit_reg_field(this_i2c->base_address, STA, 0x00u); + this_i2c->is_transaction_pending = 1u; + } + } + if (this_i2c->slave_tx_idx >= this_i2c->slave_tx_size) + { + /* Ensure 0xFF is returned to the master when the slave specifies + * an empty transmit buffer. */ + HAL_set_8bit_reg(this_i2c->base_address, DATA, 0xFFu); + } + else + { + /* Load the data the data byte to be sent to the master. */ + HAL_set_8bit_reg(this_i2c->base_address, DATA, (uint_fast8_t)this_i2c->slave_tx_buffer[this_i2c->slave_tx_idx++]); + } + /* Determine if this is the last data byte to send to the master. */ + if (this_i2c->slave_tx_idx >= this_i2c->slave_tx_size) /* last byte? */ + { + HAL_set_8bit_reg_field(this_i2c->base_address, AA, 0x00u); + /* Next read transaction will result in slave's transmit buffer + * being sent from the first byte. */ + this_i2c->slave_tx_idx = 0u; + } + break; + + case ST_SLAVE_RNACK: /* Data byte has been transmitted; not-ACK has been received. */ + case ST_FINAL: /* Last Data byte tx'ed, ACK received */ + //write_hex(STDOUT_FILENO, status); + /* We assume that the transaction will be stopped by the master. + * Reset slave_tx_idx so that a subsequent read will result in the slave's + * transmit buffer being sent from the first byte. */ + this_i2c->slave_tx_idx = 0u; + HAL_set_8bit_reg_field(this_i2c->base_address, AA, 0x01u); + + /* Mark previous state as complete */ + this_i2c->slave_status = I2C_SUCCESS; + /* Check if transaction was pending. If yes, set the START bit */ + if(this_i2c->is_transaction_pending) + { + HAL_set_8bit_reg_field(this_i2c->base_address, STA, 0x01u); + } + /* + * Set the transaction back to NO_TRANSACTION to allow user to do further + * transaction + */ + this_i2c->transaction = NO_TRANSACTION; + + break; + + /* Master Reset has been activated Wait 35 ms for interrupt to be set, + * clear interrupt and proceed to 0xF8 state. */ + case ST_RESET_ACTIVATED: + case ST_BUS_ERROR: /* Bus error during MST or selected slave modes */ + default: + //write_hex(STDOUT_FILENO, status); + /* Some undefined state has encountered. Clear Start bit to make + * sure, next good transaction happen */ + HAL_set_8bit_reg_field(this_i2c->base_address, STA, 0x00u); + /* + * Set the transaction back to NO_TRANSACTION to allow user to do further + * transaction. + */ + this_i2c->transaction = NO_TRANSACTION; + /* + * Reset slave_tx_idx so that a subsequent read will result in the slave's + * transmit buffer being sent from the first byte. + */ + this_i2c->slave_tx_idx = 0u; + /* + * Clear statuses to I2C_FAILED only if there was an operation in progress. + */ + if(I2C_IN_PROGRESS == this_i2c->master_status) + { + this_i2c->master_status = I2C_FAILED; + } + + if(I2C_IN_PROGRESS == this_i2c->slave_status) + { + this_i2c->slave_status = I2C_FAILED; + } + + break; + } + + if ( clear_irq ) + { + /* clear interrupt. */ + HAL_set_8bit_reg_field(this_i2c->base_address, SI, 0x00u); + } + + /* Read the status register to ensure the last I2C registers write took place + * in a system built around a bus making use of posted writes. */ +// status = HAL_get_8bit_reg( this_i2c->base_address, STATUS); +} + +/*------------------------------------------------------------------------------ + * I2C_smbus_init() + * See "i2c.h" for details of how to use this function. + */ + +/* + * SMBSUS_NO = 1 + * SMBALERT_NO = 1 + * SMBus enable = 1 + */ +#define INIT_AND_ENABLE_SMBUS 0x54u +void I2C_smbus_init +( + i2c_instance_t * this_i2c +) +{ + /* + * Single byte register write, should be interrupt safe + */ + /* Enable SMBUS */ + HAL_set_8bit_reg(this_i2c->base_address, SMBUS, INIT_AND_ENABLE_SMBUS); +} + +/*------------------------------------------------------------------------------ + * I2C_enable_smbus_irq() + * See "i2c.h" for details of how to use this function. + */ +void I2C_enable_smbus_irq +( + i2c_instance_t * this_i2c, + uint8_t irq_type +) +{ + psr_t saved_psr; + + /* + * We need to disable interrupts here to ensure we can update the + * hardware register without the SMBUS IRQs interrupting us. + */ + + saved_psr=HAL_disable_interrupts(); + + if ( irq_type & I2C_SMBALERT_IRQ) + { + HAL_set_8bit_reg_field(this_i2c->base_address, SMBALERT_IE, 0x01u); + } + if ( irq_type & I2C_SMBSUS_IRQ) + { + HAL_set_8bit_reg_field(this_i2c->base_address, SMBSUS_IE, 0x01u); + } + + + HAL_restore_interrupts( saved_psr ); +} + +/*------------------------------------------------------------------------------ + * I2C_disable_smbus_irq() + * See "i2c.h" for details of how to use this function. + */ +void I2C_disable_smbus_irq +( + i2c_instance_t * this_i2c, + uint8_t irq_type +) +{ + psr_t saved_psr; + + /* + * We need to disable interrupts here to ensure we can update the + * hardware register without the SMBUS IRQs interrupting us. + */ + + saved_psr=HAL_disable_interrupts(); + + if ( irq_type & I2C_SMBALERT_IRQ) + { + HAL_set_8bit_reg_field(this_i2c->base_address, SMBALERT_IE, 0x00u); + } + if (irq_type & I2C_SMBSUS_IRQ ) + { + HAL_set_8bit_reg_field(this_i2c->base_address, SMBSUS_IE, 0x00u); + } + + + HAL_restore_interrupts( saved_psr ); +} + +/*------------------------------------------------------------------------------ + * I2C_suspend_smbus_slave() + * See "i2c.h" for details of how to use this function. + */ +void I2C_suspend_smbus_slave +( + i2c_instance_t * this_i2c +) +{ + psr_t saved_psr; + + /* + * We need to disable interrupts here to ensure we can update the + * hardware register without the SMBUS IRQs interrupting us. + */ + + saved_psr=HAL_disable_interrupts(); + + HAL_set_8bit_reg_field(this_i2c->base_address, SMBSUS_NO_CONTROL, 0x00u); + + + HAL_restore_interrupts( saved_psr ); +} + +/*------------------------------------------------------------------------------ + * I2C_resume_smbus_slave() + * See "i2c.h" for details of how to use this function. + */ +void I2C_resume_smbus_slave +( + i2c_instance_t * this_i2c +) +{ + psr_t saved_psr; + + /* + * We need to disable interrupts here to ensure we can update the + * hardware register without the SMBUS IRQs interrupting us. + */ + + saved_psr=HAL_disable_interrupts(); + + HAL_set_8bit_reg_field(this_i2c->base_address, SMBSUS_NO_CONTROL, 0x01u); + + + HAL_restore_interrupts( saved_psr ); +} + +/*------------------------------------------------------------------------------ + * I2C_reset_smbus() + * See "i2c.h" for details of how to use this function. + */ +void I2C_reset_smbus +( + i2c_instance_t * this_i2c +) +{ + psr_t saved_psr; + + /* + * We need to disable interrupts here to ensure we can update the + * hardware register without the SMBUS IRQs interrupting us. + */ + + saved_psr=HAL_disable_interrupts(); + HAL_set_8bit_reg_field(this_i2c->base_address, SMBUS_MST_RESET, 0x01u); + + + HAL_restore_interrupts( saved_psr ); +} + +/*------------------------------------------------------------------------------ + * I2C_set_smbus_alert() + * See "i2c.h" for details of how to use this function. + */ +void I2C_set_smbus_alert +( + i2c_instance_t * this_i2c +) +{ + psr_t saved_psr; + + /* + * We need to disable interrupts here to ensure we can update the + * hardware register without the SMBUS IRQs interrupting us. + */ + + saved_psr=HAL_disable_interrupts(); + HAL_set_8bit_reg_field(this_i2c->base_address, SMBALERT_NO_CONTROL, 0x00u); + + + HAL_restore_interrupts( saved_psr ); +} + +/*------------------------------------------------------------------------------ + * I2C_clear_smbus_alert() + * See "i2c.h" for details of how to use this function. + */ +void I2C_clear_smbus_alert +( + i2c_instance_t * this_i2c +) +{ + psr_t saved_psr; + + /* + * We need to disable interrupts here to ensure we can update the + * hardware register without the SMBUS IRQs interrupting us. + */ + + saved_psr=HAL_disable_interrupts(); + + HAL_set_8bit_reg_field(this_i2c->base_address, SMBALERT_NO_CONTROL, 0x01u); + + + HAL_restore_interrupts( saved_psr ); +} + +/*------------------------------------------------------------------------------ + * I2C_get_irq_status() + * See "i2c.h" for details of how to use this function. + */ +uint8_t I2C_get_irq_status +( + i2c_instance_t * this_i2c +) +{ + uint8_t status ; + uint8_t irq_type = I2C_NO_IRQ ; + + status = HAL_get_8bit_reg(this_i2c->base_address, SMBUS); + + if( status & (uint8_t)SMBALERT_NI_STATUS_MASK ) + { + irq_type |= I2C_SMBALERT_IRQ ; + } + + if( status & (uint8_t)SMBSUS_NI_STATUS_MASK ) + { + irq_type |= I2C_SMBSUS_IRQ ; + } + + status = HAL_get_8bit_reg(this_i2c->base_address, CONTROL); + + if( status & (uint8_t)SI_MASK ) + { + irq_type |= I2C_INTR_IRQ ; + } + return(irq_type); +} + +/*------------------------------------------------------------------------------ + * I2C_set_slave_addr2() + * See "i2c.h" for details of how to use this function. + */ +void I2C_set_user_data +( + i2c_instance_t * this_i2c, + void * p_user_data +) +{ + this_i2c->p_user_data = p_user_data ; +} + +/*------------------------------------------------------------------------------ + * I2C_get_user_data() + * See "i2c.h" for details of how to use this function. + */ +void * I2C_get_user_data +( + i2c_instance_t * this_i2c +) +{ + return( this_i2c->p_user_data); +} + +#ifdef __cplusplus +} +#endif + diff --git a/FreeRTOS/Demo/RISC-V_IGLOO2_Creative_SoftConsole/drivers/CoreI2C/core_i2c.h b/FreeRTOS/Demo/RISC-V_IGLOO2_Creative_SoftConsole/drivers/CoreI2C/core_i2c.h new file mode 100644 index 000000000..2b1d5acab --- /dev/null +++ b/FreeRTOS/Demo/RISC-V_IGLOO2_Creative_SoftConsole/drivers/CoreI2C/core_i2c.h @@ -0,0 +1,2280 @@ +/******************************************************************************* + * (c) Copyright 2009-2015 Microsemi SoC Products Group. All rights reserved. + * + * CoreI2C software driver Application Programming Interface. + * This file contains defines and function declarations allowing to interface + * with the CoreI2C software driver. + * + * SVN $Revision: 7984 $ + * SVN $Date: 2015-10-12 12:07:40 +0530 (Mon, 12 Oct 2015) $ + */ +/*=========================================================================*//** + @mainpage CoreI2C Bare Metal Driver. + The CoreI2C bare metal software driver supports I2C master and slave + operations. + + @section intro_sec Introduction + The CoreI2C driver provides a set of functions for controlling the Microsemi + CoreI2C hardware IP. The driver supports up to 16 separate I2C channels per + CoreI2C instance, with common slave address settings shared between channels + on a device. + + Optional features of the CoreI2C allow it operate with I2C based protocols + such as System Management Bus (SMBus), Power Management Bus (PMBus) and + Intelligent Platform Management Interface (IPMI). This driver provides support + for these features when enabled in the CoreI2C IP. + + The major features provided by CoreI2C driver are: + - Support for configuring the I2C channels of each CoreI2C peripheral. + - I2C master operations. + - I2C slave operations. + - SMBus related operations. + + This driver can be used as part of a bare metal system where no operating + system is available. The driver can be adapted for use as part of an + operating system, but the implementation of the adaptation layer between the + driver and the operating system's driver model is outside the scope of this + driver. + + @section hw_dependencies Hardware Flow Dependencies + Your application software should configure the CoreI2C driver through + calls to the I2C_init() function for each CoreI2C instance in the + hardware design. The configuration parameters include the CoreI2C hardware + instance base address and other runtime parameters, such as the I2C serial + clock frequency and I2C device address. + + Once channel 0 of a CoreI2C peripheral has been initialized via I2C_init(), + any additional channels present should be configured by calling + I2C_channel_init() for each of the remaining channels. + + No CoreI2C hardware configuration parameters are used by the driver, apart + from the CoreI2C hardware instance base address. Hence, no additional + configuration files are required to use the driver. + + Interrupt Control + The CoreI2C driver has to enable and disable the generation of interrupts by + CoreI2C at various times when it is operating. This enabling and disabling of + interrupts must be done through the system’s interrupt controller. For that + reason, the method of controlling the CoreI2C interrupt is system specific + and it is necessary to customize the I2C_enable_irq() and I2C_disable_irq() + functions. These functions are found in the file i2c_interrupt.c. Their + default implementation fires an assertion to attract attention to the fact + that these functions must be modified. + + The implementation of the I2C_enable_irq() function should permit interrupts + generated by a CoreI2C instance to interrupt the processor. The implementation + of the I2C_disable_irq() function should prevent interrupts generated by a + CoreI2C instance from interrupting the processor. Please refer to the provided + example projects for a working implementation of these functions. + + The function I2C_register_write_handler() is used to register a write handler + function with the CoreI2C driver that it calls on completion of an I2C write + transaction by the CoreI2C slave. It is your responsibility to create and + register the implementation of this handler function that processes or + trigger the processing of the received data. + + The SMBSUS and SMBALERT interrupts are related to the SMBus interface and are + enabled and disabled through I2C_enable_smbus_irq() and + I2C_disable_smbus_irq() respectively. It is your responsibility to create + interrupt handler functions in your application to get the desired response + for the SMBus interrupts. + + Note: You must include the path to any application header files that are + included in the i2c_interrupt.c file, as an include path in your + project’s compiler settings. The details of how to do this will depend + on your development software. + + SMBus Logic options + SMBus related APIs will not have any effect if in CoreI2C hardware + configuration "Generate SMBus Logic" is not enabled. The APIs which will not + give desired results in case SMBus Logic is disabled are: + + I2C_smbus_init() + I2C_reset_smbus() + I2C_enable_smbus_irq() + I2C_disable_smbus_irq() + I2C_suspend_smbus_slave() + I2C_resume_smbus_slave() + I2C_set_smsbus_alert() + I2C_clear_smsbus_alert() + I2C_get_irq_status() + + Fixed Baud Rate Values + The serial clock frequency parameter passed to the I2C_init() and + I2C_channel_init() functions may not have any effect if fixed values were + selected for Baud rate in the hardware configuration of CoreI2C. When fixed + values are selected for these baud rates, the driver cannot overwrite + the fixed values. + + Fixed Slave Address Options Values + The primary slave address parameter passed to the I2C_init() function, and + secondary address value passed to the I2C_set_slave_second_addr() function, + may not have the desired effect if fixed values were selected for the slave 0 + address and slave 1 address respectively. Proper operation of this version of + the driver requires the slave addresses to be programmable. + + @section theory_op Theory of Operation + The CoreI2C software driver is designed to allow the control of multiple + instances of CoreI2C with one or more I2C channels. Each channel in an + instance of CoreI2C in the hardware design is associated with a single + instance of the i2c_instance_t structure in the software. You must allocate + memory for one unique i2c_instance_t structure instance for each channel of + each CoreI2C hardware instance. The contents of these data structures are + initialised during calls to I2C_init() and if necessary I2C_channel_init(). + A pointer to the structure is passed to subsequent driver functions in order + to identify the CoreI2C hardware instance and channel you wish to perform the + requested operation. + + Note: Do not attempt to directly manipulate the contents of i2c_instance_t + structures. These structures are only intended to be modified by the driver + functions. + + The CoreI2C driver functions are grouped into the following categories: + - Initialization and configuration functions + - Interrupt control + - I2C slave addressing functions + - I2C master operations functions to handle write, read and write-read + transactions + - I2C slave operations functions to handle write, read and write-read + transactions + - Mixed master-slave operations + - SMBus interface configuration and control. + + Initialization and Configuration + The CoreI2C device is first initialized through a call to the I2C_init() + function. Since each CoreI2C peripheral supports up to 16 channels, an + additional function, I2C_channel_init(), is required to initialize the + remaining channels with their own data structures. + + I2C_init() initializes channel 0 of a CoreI2C and the i2c_instance_t for + channel 0 acts as the basis for further channel initialization as the + hardware base address and I2C serial address are same across all the + channels. I2C_init() must be called before any other I2C driver function + calls. The I2C_init() call for each CoreI2C takes the I2C serial address + assigned to the I2C and the serial clock divider to be used to generate its + I2C clock as configuration parameters. + + I2C_channel_init() takes as input parameters a pointer to the CoreI2C + i2c_instance_t which has been initialized via I2C_init() and a pointer to a + separate i2c_instance_t which represents this new channel. Another input + parameter which is required by this function is serial clock divider which + generates its I2C clock. + + Interrupt Control + The CoreI2C driver is interrupt driven and it uses each channels INT + interrupt to drive the state machine which is at the heart of the driver. + The application is responsible for providing the link between the interrupt + generating hardware and the CoreI2C interrupt handler and must ensure that + the I2C_isr() function is called with the correct i2c_instance_t structure + pointer for the CoreI2C channel initiating the interrupt. + + The driver enables and disables the generation of INT interrupts by CoreI2C + at various times when it is operating through the user supplied + I2C_enable_irq() and I2C_disable_irq() functions. + + The function I2C_register_write_handler() is used to register a write + handler function with the CoreI2C driver which is called on completion + of an I2C write transaction by the CoreI2C slave. It is the user + applications responsibility to create and register the implementation of + this handler function that processes or triggers the processing of the + received data. + + The other two interrupt sources in the CoreI2C, are related to SMBus + operation and are enabled and disabled through I2C_enable_smbus_irq() and + I2C_disable_smbus_irq() respectively. Due to the application specific + nature of the response to SMBus interrupts, you must design interrupt + handler functions in the application to get the desired behaviour for + SMBus related interrupts. + + If enabled, the SMBA_INT signal from the CoreI2C is asserted if an + SMBALERT condition is signalled on the SMBALERT_NI input for the channel. + + If enabled, the SMBS_INT signal from the CoreI2C is asserted if an + SMBSUSPEND condition is signalled on the SMBSUS_NI input for the channel. + + I2C slave addressing functions + A CoreI2C peripheral can respond to three slave addresses: + - Slave address 0 - This is the primary slave address which is used for + accessing a CoreI2C channel when it acts as a slave in + I2C transactions. You must configure the primary slave + address via I2C_init(). + + - Slave address 1 - This is the secondary slave address which might be + required in certain application specific scenarios. + The secondary slave address can be configured via + I2C_set_slave_second_addr() and disabled via + I2C_disable_slave_second_addr(). + + - General call address - A CoreI2C slave can be configured to respond to + a broadcast command by a master transmitting the + general call address of 0x00. Use the I2C_set_gca() + function to enable the slave to respond to the general + call address. If the CoreI2C slave is not required to + respond to the general call address, disable this + address by calling I2C_clear_gca(). + + Note: All channels on a CoreI2C instance share the same slave address logic. + This means that they cannot have separate slave addresses and rely on + the separate physical I2C bus connections to distinguish them. + + Transaction Types + The I2C driver is designed to handle three types of I2C transaction: + Write transactions + Read transactions + Write-read transactions + + Write transaction + The master I2C device initiates a write transaction by sending a START bit + as soon as the bus becomes free. The START bit is followed by the 7-bit + serial address of the target slave device followed by the read/write bit + indicating the direction of the transaction. The slave acknowledges the + receipt of it's address with an acknowledge bit. The master sends data one + byte at a time to the slave, which must acknowledge receipt of each byte + for the next byte to be sent. The master sends a STOP bit to complete the + transaction. The slave can abort the transaction by replying with a + non-acknowledge bit instead of an acknowledge. + + The application programmer can choose not to send a STOP bit at the end of + the transaction causing the next transaction to begin with a repeated + START bit. + + Read transaction + The master I2C device initiates a read transaction by sending a START bit + as soon as the bus becomes free. The START bit is followed by the 7-bit + serial address of the target slave device followed by the read/write bit + indicating the direction of the transaction. The slave acknowledges + receipt of it's slave address with an acknowledge bit. The slave sends + data one byte at a time to the master, which must acknowledge receipt of + each byte for the next byte to be sent. The master sends a non-acknowledge + bit following the last byte it wishes to read followed by a STOP bit. + + The application programmer can choose not to send a STOP bit at the end of + the transaction causing the next transaction to begin with a repeated + START bit. + + Write-read transaction + The write-read transaction is a combination of a write transaction + immediately followed by a read transaction. There is no STOP bit between + the write and read phases of a write-read transaction. A repeated START + bit is sent between the write and read phases. + + Whilst the write handler is being executed, the slave holds the clock line + low to stretch the clock until the response is ready. + + The write-read transaction is typically used to send a command or offset + in the write transaction specifying the logical data to be transferred + during the read phase. + + The application programmer can choose not to send a STOP bit at the end of + the transaction causing the next transaction to begin with a repeated + START bit. + + Master Operations + The application can use the I2C_write(), I2C_read() and I2C_write_read() + functions to initiate an I2C bus transaction. The application can then wait + for the transaction to complete using the I2C_wait_complete() function + or poll the status of the I2C transaction using the I2C_get_status() + function until it returns a value different from I2C_IN_PROGRESS. The + I2C_system_tick() function can be used to set a time base for the + I2C_wait_complete() function’s time out delay. + + Slave Operations + The configuration of the I2C driver to operate as an I2C slave requires + the use of the following functions: + I2C_set_slave_tx_buffer() + I2C_set_slave_rx_buffer() + I2C_set_slave_mem_offset_length() + I2C_register_write_handler() + I2C_enable_slave() + + Use of all functions is not required if the slave I2C does not need to support + all types of I2C read transactions. The subsequent sections list the functions + that must be used to support each transaction type. + + Responding to read transactions + The following functions are used to configure the CoreI2C driver to + respond to I2C read transactions: + I2C_set_slave_tx_buffer() + I2C_enable_slave() + + The function I2C_set_slave_tx_buffer() specifies the data buffer that + will be transmitted when the I2C slave is the target of an I2C read + transaction. It is then up to the application to manage the content of + that buffer to control the data that will be transmitted to the I2C + master as a result of the read transaction. + + The function I2C_enable_slave() enables the I2C hardware instance + to respond to I2C transactions. It must be called after the I2C driver + has been configured to respond to the required transaction types. + + Responding to write transactions + The following functions are used to configure the I2C driver to respond + to I2C write transactions: + I2C_set_slave_rx_buffer() + I2C_register_write_handler() + I2C_enable_slave() + + The function I2C_set_slave_rx_buffer() specifies the data buffer that + will be used to store the data received by the I2C slave when it is the + target an I2C write transaction. + + The function I2C_register_write_handler() specifies the handler function + that must be called on completion of the I2C write transaction. It is this + handler function that processes or triggers the processing of the received + data. + + The function I2C_enable_slave() enables the I2C hardware instance + to respond to I2C transactions. It must be called after the I2C driver + has been configured to respond to the required transaction types. + + Responding to write-read transactions + The following functions are used to configure the CoreI2C driver to + respond to write-read transactions: + I2C_set_slave_mem_offset_length() + I2C_set_slave_tx_buffer() + I2C_set_slave_rx_buffer() + I2C_register_write_handler() + I2C_enable_slave() + + The function I2C_set_slave_mem_offset_length() specifies the number of + bytes expected by the I2C slave during the write phase of the write-read + transaction. + + The function I2C_set_slave_tx_buffer() specifies the data that will be + transmitted to the I2C master during the read phase of the write-read + transaction. The value received by the I2C slave during the write phase of + the transaction will be used as an index into the transmit buffer + specified by this function to decide which part of the transmit buffer + will be transmitted to the I2C master as part of the read phase of the + write-read transaction. + + The function I2C_set_slave_rx_buffer() specifies the data buffer that + will be used to store the data received by the I2C slave during the write + phase of the write-read transaction. This buffer must be at least large + enough to accommodate the number of bytes specified through the + I2C_set_slave_mem_offset_length() function. + + The function I2C_register_write_handler() can optionally be used to + specify a handler function that is called on completion of the write phase + of the I2C write-read transaction. If a handler function is registered, it + is responsible for processing the received data in the slave receive + buffer and populating the slave transmit buffer with the data that will be + transmitted to the I2C master as part of the read phase of the write-read + transaction. + + The function I2C_enable_slave() enables the CoreI2C hardware instance to + respond to I2C transactions. It must be called after the CoreI2C driver + has been configured to respond to the required transaction types. + + Mixed Master-Slave Operations + The CoreI2C device supports mixed master and slave operations. If the + CoreI2C slave has a transaction in progress and your application attempts to + begin a master mode transaction, the CoreI2C driver queu3es the master mode + transaction until the bus is released and the CoreI2C can switch to master + mode and acquire the bus. The CoreI2C master then starts the previously + queued master transaction. + + SMBus Control + The CoreI2C driver enables the CoreI2C peripheral’s SMBus functionality + using the I2C_smbus_init() function. + + The I2C_suspend_smbus_slave() function is used, with a master mode CoreI2C, + to force slave devices on the SMBus to enter their power-down/suspend mode. + The I2C_resume_smbus_slave() function is used to end the suspend operation + on the SMBus. + + The I2C_reset_smbus() function is used, with a master mode CoreI2C, to force + all devices on the SMBus to reset their SMBUs interface. + + The I2C_set_smsbus_alert() function is used, by a slave mode CoreI2C, to + force communication with the SMBus master. Once communications with the + master is initiated, the I2C_clear_smsbus_alert() function is used to clear + the alert condition. + + The I2C_enable_smbus_irq() and I2C_disable_smbus_irq() functions are used to + enable and disable the SMBSUS and SMBALERT SMBus interrupts. + + *//*=========================================================================*/ + +#ifndef CORE_I2C_H_ +#define CORE_I2C_H_ + +#include "cpu_types.h" +#ifdef __cplusplus +extern "C" { +#endif + +/*-------------------------------------------------------------------------*//** + The I2C_RELEASE_BUS constant is used to specify the options parameter to + functions I2C_read(), I2C_write() and I2C_write_read() to indicate + that a STOP bit must be generated at the end of the I2C transaction to release + the bus. + */ +#define I2C_RELEASE_BUS 0x00u + +/*-------------------------------------------------------------------------*//** + The I2C_HOLD_BUS constant is used to specify the options parameter to + functions I2C_read(), I2C_write() and I2C_write_read() to indicate + that a STOP bit must not be generated at the end of the I2C transaction in + order to retain the bus ownership. This causes the next transaction to + begin with a repeated START bit and no STOP bit between the transactions. + */ +#define I2C_HOLD_BUS 0x01u + +/*-------------------------------------------------------------------------*//** + The following constants specify the interrupt identifier number which will be + solely used by driver API. This has nothing to do with hardware interrupt line. + I2C_INT_IRQ is the primary interrupt signal which drives the state machine + of the CoreI2C driver. The I2C_SMBALERT_IRQ and I2C_SMBUS_IRQ are used by + SMBus interrupt enable and disable functions. These IRQ numbers are also used + by I2C_get_irq_status(). + */ +#define I2C_NO_IRQ 0x00u +#define I2C_SMBALERT_IRQ 0x01u +#define I2C_SMBSUS_IRQ 0x02u +#define I2C_INTR_IRQ 0x04u + +/*-------------------------------------------------------------------------*//** + The I2C_NO_TIMEOUT constant is used as parameter to the I2C_wait_complete() + function to indicate that the wait for completion of the transaction should + not time out. + */ +#define I2C_NO_TIMEOUT 0u + +/*-------------------------------------------------------------------------*//** + The i2c_channel_number_t type is used to specify the channel number of a + CoreI2C instance. + */ +typedef enum i2c_channel_number { + I2C_CHANNEL_0 = 0u, + I2C_CHANNEL_1, + I2C_CHANNEL_2, + I2C_CHANNEL_3, + I2C_CHANNEL_4, + I2C_CHANNEL_5, + I2C_CHANNEL_6, + I2C_CHANNEL_7, + I2C_CHANNEL_8, + I2C_CHANNEL_9, + I2C_CHANNEL_10, + I2C_CHANNEL_11, + I2C_CHANNEL_12, + I2C_CHANNEL_13, + I2C_CHANNEL_14, + I2C_CHANNEL_15, + I2C_MAX_CHANNELS = 16u +} i2c_channel_number_t; + +/*-------------------------------------------------------------------------*//** + The i2c_clock_divider_t type is used to specify the divider to be applied + to the I2C PCLK or BCLK signal in order to generate the I2C clock. + The I2C_BCLK_DIV_8 value selects a clock frequency based on division of BCLK, + all other values select a clock frequency based on division of PCLK. + */ +typedef enum i2c_clock_divider { + I2C_PCLK_DIV_256 = 0u, + I2C_PCLK_DIV_224, + I2C_PCLK_DIV_192, + I2C_PCLK_DIV_160, + I2C_PCLK_DIV_960, + I2C_PCLK_DIV_120, + I2C_PCLK_DIV_60, + I2C_BCLK_DIV_8 +} i2c_clock_divider_t; + +/*-------------------------------------------------------------------------*//** + The i2c_status_t type is used to report the status of I2C transactions. + */ +typedef enum i2c_status +{ + I2C_SUCCESS = 0u, + I2C_IN_PROGRESS, + I2C_FAILED, + I2C_TIMED_OUT +} i2c_status_t; + +/*-------------------------------------------------------------------------*//** + The i2c_slave_handler_ret_t type is used by slave write handler functions + to indicate whether or not the received data buffer should be released. + */ +typedef enum i2c_slave_handler_ret { + I2C_REENABLE_SLAVE_RX = 0u, + I2C_PAUSE_SLAVE_RX = 1u +} i2c_slave_handler_ret_t; + +typedef struct i2c_instance i2c_instance_t ; + +/*-------------------------------------------------------------------------*//** + Slave write handler functions prototype. + ------------------------------------------------------------------------------ + This defines the function prototype that must be followed by I2C slave write + handler functions. These functions are registered with the CoreI2C driver + through the I2C_register_write_handler() function. + + Declaring and Implementing Slave Write Handler Functions: + Slave write handler functions should follow the following prototype: + i2c_slave_handler_ret_t write_handler + ( + i2c_instance_t *instance, uint8_t * data, uint16_t size + ); + + The instance parameter is a pointer to the i2c_instance_t for which this + slave write handler has been declared. + + The data parameter is a pointer to a buffer (received data buffer) holding + the data written to the I2C slave. + + Defining the macro INCLUDE_SLA_IN_RX_PAYLOAD causes the driver to insert the + actual address used to access the slave as the first byte in the buffer. + This allows applications tailor their response based on the actual address + used to access the slave (primary address, secondary address or GCA). + + The size parameter is the number of bytes held in the received data buffer. + Handler functions must return one of the following values: + I2C_REENABLE_SLAVE_RX + I2C_PAUSE_SLAVE_RX. + + If the handler function returns I2C_REENABLE_SLAVE_RX, the driver releases + the received data buffer and allows further I2C write transactions to the + I2C slave to take place. + + If the handler function returns I2C_PAUSE_SLAVE_RX, the I2C slave responds + to subsequent write requests with a non-acknowledge bit (NACK), until the + received data buffer content has been processed by some other part of the + software application. + + A call to I2C_enable_slave() is required at some point after returning + I2C_PAUSE_SLAVE_RX in order to release the received data buffer so it can + be used to store data received by subsequent I2C write transactions. + */ +typedef i2c_slave_handler_ret_t (*i2c_slave_wr_handler_t)(i2c_instance_t *instance, uint8_t *, uint16_t ); + + +/*-------------------------------------------------------------------------*//** + i2c_instance_t + ------------------------------------------------------------------------------ + This structure is used to identify the various CoreI2C hardware instances in + your system and the I2C channels within them. Your application software should + declare one instance of this structure for each channel of each instance of + CoreI2C in your system. The functions I2C_init() and I2C_channel_init() + initialize this structure depending on whether it is channel 0 or one of the + additional channels respectively. A pointer to an initialized instance of the + structure should be passed as the first parameter to the CoreI2C driver + functions, to identify which CoreI2C hardware instance and channel should + perform the requested operation. + + The contents of this data structure should not be modified or used outside of + the CoreI2C driver. Software using the CoreI2C driver should only need to + create one single instance of this data structure for each channel of each + CoreI2C hardware instance in the system then pass a pointer to these data + structures with each call to the CoreI2C driver in order to identify the + CoreI2C hardware instance it wishes to use. + */ +struct i2c_instance +{ + addr_t base_address; + uint_fast8_t ser_address; + + /* Transmit related info:*/ + uint_fast8_t target_addr; + + /* Current transaction type (WRITE, READ, RANDOM_READ)*/ + uint8_t transaction; + + uint_fast16_t random_read_addr; + + uint8_t options; + + /* Master TX INFO: */ + const uint8_t * master_tx_buffer; + uint_fast16_t master_tx_size; + uint_fast16_t master_tx_idx; + uint_fast8_t dir; + + /* Master RX INFO: */ + uint8_t * master_rx_buffer; + uint_fast16_t master_rx_size; + uint_fast16_t master_rx_idx; + + /* Master Status */ + volatile i2c_status_t master_status; + uint32_t master_timeout_ms; + + /* Slave TX INFO */ + const uint8_t * slave_tx_buffer; + uint_fast16_t slave_tx_size; + uint_fast16_t slave_tx_idx; + + /* Slave RX INFO */ + uint8_t * slave_rx_buffer; + uint_fast16_t slave_rx_size; + uint_fast16_t slave_rx_idx; + /* Slave Status */ + volatile i2c_status_t slave_status; + + /* Slave data: */ + uint_fast8_t slave_mem_offset_length; + i2c_slave_wr_handler_t slave_write_handler; + uint8_t is_slave_enabled; + + /* user specific data */ + void *p_user_data ; + + /* I2C bus status */ + uint8_t bus_status; + + /* Is transaction pending flag */ + uint8_t is_transaction_pending; + + /* I2C Pending transaction */ + uint8_t pending_transaction; +}; + +/*-------------------------------------------------------------------------*//** + I2C initialization routine. + ------------------------------------------------------------------------------ + The I2C_init() function is used to configure channel 0 of a CoreI2C instance. + It sets the base hardware address which is used to locate the CoreI2C instance + in memory and also used internally by I2C_channel_init() to calculate the + register addresses for any additional channels. The slave serial address set + is shared by all channels on a CoreI2C instance. + + If only one channel is configured in a CoreI2C, the address of the + i2c_instance_t used in I2C_Init() will also be used in subsequent calls to the + CoreI2C driver functions. If more than one channel is configured in the + CoreI2C, I2C_channel_init() will be called after I2C_init(), which initializes + the i2c_instance_t data structure for a specific channel. + ------------------------------------------------------------------------------ + @param this_i2c: + Pointer to the i2c_instance_t data structure which will hold all data + related to channel 0 of the CoreI2C instance being initialized. A pointer + to this structure will be used in all subsequent calls to CoreI2C driver + functions which are to operate on channel 0 of this CoreI2C instance. + + @param base_address: + Base address in the processor's memory map of the registers of the CoreI2C + instance being initialized. + + @param ser_address: + This parameter sets the primary I2C serial address (SLAVE0 address) for the + CoreI2C being initialized. It is the principal I2C bus address to which the + CoreI2C instance will respond. CoreI2C can operate in master mode or slave + mode and the serial address is significant only in the case of I2C slave + mode. In master mode, CoreI2C does not require a serial address and the + value of this parameter is not important. If you do not intend to use the + CoreI2C device in slave mode, then any dummy slave address value can be + provided to this parameter. However, in systems where the CoreI2C may be + expected to switch from master mode to slave mode, it is advisable to + initialize the CoreI2C device with a valid serial slave address. + + You need to call the I2C_init() function whenever it is required to change + the primary slave address as there is no separate function to set the + primary slave address of the I2C device. The serial address being + initialized through this function is basically the primary slave address or + slave address0. I2C_set_slave_second_addr() can be used to set the + secondary slave address or slave address 1. + Note : ser_address parameter does not have any affect if fixed slave + address is enabled in CoreI2C hardware design. CoreI2C will + be always addressed with the hardware configured fixed slave + address. + Note : ser_address parameter will not have any affect if the CoreI2C + instance is only used in master mode. + + @param ser_clock_speed: + This parameter sets the I2C serial clock frequency. It selects the divider + that will be used to generate the serial clock from the APB PCLK or from + the BCLK. It can be one of the following: + I2C_PCLK_DIV_256 + I2C_PCLK_DIV_224 + I2C_PCLK_DIV_192 + I2C_PCLK_DIV_160 + I2C_PCLK_DIV_960 + I2C_PCLK_DIV_120 + I2C_PCLK_DIV_60 + I2C_BCLK_DIV_8 + Note: serial_clock_speed value will have no affect if Fixed baud rate is + enabled in CoreI2C hardware instance configuration dialogue window. + The fixed baud rate divider value will override the value + passed as parameter in this function. + Note: serial_clock_speed value is not critical for devices that only operate + as slaves and can be set to any of the above values. + + @return none. + + Example: + @code + #define COREI2C_BASE_ADDR 0xC0000000u + #define COREI2C_SER_ADDR 0x10u + + i2c_instance_t g_i2c_inst; + + void system_init( void ) + { + I2C_init( &g_i2c_inst, COREI2C_BASE_ADDR, COREI2C_SER_ADDR, + I2C_PCLK_DIV_256 ); + } + @endcode + */ +void I2C_init +( + i2c_instance_t * this_i2c, + addr_t base_address, + uint8_t ser_address, + i2c_clock_divider_t ser_clock_speed +); + +/*-------------------------------------------------------------------------*//** + I2C channel initialization routine. + ------------------------------------------------------------------------------ + The I2C_channel_init() function initializes and configures hardware and data + structures of one of the additional channels of a CoreI2C instance. + I2C_init() must be called before calling this function to set the CoreI2C + instance hardware base address and I2C serial address. I2C_channel_init() also + initializes I2C serial clock divider to set the serial clock baud rate. + The pointer to data structure i2c_instance_t used for a particular channel + will be used as an input parameter to subsequent CoreI2C driver functions + which operate on this channel. + ------------------------------------------------------------------------------ + @param this_i2c_channel + Pointer to the i2c_instance_t data structure holding all data related to the + CoreI2C channel being initialized. A pointer to the same data structure will + be used in subsequent calls to the CoreI2C driver functions in order to + identify the CoreI2C channel instance that should perform the operation + implemented by the called driver function. + + @param this_i2c: + This is a pointer to an i2c_instance_t structure previously initialized by + I2C_init(). It holds information regarding the hardware base address and + I2C serial address for the CoreI2C containing the channel to be + initialized. This information is required by I2C_channel_init() to + initialize the i2c_instance_t structure pointed to by this_i2c_channel as + all channels in a CoreI2C instance share the same base address and serial + address. It is very important that the i2c_instance_t structure pointed to + by this_i2c has been previously initialized with a call to I2C_init(). + + @param channel_number: + This parameter of type i2c_channel_number_t identifies the channel to be + initialized. + + @param ser_clock_speed: + This parameter sets the I2C serial clock frequency. It selects the divider + that will be used to generate the serial clock from the APB PCLK or from + the BCLK. It can be one of the following: + I2C_PCLK_DIV_256 + I2C_PCLK_DIV_224 + I2C_PCLK_DIV_192 + I2C_PCLK_DIV_160 + I2C_PCLK_DIV_960 + I2C_PCLK_DIV_120 + I2C_PCLK_DIV_60 + I2C_BCLK_DIV_8 + + Note: serial_clock_speed value will have no affect if Fixed baud rate is + enabled in CoreI2C hardware instance configuration dialogue window. + The fixed baud rate divider value will supersede the value + passed as parameter in this function. + + Note: ser_clock_speed value is not critical for devices that only operate + as slaves and can be set to any of the above values. + @return none. + + Example: + @code + #define COREI2C_BASE_ADDR 0xC0000000u + #define COREI2C_SER_ADDR 0x10u + #define DATA_LENGTH 16u + + i2c_instance_t g_i2c_inst; + i2c_instance_t g_i2c_channel_1_inst; + + uint8_t tx_buffer[DATA_LENGTH]; + uint8_t write_length = DATA_LENGTH; + + void system_init( void ) + { + uint8_t target_slave_addr = 0x12; + + // Initialize base CoreI2C instance + I2C_init( &g_i2c_inst, COREI2C_BASE_ADDR, COREI2C_SER_ADDR, + I2C_PCLK_DIV_256 ); + + // Initialize CoreI2C channel 1 with different clock speed + I2C_channel_init( &g_i2c_channel_1_inst, &g_i2c_inst, I2C_CHANNEL_1, + I2C_PCLK_DIV_224 ); + + // Write data to Channel 1 of CoreI2C instance. + I2C_write( &g_i2c_channel_1_inst, target_slave_addr, tx_buffer, + write_length, I2C_RELEASE_BUS ); + } + @endcode + +*/ +void I2C_channel_init +( + i2c_instance_t * this_i2c_channel, + i2c_instance_t * this_i2c, + i2c_channel_number_t channel_number, + i2c_clock_divider_t ser_clock_speed +); + +/*------------------------------------------------------------------------------ + CoreI2C interrupt service routine. + ------------------------------------------------------------------------------ + The function I2C_isr is the CoreI2C interrupt service routine. User must + call this function from their application level CoreI2C interrupt handler + function. This function runs the I2C state machine based on previous and + current status. + ------------------------------------------------------------------------------ + @param this_i2c: + The this_i2c parameter is a pointer to the i2c_instance_t data structure + holding all data related to a specific CoreI2C channel. For example, if only + one channel is initialized, this data structure holds the information of + channel 0 of the instantiated CoreI2C hardware. + + @return none + + Example: + @code + + #define COREI2C_BASE_ADDR 0xC0000000u + #define COREINTERRUPT_BASE_ADDR 0xCC000000u + #define COREI2C_SER_ADDR 0x10u + #define I2C_IRQ_NB 2u + + i2c_instance_t g_i2c_inst; + + void core_i2c_isr( void ) + { + I2C_isr( &g_i2c_inst ); + } + + void main( void ) + { + CIC_init( COREINTERRUPT_BASE_ADDR ); + NVIC_init(); + CIC_set_irq_handler( I2C_IRQ_NB, core_i2c_isr ); + I2C_init( &g_i2c_inst, COREI2C_BASE_ADDR, COREI2C_SER_ADDR, + I2C_PCLK_DIV_256 ); + NVIC_enable_interrupt( NVIC_IRQ_0 ); + } + @endcode + */ +void I2C_isr +( + i2c_instance_t * this_i2c +); + +/******************************************************************************* + ******************************************************************************* + * + * Master specific functions + * + * The following functions are only used within an I2C master's implementation. + */ + +/*-------------------------------------------------------------------------*//** + I2C master write function. + ------------------------------------------------------------------------------ + This function initiates an I2C master write transaction. This function returns + immediately after initiating the transaction. The content of the write buffer + passed as parameter should not be modified until the write transaction + completes. It also means that the memory allocated for the write buffer should + not be freed or should not go out of scope before the write completes. You can + check for the write transaction completion using the I2C_status() function. + ------------------------------------------------------------------------------ + @param this_i2c: + The this_i2c parameter is a pointer to the i2c_instance_t data structure + holding all data related to a specific CoreI2C channel. For example, if only + one channel is initialized, this data structure holds the information of + channel 0 of the instantiated CoreI2C hardware. + + @param serial_addr: + This parameter specifies the serial address of the target I2C device. + + @param write_buffer: + This parameter is a pointer to a buffer holding the data to be written to + the target I2C device. + Care must be taken not to release the memory used by this buffer before the + write transaction completes. For example, it is not appropriate to return + from a function allocating this buffer as an auto array variable before the + write transaction completes as this would result in the buffer's memory + being de-allocated from the stack when the function returns. This memory + could then be subsequently reused and modified causing unexpected data to + be written to the target I2C device. + + @param write_size: + Number of bytes held in the write_buffer to be written to the target I2C + device. + + @param options: + The options parameter is used to indicate if the I2C bus should be released + on completion of the write transaction. Using the I2C_RELEASE_BUS + constant for the options parameter causes a STOP bit to be generated at the + end of the write transaction causing the bus to be released for other I2C + devices to use. Using the I2C_HOLD_BUS constant as options parameter + prevents a STOP bit from being generated at the end of the write + transaction, preventing other I2C devices from initiating a bus transaction. + + @return none. + + Example: + @code + #define COREI2C_BASE_ADDR 0xC0000000u + #define COREI2C_DUMMY_ADDR 0x10u + #define DATA_LENGTH 16u + + i2c_instance_t g_i2c_inst; + + uint8_t tx_buffer[DATA_LENGTH]; + uint8_t write_length = DATA_LENGTH; + + void main( void ) + { + uint8_t target_slave_addr = 0x12; + i2c_status_t status; + + // Initialize base CoreI2C instance + I2C_init( &g_i2c_inst, COREI2C_BASE_ADDR, COREI2C_DUMMY_ADDR, + I2C_PCLK_DIV_256 ); + + // Write data to Channel 0 of CoreI2C instance. + I2C_write( &g_i2c_inst, target_slave_addr, tx_buffer, write_length, + I2C_RELEASE_BUS ); + + // Wait for completion and record the outcome + status = I2C_wait_complete( &g_i2c_inst, I2C_NO_TIMEOUT ); + } + @endcode + */ +void I2C_write +( + i2c_instance_t * this_i2c, + uint8_t serial_addr, + const uint8_t * write_buffer, + uint16_t write_size, + uint8_t options +); + +/*-------------------------------------------------------------------------*//** + I2C master read. + ------------------------------------------------------------------------------ + This function initiates an I2C master read transaction. This function returns + immediately after initiating the transaction. + The contents of the read buffer passed as parameter should not be modified + until the read transaction completes. It also means that the memory allocated + for the read buffer should not be freed or should not go out of scope before + the read completes. You can check for the read transaction completion using + the I2C_status() function. + ------------------------------------------------------------------------------ + @param this_i2c: + The this_i2c parameter is a pointer to the i2c_instance_t data structure + holding all data related to a specific CoreI2C channel. For example, if only + one channel is initialized, this data structure holds the information of + channel 0 of the instantiated CoreI2C hardware. + + @param serial_addr: + This parameter specifies the serial address of the target I2C device. + + @param read_buffer + This is a pointer to a buffer where the data received from the target device + will be stored. + Care must be taken not to release the memory used by this buffer before the + read transaction completes. For example, it is not appropriate to return + from a function allocating this buffer as an auto array variable before the + read transaction completes as this would result in the buffer's memory being + de-allocated from the stack when the function returns. This memory could + then be subsequently reallocated resulting in the read transaction + corrupting the newly allocated memory. + + @param read_size: + This parameter specifies the number of bytes to read from the target device. + This size must not exceed the size of the read_buffer buffer. + + @param options: + The options parameter is used to indicate if the I2C bus should be released + on completion of the read transaction. Using the I2C_RELEASE_BUS + constant for the options parameter causes a STOP bit to be generated at the + end of the read transaction causing the bus to be released for other I2C + devices to use. Using the I2C_HOLD_BUS constant as options parameter + prevents a STOP bit from being generated at the end of the read transaction, + preventing other I2C devices from initiating a bus transaction. + + @return none. + + Example: + @code + #define COREI2C_BASE_ADDR 0xC0000000u + #define COREI2C_DUMMY_ADDR 0x10u + #define DATA_LENGTH 16u + + i2c_instance_t g_i2c_inst; + + uint8_t rx_buffer[DATA_LENGTH]; + uint8_t read_length = DATA_LENGTH; + + void main( void ) + { + uint8_t target_slave_addr = 0x12; + i2c_status_t status; + + // Initialize base CoreI2C instance + I2C_init( &g_i2c_inst, COREI2C_BASE_ADDR, COREI2C_DUMMY_ADDR, + I2C_PCLK_DIV_256 ); + + // Read data from target slave Channel 0 of CoreI2C instance. + I2C_read( &g_i2c_inst, target_slave_addr, rx_buffer, read_length, + I2C_RELEASE_BUS ); + + status = I2C_wait_complete( &g_i2c_inst, I2C_NO_TIMEOUT ); + } + @endcode + */ +void I2C_read +( + i2c_instance_t * this_i2c, + uint8_t serial_addr, + uint8_t * read_buffer, + uint16_t read_size, + uint8_t options +); + +/*-------------------------------------------------------------------------*//** + I2C master write-read + ------------------------------------------------------------------------------ + This function initiates an I2C write-read transaction where data is first + written to the target device before issuing a restart condition and changing + the direction of the I2C transaction in order to read from the target device. + + The same warnings about buffer allocation in I2C_write() and I2C_read() + apply to this function. + ------------------------------------------------------------------------------ + @param this_i2c: + The this_i2c parameter is a pointer to the i2c_instance_t data structure + holding all data related to a specific CoreI2C channel. For example, if only + one channel is initialized, this data structure holds the information of + channel 0 of the instantiated CoreI2C hardware. + + @param serial_addr: + This parameter specifies the serial address of the target I2C device. + + @param addr_offset: + This parameter is a pointer to the buffer containing the data that will be + sent to the slave during the write phase of the write-read transaction. This + data is typically used to specify an address offset specifying to the I2C + slave device what data it must return during the read phase of the + write-read transaction. + + @param offset_size: + This parameter specifies the number of offset bytes to be written during the + write phase of the write-read transaction. This is typically the size of the + buffer pointed to by the addr_offset parameter. + + @param read_buffer: + This parameter is a pointer to the buffer where the data read from the I2C + slave will be stored. + + @param read_size: + This parameter specifies the number of bytes to read from the target I2C + slave device. This size must not exceed the size of the buffer pointed to by + the read_buffer parameter. + + @param options: + The options parameter is used to indicate if the I2C bus should be released + on completion of the write-read transaction. Using the I2C_RELEASE_BUS + constant for the options parameter causes a STOP bit to be generated at the + end of the write-read transaction causing the bus to be released for other + I2C devices to use. Using the I2C_HOLD_BUS constant as options parameter + prevents a STOP bit from being generated at the end of the write-read + transaction, preventing other I2C devices from initiating a bus transaction. + + @return none. + + Example: + @code + #define COREI2C_BASE_ADDR 0xC0000000u + #define COREI2C_DUMMY_ADDR 0x10u + #define TX_LENGTH 16u + #define RX_LENGTH 8u + + i2c_instance_t g_i2c_inst; + uint8_t rx_buffer[RX_LENGTH]; + uint8_t read_length = RX_LENGTH; + uint8_t tx_buffer[TX_LENGTH]; + uint8_t write_length = TX_LENGTH; + + void main( void ) + { + uint8_t target_slave_addr = 0x12; + i2c_status_t status; + // Initialize base CoreI2C instance + I2C_init( &g_i2c_inst, COREI2C_BASE_ADDR, COREI2C_DUMMY_ADDR, + I2C_PCLK_DIV_256 ); + + I2C_write_read( &g_i2c_inst, target_slave_addr, tx_buffer, write_length, + rx_buffer, read_length, I2C_RELEASE_BUS ); + + status = I2C_wait_complete( &g_i2c_inst, I2C_NO_TIMEOUT ); + } + @endcode + */ +void I2C_write_read +( + i2c_instance_t * this_i2c, + uint8_t serial_addr, + const uint8_t * addr_offset, + uint16_t offset_size, + uint8_t * read_buffer, + uint16_t read_size, + uint8_t options +); + +/*-------------------------------------------------------------------------*//** + I2C status + ------------------------------------------------------------------------------ + This function indicates the current state of a CoreI2C channel. + ------------------------------------------------------------------------------ + @param this_i2c: + The this_i2c parameter is a pointer to the i2c_instance_t data structure + holding all data related to a specific CoreI2C channel. For example, if only + one channel is initialized, this data structure holds the information of + channel 0 of the instantiated CoreI2C hardware. + ------------------------------------------------------------------------------ + @return + The return value indicates the current state of a CoreI2C channel or the + outcome of the previous transaction if no transaction is in progress. + Possible return values are: + I2C_SUCCESS + The last I2C transaction has completed successfully. + I2C_IN_PROGRESS + There is an I2C transaction in progress. + I2C_FAILED + The last I2C transaction failed. + I2C_TIMED_OUT + The request has failed to complete in the allotted time. + + Example: + @code + i2c_instance_t g_i2c_inst; + + while( I2C_IN_PROGRESS == I2C_get_status( &g_i2c_inst ) ) + { + // Do something useful while waiting for I2C operation to complete + our_i2c_busy_task(); + } + + if( I2C_SUCCESS != I2C_get_status( &g_i2c_inst ) ) + { + // Something went wrong... + our_i2c_error_recovery( &g_i2c_inst ); + } + @endcode + */ +i2c_status_t I2C_get_status +( + i2c_instance_t * this_i2c +); + +/*-------------------------------------------------------------------------*//** + Wait for I2C transaction completion. + ------------------------------------------------------------------------------ + This function waits for the current I2C transaction to complete. The return + value indicates whether the last I2C transaction was successful or not. + ------------------------------------------------------------------------------ + @param this_i2c: + The this_i2c parameter is a pointer to the i2c_instance_t data structure + holding all data related to a specific CoreI2C channel. For example, if only + one channel is initialized, this data structure holds the information of + channel 0 of the instantiated CoreI2C hardware. + @param timeout_ms: + The timeout_ms parameter specified the delay within which the current I2C + transaction is expected to complete. The time out delay is given in + milliseconds. I2C_wait_complete() will return I2C_TIMED_OUT if the current + transaction has not completed after the time out delay has expired. This + parameter can be set to I2C_NO_TIMEOUT to indicate that I2C_wait_complete() + must not time out. + ------------------------------------------------------------------------------ + @return + The return value indicates the outcome of the last I2C transaction. It can + be one of the following: + I2C_SUCCESS + The last I2C transaction has completed successfully. + I2C_FAILED + The last I2C transaction failed. + I2C_TIMED_OUT + The last transaction failed to complete within the time out delay given + as second parameter. + + Example: + @code + #define COREI2C_BASE_ADDR 0xC0000000u + #define COREI2C_DUMMY_ADDR 0x10u + #define DATA_LENGTH 16u + + i2c_instance_t g_i2c_inst; + + uint8_t rx_buffer[DATA_LENGTH]; + uint8_t read_length = DATA_LENGTH; + + void main( void ) + { + uint8_t target_slave_addr = 0x12; + i2c_status_t status; + + // Initialize base CoreI2C instance + I2C_init( &g_i2c_inst, COREI2C_BASE_ADDR, COREI2C_DUMMY_ADDR, + I2C_PCLK_DIV_256 ); + + // Read data from Channel 0 of CoreI2C instance. + I2C_read( &g_i2c_inst, target_slave_addr, rx_buffer, read_length, + I2C_RELEASE_BUS ); + + // Wait for completion and record the outcome + status = I2C_wait_complete( &g_i2c_inst, I2C_NO_TIMEOUT ); + } + @endcode + */ +i2c_status_t I2C_wait_complete +( + i2c_instance_t * this_i2c, + uint32_t timeout_ms +); + +/*-------------------------------------------------------------------------*//** + Time out delay expiration. + ------------------------------------------------------------------------------ + This function is used to control the expiration of the time out delay + specified as a parameter to the I2C_wait_complete() function. It must be + called from the interrupt service routine of a periodic interrupt source such + as the Cortex-M3 SysTick timer interrupt. It takes the period of the interrupt + source as its ms_since_last_tick parameter and uses it as the time base for + the I2C_wait_complete() function’s time out delay. + + Note: This function does not need to be called if the I2C_wait_complete() + function is called with a timeout_ms value of I2C_NO_TIMEOUT. + Note: If this function is not called then the I2C_wait_complete() function + will behave as if its timeout_ms was specified as I2C_NO_TIMEOUT and it + will not time out. + Note: If this function is being called from an interrupt handler (e.g SysTick) + it is important that the calling interrupt have a lower priority than + the CoreI2C interrupt(s) to ensure any updates to shared data are + protected. + + ------------------------------------------------------------------------------ + @param this_i2c: + The this_i2c parameter is a pointer to the i2c_instance_t data structure + holding all data related to a specific CoreI2C channel. For example, if only + one channel is initialized, this data structure holds the information of + channel 0 of the instantiated CoreI2C hardware. + @param ms_since_last_tick: + The ms_since_last_tick parameter specifies the number of milliseconds that + elapsed since the last call to I2C_system_tick(). This parameter would + typically be a constant specifying the interrupt rate of a timer used to + generate system ticks. + ------------------------------------------------------------------------------ + @return + none. + + Example: + The example below shows an example of how the I2C_system_tick() function + would be called in a Cortex-M3 based system. I2C_system_tick() is called for + each I2C channel from the Cortex-M3 SysTick timer interrupt service routine. + The SysTick is configured to generate an interrupt every 10 milliseconds in + the example below. + @code + #define SYSTICK_INTERVAL_MS 10 + + void SysTick_Handler(void) + { + I2C_system_tick(&g_core_i2c0, SYSTICK_INTERVAL_MS); + I2C_system_tick(&g_core_i2c2, SYSTICK_INTERVAL_MS); + } + @endcode + */ +void I2C_system_tick +( + i2c_instance_t * this_i2c, + uint32_t ms_since_last_tick +); + +/******************************************************************************* + ******************************************************************************* + * + * Slave specific functions + * + * The following functions are only used within the implementation of an I2C + * slave device. + */ + +/*-------------------------------------------------------------------------*//** + I2C slave transmit buffer configuration. + ------------------------------------------------------------------------------ + This function specifies the memory buffer holding the data that will be sent + to the I2C master when this CoreI2C channel is the target of an I2C read or + write-read transaction. + ------------------------------------------------------------------------------ + @param this_i2c: + The this_i2c parameter is a pointer to the i2c_instance_t data structure + holding all data related to a specific CoreI2C channel. For example, if only + one channel is initialized, this data structure holds the information of + channel 0 of the instantiated CoreI2C hardware. + + @param tx_buffer: + This parameter is a pointer to the memory buffer holding the data to be + returned to the I2C master when this CoreI2C channel is the target of an + I2C read or write-read transaction. + + @param tx_size: + Size of the transmit buffer pointed to by the tx_buffer parameter. + + @return none. + + Example: + @code + #define COREI2C_BASE_ADDR 0xC0000000u + #define SLAVE_SER_ADDR 0x10u + #define SLAVE_TX_BUFFER_SIZE 10u + + i2c_instance_t g_i2c_inst; + + uint8_t g_slave_tx_buffer[SLAVE_TX_BUFFER_SIZE] = { 1, 2, 3, 4, 5, + 6, 7, 8, 9, 10 }; + + void main( void ) + { + // Initialize the CoreI2C driver with its base address, I2C serial + // address and serial clock divider. + I2C_init( &g_i2c_inst, COREI2C_BASE_ADDR, SLAVE_SER_ADDR, + I2C_PCLK_DIV_256 ); + + // Specify the transmit buffer containing the data that will be + // returned to the master during read and write-read transactions. + I2C_set_slave_tx_buffer( &g_i2c_inst, g_slave_tx_buffer, + sizeof(g_slave_tx_buffer) ); + } + @endcode + */ +void I2C_set_slave_tx_buffer +( + i2c_instance_t * this_i2c, + const uint8_t * tx_buffer, + uint16_t tx_size +); + +/*-------------------------------------------------------------------------*//** + I2C slave receive buffer configuration. + ------------------------------------------------------------------------------ + This function specifies the memory buffer that will be used by the CoreI2C + channel to receive data when it is a slave. This buffer is the memory where + data will be stored when the CoreI2C channel is the target of an I2C master + write transaction (i.e. when it is the slave). + ------------------------------------------------------------------------------ + @param this_i2c: + The this_i2c parameter is a pointer to the i2c_instance_t data structure + holding all data related to a specific CoreI2C channel. For example, if only + one channel is initialized, this data structure holds the information of + channel 0 of the instantiated CoreI2C hardware. + + @param rx_buffer: + This parameter is a pointer to the memory buffer allocated by the caller + software to be used as a slave receive buffer. + + @param rx_size: + Size of the slave receive buffer. This is the amount of memory that is + allocated to the buffer pointed to by rx_buffer. + Note: This buffer size indirectly specifies the maximum I2C write + transaction length this CoreI2C channel can be the target of. This + is because this CoreI2C channel responds to further received + bytes with a non-acknowledge bit (NACK) as soon as its receive + buffer is full. This causes the write transaction to fail. + + @return none. + + Example: + @code + #define COREI2C_BASE_ADDR 0xC0000000u + #define SLAVE_SER_ADDR 0x10u + #define SLAVE_RX_BUFFER_SIZE 10u + + i2c_instance_t g_i2c_inst; + + uint8_t g_slave_rx_buffer[SLAVE_RX_BUFFER_SIZE]; + + void main( void ) + { + // Initialize the CoreI2C driver with its base address, I2C serial + // address and serial clock divider. + I2C_init( &g_i2c_inst, COREI2C_BASE_ADDR, SLAVE_SER_ADDR, + I2C_PCLK_DIV_256 ); + + // Specify the buffer used to store the data written by the I2C master. + I2C_set_slave_rx_buffer( &g_i2c_inst, g_slave_rx_buffer, + sizeof(g_slave_rx_buffer) ); + } + @endcode + */ +void I2C_set_slave_rx_buffer +( + i2c_instance_t * this_i2c, + uint8_t * rx_buffer, + uint16_t rx_size +); + +/*-------------------------------------------------------------------------*//** + I2C slave memory offset length configuration. + ------------------------------------------------------------------------------ + This function is used as part of the configuration of a CoreI2C channel for + operation as a slave supporting write-read transactions. It specifies the + number of bytes expected as part of the write phase of a write-read + transaction. The bytes received during the write phase of a write-read + transaction will be interpreted as an offset into the slave's transmit buffer. + This allows random access into the I2C slave transmit buffer from a remote + I2C master. + ------------------------------------------------------------------------------ + @param this_i2c: + The this_i2c parameter is a pointer to the i2c_instance_t data structure + holding all data related to a specific CoreI2C channel. For example, if only + one channel is initialized, this data structure holds the information of + channel 0 of the instantiated CoreI2C hardware. + + @param offset_length: + The offset_length parameter configures the number of bytes to be interpreted + by the CoreI2C slave as a memory offset value during the write phase of + write-read transactions. The maximum value for the offset_length parameter + is two. The value of offset_length has the following effect on the + interpretation of the received data. + + If offset_length is 0, the offset into the transmit buffer is fixed at 0. + + If offset_length is 1, a single byte of received data is interpreted as an + unsigned 8 bit offset value in the range 0 to 255. + + If offset_length is 2, 2 bytes of received data are interpreted as an + unsigned 16 bit offset value in the range 0 to 65535. The first byte + received in this case provides the high order bits of the offset and + the second byte provides the low order bits. + + If the number of bytes received does not match the non 0 value of + offset_length the transmit buffer offset is set to 0. + + @return none. + + Example: + @code + #define COREI2C_BASE_ADDR 0xC0000000u + #define SLAVE_SER_ADDR 0x10u + #define SLAVE_TX_BUFFER_SIZE 10u + + i2c_instance_t g_i2c_inst; + + uint8_t g_slave_tx_buffer[SLAVE_TX_BUFFER_SIZE] = { 1, 2, 3, 4, 5, + 6, 7, 8, 9, 10 }; + + void main( void ) + { + // Initialize the CoreI2C driver with its base address, I2C serial + // address and serial clock divider. + I2C_init( &g_i2c_inst, COREI2C_BASE_ADDR, SLAVE_SER_ADDR, + I2C_PCLK_DIV_256 ); + I2C_set_slave_tx_buffer( &g_i2c_inst, g_slave_tx_buffer, + sizeof(g_slave_tx_buffer) ); + I2C_set_slave_mem_offset_length( &g_i2c_inst, 1 ); + } + @endcode + */ +void I2C_set_slave_mem_offset_length +( + i2c_instance_t * this_i2c, + uint8_t offset_length +); + +/*-------------------------------------------------------------------------*//** + I2C write handler registration. + ------------------------------------------------------------------------------ + Register the function that is called to process the data written to this + CoreI2C channel when it is the slave in an I2C write transaction. + Note: If a write handler is registered, it is called on completion of the + write phase of a write-read transaction and responsible for processing + the received data in the slave receive buffer and populating the slave + transmit buffer with the data that will be transmitted to the I2C master + as part of the read phase of the write-read transaction. If a write + handler is not registered, the write data of a write read transaction is + interpreted as an offset into the slave’s transmit buffer and handled by + the driver. + ------------------------------------------------------------------------------ + @param this_i2c: + The this_i2c parameter is a pointer to the i2c_instance_t data structure + holding all data related to a specific CoreI2C channel. For example, if only + one channel is initialized, this data structure holds the information of + channel 0 of the instantiated CoreI2C hardware. + + @param handler: + Pointer to the function that will process the I2C write request. + + @return none. + + Example: + @code + #define COREI2C_BASE_ADDR 0xC0000000u + #define SLAVE_SER_ADDR 0x10u + #define SLAVE_TX_BUFFER_SIZE 10u + + i2c_instance_t g_i2c_inst; + + uint8_t g_slave_tx_buffer[SLAVE_TX_BUFFER_SIZE] = { 1, 2, 3, 4, 5, + 6, 7, 8, 9, 10 }; + + // local function prototype + void slave_write_handler + ( + i2c_instance_t * this_i2c, + uint8_t * p_rx_data, + uint16_t rx_size + ); + + void main( void ) + { + // Initialize the CoreI2C driver with its base address, I2C serial + // address and serial clock divider. + I2C_init( &g_i2c_inst, COREI2C_BASE_ADDR, SLAVE_SER_ADDR, + I2C_PCLK_DIV_256 ); + I2C_set_slave_tx_buffer( &g_i2c_inst, g_slave_tx_buffer, + sizeof(g_slave_tx_buffer) ); + I2C_set_slave_mem_offset_length( &g_i2c_inst, 1 ); + I2C_register_write_handler( &g_i2c_inst, slave_write_handler ); + } + @endcode +*/ +void I2C_register_write_handler +( + i2c_instance_t * this_i2c, + i2c_slave_wr_handler_t handler +); + +/*-------------------------------------------------------------------------*//** + I2C slave enable. + ------------------------------------------------------------------------------ + This function enables slave mode operation for a CoreI2C channel. It enables + the CoreI2C slave to receive data when it is the target of an I2C read, write + or write-read transaction. + ------------------------------------------------------------------------------ + @param this_i2c: + The this_i2c parameter is a pointer to the i2c_instance_t data structure + holding all data related to a specific CoreI2C channel. For example, if only + one channel is initialized, this data structure holds the information of + channel 0 of the instantiated CoreI2C hardware. + + @return none. + + Example: + @code + // Enable I2C slave + I2C_enable_slave( &g_i2c_inst ); + @endcode + */ +void I2C_enable_slave +( + i2c_instance_t * this_i2c +); + +/*-------------------------------------------------------------------------*//** + I2C slave disable. + ------------------------------------------------------------------------------ + This function disables slave mode operation for a CoreI2C channel. It stops + the CoreI2C slave acknowledging I2C read, write or write-read transactions + targeted at it. + ------------------------------------------------------------------------------ + @param this_i2c: + The this_i2c parameter is a pointer to the i2c_instance_t data structure + holding all data related to a specific CoreI2C channel. For example, if only + one channel is initialized, this data structure holds the information of + channel 0 of the instantiated CoreI2C hardware. + + @return none. + + Example: + @code + // Disable I2C slave + I2C_disable_slave( &g_i2c_inst ); + @endcode + */ +void I2C_disable_slave +( + i2c_instance_t * this_i2c +); +/*-------------------------------------------------------------------------*//** + Set I2C slave second address. + ------------------------------------------------------------------------------ + The function I2C_set_slave_second_addr() sets the secondary slave address for + a CoreI2C slave device. This is an additional slave address which might be + required in certain applications, for example to enable fail-safe operation in + a system. As the CoreI2C device supports 7-bit addressing, the highest value + which can be assigned to second slave address is 127 (0x7F). + Note: This function does not support CoreI2C hardware configured with a fixed + second slave address. The current implementation of the ADDR1[0] register + bit makes it difficult for the driver to support both programmable and + fixed second slave address, so we choose to support programmable only. + ------------------------------------------------------------------------------ + @param this_i2c: + The this_i2c parameter is a pointer to the i2c_instance_t data structure + holding all data related to a specific CoreI2C channel. For example, if only + one channel is initialized, this data structure holds the information of + channel 0 of the instantiated CoreI2C hardware. + + @param second_slave_addr: + The second_slave_addr parameter is the secondary slave address of the I2C + device. + + @return + none. + + Example: + @code + #define COREI2C_BASE_ADDR 0xC0000000u + #define SLAVE_SER_ADDR 0x10u + #define SECOND_SLAVE_ADDR 0x20u + + i2c_instance_t g_i2c_inst; + void main( void ) + { + // Initialize the CoreI2C driver with its base address, primary I2C + // serial address and serial clock divider. + I2C_init( &g_i2c_inst, COREI2C_BASE_ADDR, SLAVE_SER_ADDR, + I2C_PCLK_DIV_256 ); + I2C_set_slave_second_addr( &g_i2c_inst, SECOND_SLAVE_ADDR ); + } + @endcode + */ +void I2C_set_slave_second_addr +( + i2c_instance_t * this_i2c, + uint8_t second_slave_addr +); + +/*-------------------------------------------------------------------------*//** + Disable second slave address. + ------------------------------------------------------------------------------ + The function I2C_disable_slave_second_addr() disables the secondary slave + address of the CoreI2C slave device. + Note: This version of the driver only supports CoreI2C hardware configured + with a programmable second slave address. + ------------------------------------------------------------------------------ + @param this_i2c: + The this_i2c parameter is a pointer to the i2c_instance_t data structure + holding all data related to a specific CoreI2C channel. For example, if only + one channel is initialized, this data structure holds the information of + channel 0 of the instantiated CoreI2C hardware. + + @return + none. + + Example: + @code + i2c_instance_t g_i2c_inst; + I2C_disable_slave_second_addr( &g_i2c_inst); + @endcode + */ +void I2C_disable_slave_second_addr +( + i2c_instance_t * this_i2c +); + +/*-------------------------------------------------------------------------*//** + The I2C_set_gca() function is used to set the general call acknowledgement bit + of a CoreI2C slave device. This allows all channels of the CoreI2C slave + device respond to a general call or broadcast message from an I2C master. + ------------------------------------------------------------------------------ + @param this_i2c: + The this_i2c parameter is a pointer to the i2c_instance_t data structure + holding all data related to a specific CoreI2C channel. For example, if only + one channel is initialized, this data structure holds the information of + channel 0 of the instantiated CoreI2C hardware. + + @return + none. + + Example: + @code + i2c_instance_t g_i2c_inst; + + // Enable recognition of the General Call Address + I2C_set_gca( &g_i2c_inst ); + @endcode + */ +void I2C_set_gca +( + i2c_instance_t * this_i2c +); + +/*-------------------------------------------------------------------------*//** + The I2C_clear_gca() function is used to clear the general call acknowledgement + bit of a CoreI2C slave device. This will stop all channels of the I2C slave + device responding to any general call or broadcast message from the master. + ------------------------------------------------------------------------------ + @param this_i2c: + The this_i2c parameter is a pointer to the i2c_instance_t data structure + holding all data related to a specific CoreI2C channel. For example, if only + one channel is initialized, this data structure holds the information of + channel 0 of the instantiated CoreI2C hardware. + + @return + none. + + Example: + @code + i2c_instance_t g_i2c_inst; + + // Disable recognition of the General Call Address + I2C_clear_gca( &g_i2c_inst ); + @endcode + */ + +void I2C_clear_gca +( + i2c_instance_t * this_i2c +); + +/*------------------------------------------------------------------------------ + I2C SMBUS specific APIs + ----------------------------------------------------------------------------*/ + +/*-------------------------------------------------------------------------*//** + The I2C_smbus_init() function enables SMBus timeouts and status logic for a + CoreI2C channel. + Note: This and any of the other SMBus related functionality will only have an + effect if the CoreI2C was instantiated with the Generate SMBus Logic + option checked. + Note: If the CoreI2C was instantiated with the Generate IPMI Logic option + checked this function will enable the IPMI 3mS SCL low timeout but none + of the other SMBus functions will have any effect. + ------------------------------------------------------------------------------ + @param this_i2c: + The this_i2c parameter is a pointer to the i2c_instance_t data structure + holding all data related to a specific CoreI2C channel. For example, if only + one channel is initialized, this data structure holds the information of + channel 0 of the instantiated CoreI2C hardware. + + @return + none. + + Example: + @code + #define COREI2C_BASE_ADDR 0xC0000000u + #define SLAVE_SER_ADDR 0x10u + + i2c_instance_t g_i2c_inst; + + void system_init( void ) + { + I2C_init( &g_i2c_inst, COREI2C_BASE_ADDR, SLAVE_SER_ADDR, + I2C_PCLK_DIV_256 ); + + // Initialize SMBus feature + I2C_smbus_init( &g_i2c_inst); + } + @endcode + */ +void I2C_smbus_init +( + i2c_instance_t * this_i2c +); + +/*-------------------------------------------------------------------------*//** + The I2C_enable_smbus_irq() function is used to enable the CoreI2C channel’s + SMBSUS and SMBALERT SMBus interrupts. + ------------------------------------------------------------------------------ + @param this_i2c: + The this_i2c parameter is a pointer to the i2c_instance_t data structure + holding all data related to a specific CoreI2C channel. For example, if only + one channel is initialized, this data structure holds the information of + channel 0 of the instantiated CoreI2C hardware. + + @param irq_type + The irq_type specify the SMBUS interrupt(s) which will be enabled. + The two possible interrupts are: + I2C_SMBALERT_IRQ + I2C_SMBSUS_IRQ + To enable both ints in one call, use I2C_SMBALERT_IRQ | I2C_SMBSUS_IRQ. + + @return + none + + Example: + @code + #define COREI2C_BASE_ADDR 0xC0000000u + #define SLAVE_SER_ADDR 0x10u + + i2c_instance_t g_i2c_inst; + + void main( void ) + { + I2C_init( &g_i2c_inst, COREI2C_BASE_ADDR, SLAVE_SER_ADDR, + I2C_PCLK_DIV_256 ); + + // Initialize SMBus feature + I2C_smbus_init( &g_i2c_inst ); + + // Enable both I2C_SMBALERT_IRQ & I2C_SMBSUS_IRQ interrupts + I2C_enable_smbus_irq( &g_i2c_inst, + (uint8_t)(I2C_SMBALERT_IRQ | I2C_SMBSUS_IRQ) ); + } + @endcode + */ +void I2C_enable_smbus_irq +( + i2c_instance_t * this_i2c, + uint8_t irq_type +); + +/*-------------------------------------------------------------------------*//** + The I2C_disable_smbus_irq() function is used to disable the CoreI2C channel’s + SMBSUS and SMBALERT SMBus interrupts. + ------------------------------------------------------------------------------ + @param this_i2c: + The this_i2c parameter is a pointer to the i2c_instance_t data structure + holding all data related to a specific CoreI2C channel. For example, if only + one channel is initialized, this data structure holds the information of + channel 0 of the instantiated CoreI2C hardware. + + @param irq_type + The irq_type specifies the SMBUS interrupt(s) which will be disabled. + The two possible interrupts are: + I2C_SMBALERT_IRQ + I2C_SMBSUS_IRQ + To disable both ints in one call, use I2C_SMBALERT_IRQ | I2C_SMBSUS_IRQ. + + @return + none. + + Example: + @code + #define COREI2C_BASE_ADDR 0xC0000000u + #define SLAVE_SER_ADDR 0x10u + + i2c_instance_t g_i2c_inst; + + void main( void ) + { + I2C_init( &g_i2c_inst, COREI2C_BASE_ADDR, SLAVE_SER_ADDR, + I2C_PCLK_DIV_256 ); + + // Initialize SMBus feature + I2C_smbus_init( &g_i2c_inst ); + + // Enable both SMBALERT & SMBSUS interrupts + I2C_enable_smbus_irq( &g_i2c_inst, + (uint8_t)(I2C_SMBALERT_IRQ | I2C_SMBSUS_IRQ)); + + ... + + // Disable the SMBALERT interrupt + I2C_disable_smbus_irq( &g_i2c_inst, I2C_SMBALERT_IRQ ); + } + @endcode + */ +void I2C_disable_smbus_irq +( + i2c_instance_t * this_i2c, + uint8_t irq_type +); + +/*-------------------------------------------------------------------------*//** + The function I2C_suspend_smbus_slave() forces any SMBUS slave devices + connected to a CoreI2C channel into power down or suspend mode by asserting + the channel's SMBSUS signal. The CoreI2C channel is the SMBus master in this + case. + ------------------------------------------------------------------------------ + @param this_i2c: + The this_i2c parameter is a pointer to the i2c_instance_t data structure + holding all data related to a specific CoreI2C channel. For example, if only + one channel is initialized, this data structure holds the information of + channel 0 of the instantiated CoreI2C hardware. + + @return + none. + + Example: + @code + #define COREI2C_BASE_ADDR 0xC0000000u + #define SLAVE_SER_ADDR 0x10u + + i2c_instance_t g_i2c_inst; + + void main( void ) + { + I2C_init( &g_i2c_inst, COREI2C_BASE_ADDR, SLAVE_SER_ADDR, + I2C_PCLK_DIV_256 ); + + // Initialize SMBus feature + I2C_smbus_init( &g_i2c_inst ); + + // suspend SMBus slaves + I2C_suspend_smbus_slave( &g_i2c_inst ); + + ... + + // Re-enable SMBus slaves + I2C_resume_smbus_slave( &g_i2c_inst ); + } + @endcode + */ +void I2C_suspend_smbus_slave +( + i2c_instance_t * this_i2c +); + +/*-------------------------------------------------------------------------*//** + The function I2C_resume_smbus_slave() de-asserts the CoreI2C channel's SMBSUS + signal to take any connected slave devices out of suspend mode. The CoreI2C + channel is the SMBus master in this case. + ------------------------------------------------------------------------------ + @param this_i2c: + The this_i2c parameter is a pointer to the i2c_instance_t data structure + holding all data related to a specific CoreI2C channel. For example, if only + one channel is initialized, this data structure holds the information of + channel 0 of the instantiated CoreI2C hardware. + + @return + none. + + Example: + @code + #define COREI2C_BASE_ADDR 0xC0000000u + #define SLAVE_SER_ADDR 0x10u + + i2c_instance_t g_i2c_inst; + + void main( void ) + { + I2C_init( &g_i2c_inst, COREI2C_BASE_ADDR, SLAVE_SER_ADDR, + I2C_PCLK_DIV_256 ); + + // Initialize SMBus feature + I2C_smbus_init( &g_i2c_inst ); + + // suspend SMBus slaves + I2C_suspend_smbus_slave( &g_i2c_inst ); + + ... + + // Re-enable SMBus slaves + I2C_resume_smbus_slave( &g_i2c_inst ); + } + @endcode + */ +void I2C_resume_smbus_slave +( + i2c_instance_t * this_i2c +); + +/*-------------------------------------------------------------------------*//** + The I2C_reset_smbus() function resets the CoreI2C channel's SMBus connection + by forcing SCLK low for 35mS. The reset is automatically cleared after 35ms + have elapsed. The CoreI2C channel is the SMBus master in this case. + ------------------------------------------------------------------------------ + @param this_i2c: + The this_i2c parameter is a pointer to the i2c_instance_t data structure + holding all data related to a specific CoreI2C channel. For example, if only + one channel is initialized, this data structure holds the information of + channel 0 of the instantiated CoreI2C hardware. + + @return + none. + + Example: + @code + #define COREI2C_BASE_ADDR 0xC0000000u + #define SLAVE_SER_ADDR 0x10u + + i2c_instance_t g_i2c_inst; + + void main( void ) + { + I2C_init( &g_i2c_inst, COREI2C_BASE_ADDR, SLAVE_SER_ADDR, + I2C_PCLK_DIV_256 ); + + // Initialize SMBus feature + I2C_smbus_init( &g_i2c_inst ); + + // Make sure the SMBus channel is in a known state by resetting it + I2C_reset_smbus( &g_i2c_inst ); + } + @endcode + */ +void I2C_reset_smbus +( + i2c_instance_t * this_i2c +); + +/*-------------------------------------------------------------------------*//** + The I2C_set_smbus_alert() function is used to force master communication with + an I2C slave device by asserting the CoreI2C channel’s SMBALERT signal. The + CoreI2C channel is the SMBus slave in this case. + ------------------------------------------------------------------------------ + @param this_i2c: + The this_i2c parameter is a pointer to the i2c_instance_t data structure + holding all data related to a specific CoreI2C channel. For example, if only + one channel is initialized, this data structure holds the information of + channel 0 of the instantiated CoreI2C hardware. + + @return + none. + + Example: + @code + #define COREI2C_BASE_ADDR 0xC0000000u + #define SLAVE_SER_ADDR 0x10u + + i2c_instance_t g_i2c_inst; + + void main( void ) + { + I2C_init( &g_i2c_inst, COREI2C_BASE_ADDR, SLAVE_SER_ADDR, + I2C_PCLK_DIV_256 ); + + // Initialize SMBus feature + I2C_smbus_init( &g_i2c_inst ); + + // Get the SMBus masters attention + I2C_set_smbus_alert( &g_i2c_inst ); + + ... + + // Once we are happy, drop the alert + I2C_clear_smbus_alert( &g_i2c_inst ); + } + @endcode + */ +void I2C_set_smbus_alert +( + i2c_instance_t * this_i2c +); + +/*-------------------------------------------------------------------------*//** + The I2C_clear_smbus_alert() function is used de-assert the CoreI2C channel’s + SMBALERT signal once a slave device has had a response from the master. The + CoreI2C channel is the SMBus slave in this case. + ------------------------------------------------------------------------------ + @param this_i2c: + The this_i2c parameter is a pointer to the i2c_instance_t data structure + holding all data related to a specific CoreI2C channel. For example, if only + one channel is initialized, this data structure holds the information of + channel 0 of the instantiated CoreI2C hardware. + + @return + none. + + Example: + @code + #define COREI2C_BASE_ADDR 0xC0000000u + #define SLAVE_SER_ADDR 0x10u + + i2c_instance_t g_i2c_inst; + + void main( void ) + { + I2C_init( &g_i2c_inst, COREI2C_BASE_ADDR, SLAVE_SER_ADDR, + I2C_PCLK_DIV_256 ); + + // Initialize SMBus feature + I2C_smbus_init( &g_i2c_inst ); + + // Get the SMBus masters attention + I2C_set_smbus_alert( &g_i2c_inst ); + + ... + + // Once we are happy, drop the alert + I2C_clear_smbus_alert( &g_i2c_inst ); + } + @endcode + */ +void I2C_clear_smbus_alert +( + i2c_instance_t * this_i2c +); + +/*-------------------------------------------------------------------------*//** + The I2C_get_irq_status function returns information on which interrupts are + currently pending in a CoreI2C channel. + The interrupts supported by CoreI2C are: + * SMBUSALERT + * SMBSUS + * INTR + The macros I2C_NO_IRQ, I2C_SMBALERT_IRQ, I2C_SMBSUS_IRQ and I2C_INTR_IRQ are + provided for use with this function. + ------------------------------------------------------------------------------ + @param this_i2c: + The this_i2c parameter is a pointer to the i2c_instance_t data structure + holding all data related to a specific CoreI2C channel. For example, if only + one channel is initialized, this data structure holds the information of + channel 0 of the instantiated CoreI2C hardware. + + @return + This function returns the status of the CoreI2C channel’s interrupts as a + single byte bitmap where a bit is set to indicate a pending interrupt. + The following are the bit positions associated with each interrupt type: + Bit 0 - SMBUS_ALERT_IRQ + Bit 1 - SMBSUS_IRQ + Bit 2 - INTR_IRQ + It returns 0, if there are no pending interrupts. + + Example + @code + #define COREI2C_BASE_ADDR 0xC0000000u + #define SLAVE_SER_ADDR 0x10u + + i2c_instance_t g_i2c_inst; + + void main( void ) + { + uint8_t irq_to_enable = I2C_SMBALERT_IRQ | I2C_SMBSUS_IRQ; + uint8_t pending_irq = 0u; + + I2C_init( &g_i2c_inst, COREI2C_BASE_ADDR, SLAVE_SER_ADDR, + I2C_PCLK_DIV_256 ); + + // Initialize SMBus feature + I2C_smbus_init( &g_i2c_inst ); + + // Enable both I2C_SMBALERT_IRQ & I2C_SMBSUS_IRQ irq + I2C_enable_smbus_irq( &g_i2c_inst, irq_to_enable ); + + // Get I2C IRQ type + pending_irq = I2C_get_irq_status( &g_i2c_inst ); + + // Let's assume, in system, INTR and SMBALERT IRQ is pending. + // So pending_irq will return status of both the IRQs + + if( pending_irq & I2C_SMBALERT_IRQ ) + { + // if true, it means SMBALERT_IRQ is there in pending IRQ list + } + if( pending_irq & I2C_INTR_IRQ ) + { + // if true, it means I2C_INTR_IRQ is there in pending IRQ list + } + } + @endcode + */ +uint8_t I2C_get_irq_status +( + i2c_instance_t * this_i2c +); + +/*-------------------------------------------------------------------------*//** + The I2C_set_user_data() function is used to allow the association of a block + of application specific data with a CoreI2C channel. The composition of the + data block is an application matter and the driver simply provides the means + for the application to set and retrieve the pointer. This may for example be + used to provide additional channel specific information to the slave write + handler. + ------------------------------------------------------------------------------ + @param this_i2c: + The this_i2c parameter is a pointer to the i2c_instance_t data structure + holding all data related to a specific CoreI2C channel. For example, if only + one channel is initialized, this data structure holds the information of + channel 0 of the instantiated CoreI2C hardware. + + @param p_user_data: + The p_user_data parameter is a pointer to the user specific data block for + this channel. It is defined as void * as the driver does not know the actual + type of data being pointed to and simply stores the pointer for later + retrieval by the application. + + @return + none. + + Example + @code + #define COREI2C_BASE_ADDR 0xC0000000u + #define SLAVE_SER_ADDR 0x10u + + i2c_instance_t g_i2c_inst; + app_data_t channel_xdata; + + void main( void ) + { + app_data_t *p_xdata; + + I2C_init( &g_i2c_inst, COREI2C_BASE_ADDR, SLAVE_SER_ADDR, + I2C_PCLK_DIV_256 ); + + // Store location of user data in instance structure + I2C_set_user_data( &g_i2c_inst, (void *)&channel_xdata ); + + ... + + // Retrieve location of user data and do some work on it + p_xdata = (app_data_t *)I2C_get_user_data( &g_i2c_inst ); + if( NULL != p_xdata ) + { + p_xdata->foo = 123; + } + } + @endcode + */ +void I2C_set_user_data +( + i2c_instance_t * this_i2c, + void * p_user_data +); + +/*-------------------------------------------------------------------------*//** + The I2C_get_user_data() function is used to allow the retrieval of the address + of a block of application specific data associated with a CoreI2C channel. + The composition of the data block is an application matter and the driver + simply provides the means for the application to set and retrieve the pointer. + This may for example be used to provide additional channel specific + information to the slave write handler. + ------------------------------------------------------------------------------ + @param this_i2c: + The this_i2c parameter is a pointer to the i2c_instance_t data structure + holding all data related to a specific CoreI2C channel. For example, if only + one channel is initialized, this data structure holds the information of + channel 0 of the instantiated CoreI2C hardware. + + @return + This function returns a pointer to the user specific data block for this + channel. It is defined as void * as the driver does not know the actual type + of data being pointed. If no user data has been registered for this channel + a NULL pointer is returned. + + Example + @code + #define COREI2C_BASE_ADDR 0xC0000000u + #define SLAVE_SER_ADDR 0x10u + + i2c_instance_t g_i2c_inst; + app_data_t channel_xdata; + + void main( void ) + { + app_data_t *p_xdata; + + I2C_init( &g_i2c_inst, COREI2C_BASE_ADDR, SLAVE_SER_ADDR, + I2C_PCLK_DIV_256 ); + + // Store location of user data in instance structure + I2C_set_user_data( &g_i2c_inst, (void *)&channel_xdata ); + + ... + + // Retrieve location of user data and do some work on it + p_xdata = (app_data_t *)I2C_get_user_data( &g_i2c_inst ); + if( NULL != p_xdata ) + { + p_xdata->foo = 123; + } + } + @endcode + */ +void * I2C_get_user_data +( + i2c_instance_t * this_i2c +); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/FreeRTOS/Demo/RISC-V_IGLOO2_Creative_SoftConsole/drivers/CoreI2C/core_smbus_regs.h b/FreeRTOS/Demo/RISC-V_IGLOO2_Creative_SoftConsole/drivers/CoreI2C/core_smbus_regs.h new file mode 100644 index 000000000..67da7a5af --- /dev/null +++ b/FreeRTOS/Demo/RISC-V_IGLOO2_Creative_SoftConsole/drivers/CoreI2C/core_smbus_regs.h @@ -0,0 +1,190 @@ +/******************************************************************************* + * (c) Copyright 2009-2015 Microsemi SoC Products Group. All rights reserved. + * + * SVN $Revision: 7984 $ + * SVN $Date: 2015-10-12 12:07:40 +0530 (Mon, 12 Oct 2015) $ + */ + +#ifndef __CORE_SMBUS_REGISTERS +#define __CORE_SMBUS_REGISTERS 1 + +/*------------------------------------------------------------------------------ + * CONTROL register details + */ +#define CONTROL_REG_OFFSET 0x00u + +/* + * CR0 bits. + */ +#define CR0_OFFSET 0x00u +#define CR0_MASK 0x01u +#define CR0_SHIFT 0u + +/* + * CR1 bits. + */ +#define CR1_OFFSET 0x00u +#define CR1_MASK 0x02u +#define CR1_SHIFT 1u + +/* + * AA bits. + */ +#define AA_OFFSET 0x00u +#define AA_MASK 0x04u +#define AA_SHIFT 2u + +/* + * SI bits. + */ +#define SI_OFFSET 0x00u +#define SI_MASK 0x08u +#define SI_SHIFT 3u + +/* + * STO bits. + */ +#define STO_OFFSET 0x00u +#define STO_MASK 0x10u +#define STO_SHIFT 4u + +/* + * STA bits. + */ +#define STA_OFFSET 0x00u +#define STA_MASK 0x20u +#define STA_SHIFT 5u + +/* + * ENS1 bits. + */ +#define ENS1_OFFSET 0x00u +#define ENS1_MASK 0x40u +#define ENS1_SHIFT 6u + +/* + * CR2 bits. + */ +#define CR2_OFFSET 0x00u +#define CR2_MASK 0x80u +#define CR2_SHIFT 7u + +/*------------------------------------------------------------------------------ + * STATUS register details + */ +#define STATUS_REG_OFFSET 0x04u + +/*------------------------------------------------------------------------------ + * DATA register details + */ +#define DATA_REG_OFFSET 0x08u + +/* + * TARGET_ADDR bits. + */ +#define TARGET_ADDR_OFFSET 0x08u +#define TARGET_ADDR_MASK 0xFEu +#define TARGET_ADDR_SHIFT 1u + +/* + * DIR bit. + */ +#define DIR_OFFSET 0x08u +#define DIR_MASK 0x01u +#define DIR_SHIFT 0u + + +/*------------------------------------------------------------------------------ + * ADDRESS register details + */ +#define ADDRESS_REG_OFFSET 0x0Cu + +/* + * GC bits. + */ +#define GC_OFFSET 0x0Cu +#define GC_MASK 0x01u +#define GC_SHIFT 0u + +/* + * ADR bits. + */ +#define OWN_SLAVE_ADDR_OFFSET 0x0Cu +#define OWN_SLAVE_ADDR_MASK 0xFEu +#define OWN_SLAVE_ADDR_SHIFT 1u + +/*------------------------------------------------------------------------------ + * SMBUS register details + */ +#define SMBUS_REG_OFFSET 0x10u + +/* + * SMBALERT_IE bits. + */ +#define SMBALERT_IE_OFFSET 0x10u +#define SMBALERT_IE_MASK 0x01u +#define SMBALERT_IE_SHIFT 0u + +/* + * SMBSUS_IE bits. + */ +#define SMBSUS_IE_OFFSET 0x10u +#define SMBSUS_IE_MASK 0x02u +#define SMBSUS_IE_SHIFT 1u + +/* + * SMB_IPMI_EN bits. + */ +#define SMB_IPMI_EN_OFFSET 0x10u +#define SMB_IPMI_EN_MASK 0x04u +#define SMB_IPMI_EN_SHIFT 2u + +/* + * SMBALERT_NI_STATUS bits. + */ +#define SMBALERT_NI_STATUS_OFFSET 0x10u +#define SMBALERT_NI_STATUS_MASK 0x08u +#define SMBALERT_NI_STATUS_SHIFT 3u + +/* + * SMBALERT_NO_CONTROL bits. + */ +#define SMBALERT_NO_CONTROL_OFFSET 0x10u +#define SMBALERT_NO_CONTROL_MASK 0x10u +#define SMBALERT_NO_CONTROL_SHIFT 4u + +/* + * SMBSUS_NI_STATUS bits. + */ +#define SMBSUS_NI_STATUS_OFFSET 0x10u +#define SMBSUS_NI_STATUS_MASK 0x20u +#define SMBSUS_NI_STATUS_SHIFT 5u + +/* + * SMBSUS_NO_CONTROL bits. + */ +#define SMBSUS_NO_CONTROL_OFFSET 0x10u +#define SMBSUS_NO_CONTROL_MASK 0x40u +#define SMBSUS_NO_CONTROL_SHIFT 6u + +/* + * SMBUS_MST_RESET bits. + */ +#define SMBUS_MST_RESET_OFFSET 0x10u +#define SMBUS_MST_RESET_MASK 0x80u +#define SMBUS_MST_RESET_SHIFT 7u + +/*------------------------------------------------------------------------------ + * SLAVE ADDRESS 1 register details + */ + +#define ADDRESS1_REG_OFFSET 0x1Cu + +/* + * SLAVE1_EN bit of Slave Address 1 . + */ +#define SLAVE1_EN_OFFSET 0x1Cu +#define SLAVE1_EN_MASK 0x01u +#define SLAVE1_EN_SHIFT 0u + +#endif /* __CORE_SMBUS_REGISTERS */ diff --git a/FreeRTOS/Demo/RISC-V_IGLOO2_Creative_SoftConsole/drivers/CoreI2C/i2c_interrupt.c b/FreeRTOS/Demo/RISC-V_IGLOO2_Creative_SoftConsole/drivers/CoreI2C/i2c_interrupt.c new file mode 100644 index 000000000..f918b8c9c --- /dev/null +++ b/FreeRTOS/Demo/RISC-V_IGLOO2_Creative_SoftConsole/drivers/CoreI2C/i2c_interrupt.c @@ -0,0 +1,35 @@ +/******************************************************************************* + * (c) Copyright 2009-2015 Microsemi SoC Products Group. All rights reserved. + * + * CoreI2C driver interrupt control. + * + * SVN $Revision: 7984 $ + * SVN $Date: 2015-10-12 12:07:40 +0530 (Mon, 12 Oct 2015) $ + */ +#include "hal.h" +#include "hal_assert.h" +#include "core_i2c.h" +#include "riscv_hal.h" + + +#define I2C_IRQn External_29_IRQn + +/*------------------------------------------------------------------------------ + * This function must be modified to enable interrupts generated from the + * CoreI2C instance identified as parameter. + */ +void I2C_enable_irq( i2c_instance_t * this_i2c ) +{ + PLIC_EnableIRQ(I2C_IRQn); +// HAL_ASSERT(0) +} + +/*------------------------------------------------------------------------------ + * This function must be modified to disable interrupts generated from the + * CoreI2C instance identified as parameter. + */ +void I2C_disable_irq( i2c_instance_t * this_i2c ) +{ + PLIC_DisableIRQ(I2C_IRQn); +// HAL_ASSERT(0) +} diff --git a/FreeRTOS/Demo/RISC-V_IGLOO2_Creative_SoftConsole/drivers/CoreTimer/core_timer.c b/FreeRTOS/Demo/RISC-V_IGLOO2_Creative_SoftConsole/drivers/CoreTimer/core_timer.c new file mode 100644 index 000000000..3f6720b16 --- /dev/null +++ b/FreeRTOS/Demo/RISC-V_IGLOO2_Creative_SoftConsole/drivers/CoreTimer/core_timer.c @@ -0,0 +1,158 @@ +/******************************************************************************* + * (c) Copyright 2007-2015 Microsemi SoC Products Group. All rights reserved. + * + * CoreTimer driver implementation. + * + * SVN $Revision: 7967 $ + * SVN $Date: 2015-10-09 18:48:26 +0530 (Fri, 09 Oct 2015) $ + */ + +#include "core_timer.h" +#include "coretimer_regs.h" +#include "hal.h" +#include "hal_assert.h" + +#ifndef NDEBUG +static timer_instance_t* NULL_timer_instance; +#endif + +/***************************************************************************//** + * TMR_init() + * See "core_timer.h" for details of how to use this function. + */ +void +TMR_init +( + timer_instance_t * this_timer, + addr_t address, + uint8_t mode, + uint32_t prescale, + uint32_t load_value +) +{ + HAL_ASSERT( this_timer != NULL_timer_instance ) + HAL_ASSERT( prescale <= PRESCALER_DIV_1024 ) + HAL_ASSERT( load_value != 0 ) + + this_timer->base_address = address; + + /* Disable interrupts. */ + HAL_set_32bit_reg_field( address, InterruptEnable,0 ); + + /* Disable timer. */ + HAL_set_32bit_reg_field( address, TimerEnable, 0 ); + + /* Clear pending interrupt. */ + HAL_set_32bit_reg( address, TimerIntClr, 1 ); + + /* Configure prescaler and load value. */ + HAL_set_32bit_reg( address, TimerPrescale, prescale ); + HAL_set_32bit_reg( address, TimerLoad, load_value ); + + /* Set the interrupt mode. */ + if ( mode == TMR_CONTINUOUS_MODE ) + { + HAL_set_32bit_reg_field( address, TimerMode, 0 ); + } + else + { + /* TMR_ONE_SHOT_MODE */ + HAL_set_32bit_reg_field( address, TimerMode, 1 ); + } +} + +/***************************************************************************//** + * TMR_start() + * See "core_timer.h" for details of how to use this function. + */ +void +TMR_start +( + timer_instance_t * this_timer +) +{ + HAL_ASSERT( this_timer != NULL_timer_instance ) + + HAL_set_32bit_reg_field( this_timer->base_address, TimerEnable, 1 ); +} + +/***************************************************************************//** + * TMR_stop() + * See "core_timer.h" for details of how to use this function. + */ +void +TMR_stop +( + timer_instance_t * this_timer +) +{ + HAL_ASSERT( this_timer != NULL_timer_instance ) + + HAL_set_32bit_reg_field( this_timer->base_address, TimerEnable, 0 ); +} + + +/***************************************************************************//** + * TMR_enable_int() + * See "core_timer.h" for details of how to use this function. + */ +void +TMR_enable_int +( + timer_instance_t * this_timer +) +{ + HAL_ASSERT( this_timer != NULL_timer_instance ) + + HAL_set_32bit_reg_field( this_timer->base_address, InterruptEnable, 1 ); +} + +/***************************************************************************//** + * TMR_clear_int() + * See "core_timer.h" for details of how to use this function. + */ +void +TMR_clear_int +( + timer_instance_t * this_timer +) +{ + HAL_ASSERT( this_timer != NULL_timer_instance ) + + HAL_set_32bit_reg( this_timer->base_address, TimerIntClr, 0x01 ); +} + +/***************************************************************************//** + * TMR_current_value() + * See "core_timer.h" for details of how to use this function. + */ +uint32_t +TMR_current_value +( + timer_instance_t * this_timer +) +{ + uint32_t value = 0; + HAL_ASSERT( this_timer != NULL_timer_instance ) + + value = HAL_get_32bit_reg( this_timer->base_address, TimerValue ); + + return value; +} + +/***************************************************************************//** + * TMR_reload() + * See "core_timer.h" for details of how to use this function. + */ +void TMR_reload +( + timer_instance_t * this_timer, + uint32_t load_value +) +{ + HAL_ASSERT( this_timer != NULL_timer_instance ) + HAL_ASSERT( load_value != 0 ) + + HAL_set_32bit_reg(this_timer->base_address, TimerLoad, load_value ); +} + diff --git a/FreeRTOS/Demo/RISC-V_IGLOO2_Creative_SoftConsole/drivers/CoreTimer/core_timer.h b/FreeRTOS/Demo/RISC-V_IGLOO2_Creative_SoftConsole/drivers/CoreTimer/core_timer.h new file mode 100644 index 000000000..04b7a6e97 --- /dev/null +++ b/FreeRTOS/Demo/RISC-V_IGLOO2_Creative_SoftConsole/drivers/CoreTimer/core_timer.h @@ -0,0 +1,206 @@ +/******************************************************************************* + * (c) Copyright 2007-2015 Microsemi SoC Products Group. All rights reserved. + * + * CoreTimer public API. + * + * SVN $Revision: 7967 $ + * SVN $Date: 2015-10-09 18:48:26 +0530 (Fri, 09 Oct 2015) $ + */ +#ifndef CORE_TIMER_H_ +#define CORE_TIMER_H_ + +#include "cpu_types.h" + +/***************************************************************************//** + * The following definitions are used to select the CoreTimer driver operating + * mode. They allow selecting continuous or one-shot mode. + * 1. Continuous Mode + * In continuous mode the timer's counter is decremented from the load value + * until it reaches zero. The timer counter is automatically reloaded, with the + * load value, upon reaching zero. An interrupt is generated every time the + * counter reaches zero if interrupt is enabled. + * This mode is typically used to generate an interrupt at constant time + * intervals. + * 2. One-shot mode: + * In one-shot mode, the counter decrements from the load value and until it + * reaches zero. An interrupt can be generated, if enabled, when the counter + * reaches zero. The timer's counter must be reloaded to begin counting down + * again. + */ +#define TMR_CONTINUOUS_MODE 0 +#define TMR_ONE_SHOT_MODE 1 + +/***************************************************************************//** + * The following definitions are used to configure the CoreTimer prescaler. + * The prescaler is used to divide down the clock used to decrement the + * CoreTimer counter. It can be configure to divide the clock by 2, 4, 8, + * 16, 32, 64, 128, 256, 512, or 1024. + */ +#define PRESCALER_DIV_2 0 +#define PRESCALER_DIV_4 1 +#define PRESCALER_DIV_8 2 +#define PRESCALER_DIV_16 3 +#define PRESCALER_DIV_32 4 +#define PRESCALER_DIV_64 5 +#define PRESCALER_DIV_128 6 +#define PRESCALER_DIV_256 7 +#define PRESCALER_DIV_512 8 +#define PRESCALER_DIV_1024 9 + +/***************************************************************************//** + * There should be one instance of this structure for each instance of CoreTimer + * in your system. The function TMR_init() initializes this structure. It is + * used to identify the various CoreTimer hardware instances in your system. + * An initialized timer instance structure should be passed as first parameter to + * CoreTimer driver functions to identify which CoreTimer instance should perform + * the requested operation. + * Software using this driver should only need to create one single instance of + * this data structure for each hardware timer instance in the system. + */ +typedef struct __timer_instance_t +{ + addr_t base_address; +} timer_instance_t; + +/***************************************************************************//** + * The function TMR_init() initializes the data structures and sets relevant + * CoreTimer registers. This function will prepare the Timer for use in a given + * hardware/software configuration. It should be called before any other Timer + * API functions. + * The timer will not start counting down immediately after this function is + * called. It is necessary to call TMR_start() to start the timer decrementing. + * The CoreTimer interrupt is disabled as part of this function. + * + * @param this_timer Pointer to a timer_instance_t structure holding all + * relevant data associated with the target timer hardware + * instance. This pointer will be used to identify the + * target CoreTimer hardware instance in subsequent calls + * to the CoreTimer functions. + * @param address Base address in the processor's memory map of the + * registers of the CoreTimer instance being initialized. + * @param mode This parameter is used to select the operating mode of + * the timer driver. This can be either TMR_CONTINUOUS_MODE + * or TMR_ONE_SHOT_MODE. + * @param prescale This parameter is used to select the prescaler divider + * used to divide down the clock used to decrement the + * timer’s counter. This can be set using one of the + * PRESCALER_DIV_ definitions, where is the + * divider’s value. + * @param load_value This parameter is used to set the timer’s load value + * from which the CoreTimer counter will decrement. + * In Continuous mode, this value will be used to reload + * the timer’s counter whenever it reaches zero. + */ +void +TMR_init +( + timer_instance_t * this_timer, + addr_t address, + uint8_t mode, + uint32_t prescale, + uint32_t load_value +); + +/***************************************************************************//** + * The function TMR_start() enables the timer to start counting down. + * This function only needs to be called once after the timer has been + * initialized through a call to TMR_init(). It does not need to be called after + * each call to TMR_reload() when the timer is used in one-shot mode. + * + * @param this_timer Pointer to a timer_instance_t structure holding all + * relevant data associated with the target timer hardware + * instance. This pointer is used to identify the target + * CoreTimer hardware instance. + */ +void +TMR_start +( + timer_instance_t * this_timer +); + +/***************************************************************************//** + * The function TMR_stop() stops the timer counting down. It can be used to + * stop interrupts from being generated when continuous mode is used and + * interrupts must be paused from being generated. + * + * @param this_timer Pointer to a timer_instance_t structure holding all + * relevant data associated with the target timer hardware + * instance. This pointer is used to identify the target + * CoreTimer hardware instance. + */ +void +TMR_stop +( + timer_instance_t * this_timer +); + +/***************************************************************************//** + * The function TMR_enable_int() enables the timer interrupt. A call to this + * function will allow the interrupt signal coming out of CoreTimer to be + * asserted. + * + * @param this_timer Pointer to a timer_instance_t structure holding all + * relevant data associated with the target timer hardware + * instance. This pointer is used to identify the target + * CoreTimer hardware instance. + */ +void +TMR_enable_int +( + timer_instance_t * this_timer +); + +/***************************************************************************//** + * The function TMR_clear_int() clears the timer interrupt. This function should + * be called within the interrupt handler servicing interrupts from the timer. + * Failure to clear the timer interrupt will result in the interrupt signal + * generating from CoreTimer to remain asserted. This assertion may cause the + * interrupt service routine to be continuously called, causing the system to + * lock up. + * + * @param this_timer Pointer to a timer_instance_t structure holding all + * relevant data associated with the target timer hardware + * instance. This pointer is used to identify the target + * CoreTimer hardware instance. + */ +void +TMR_clear_int +( + timer_instance_t * this_timer +); + +/***************************************************************************//** + * The TMR_current_value() function returns the current value of the counter. + * + * @param this_timer Pointer to a timer_instance_t structure holding all + * relevant data associated with the target timer hardware + * instance. This pointer is used to identify the target + * CoreTimer hardware instance. + * + * @return Returns the current value of the timer counter value. + */ +uint32_t +TMR_current_value +( + timer_instance_t * this_timer +); + +/***************************************************************************//** + * The TMR_reload() function is used in one-shot mode. It reloads the timer + * counter with the values passed as parameter. This will result in an interrupt + * being generated when the timer counter reaches 0 if interrupt is enabled. + * + * @param this_timer Pointer to a timer_instance_t structure holding all + * relevant data associated with the target timer hardware + * instance. This pointer is used to identify the target + * CoreTimer hardware instance. + * @param load_value This parameter sets the value from which the CoreTimer + * counter will decrement. + */ +void TMR_reload +( + timer_instance_t * this_timer, + uint32_t load_value +); + +#endif /* CORE_TIMER_H_ */ diff --git a/FreeRTOS/Demo/RISC-V_IGLOO2_Creative_SoftConsole/drivers/CoreTimer/coretimer_regs.h b/FreeRTOS/Demo/RISC-V_IGLOO2_Creative_SoftConsole/drivers/CoreTimer/coretimer_regs.h new file mode 100644 index 000000000..5d7c67da2 --- /dev/null +++ b/FreeRTOS/Demo/RISC-V_IGLOO2_Creative_SoftConsole/drivers/CoreTimer/coretimer_regs.h @@ -0,0 +1,109 @@ +/******************************************************************************* + * (c) Copyright 2007-2015 Microsemi SoC Products Group. All rights reserved. + * + * SVN $Revision: 7967 $ + * SVN $Date: 2015-10-09 18:48:26 +0530 (Fri, 09 Oct 2015) $ + */ + +#ifndef __CORE_TIMER_REGISTERS +#define __CORE_TIMER_REGISTERS 1 + +/*------------------------------------------------------------------------------ + * TimerLoad register details + */ +#define TimerLoad_REG_OFFSET 0x00 + +/* + * LoadValue bits. + */ +#define LoadValue_OFFSET 0x00 +#define LoadValue_MASK 0xFFFFFFFF +#define LoadValue_SHIFT 0 + +/*------------------------------------------------------------------------------ + * TimerValue register details + */ +#define TimerValue_REG_OFFSET 0x04 + +/* + * CurrentValue bits. + */ +#define CurrentValue_OFFSET 0x04 +#define CurrentValue_MASK 0xFFFFFFFF +#define CurrentValue_SHIFT 0 + +/*------------------------------------------------------------------------------ + * TimerControl register details + */ +#define TimerControl_REG_OFFSET 0x08 + +/* + * TimerEnable bits. + */ +#define TimerEnable_OFFSET 0x08 +#define TimerEnable_MASK 0x00000001 +#define TimerEnable_SHIFT 0 + +/* + * InterruptEnable bits. + */ +#define InterruptEnable_OFFSET 0x08 +#define InterruptEnable_MASK 0x00000002 +#define InterruptEnable_SHIFT 1 + +/* + * TimerMode bits. + */ +#define TimerMode_OFFSET 0x08 +#define TimerMode_MASK 0x00000004 +#define TimerMode_SHIFT 2 + +/*------------------------------------------------------------------------------ + * TimerPrescale register details + */ +#define TimerPrescale_REG_OFFSET 0x0C + +/* + * Prescale bits. + */ +#define Prescale_OFFSET 0x0C +#define Prescale_MASK 0x0000000F +#define Prescale_SHIFT 0 + +/*------------------------------------------------------------------------------ + * TimerIntClr register details + */ +#define TimerIntClr_REG_OFFSET 0x10 + +/* + * TimerIntClr bits. + */ +#define TimerIntClr_OFFSET 0x10 +#define TimerIntClr_MASK 0xFFFFFFFF +#define TimerIntClr_SHIFT 0 + +/*------------------------------------------------------------------------------ + * TimerRIS register details + */ +#define TimerRIS_REG_OFFSET 0x14 + +/* + * RawTimerInterrupt bits. + */ +#define RawTimerInterrupt_OFFSET 0x14 +#define RawTimerInterrupt_MASK 0x00000001 +#define RawTimerInterrupt_SHIFT 0 + +/*------------------------------------------------------------------------------ + * TimerMIS register details + */ +#define TimerMIS_REG_OFFSET 0x18 + +/* + * TimerInterrupt bits. + */ +#define TimerInterrupt_OFFSET 0x18 +#define TimerInterrupt_MASK 0x00000001 +#define TimerInterrupt_SHIFT 0 + +#endif /* __CORE_TIMER_REGISTERS */ diff --git a/FreeRTOS/Demo/RISC-V_IGLOO2_Creative_SoftConsole/drivers/CoreUARTapb/core_uart_apb.c b/FreeRTOS/Demo/RISC-V_IGLOO2_Creative_SoftConsole/drivers/CoreUARTapb/core_uart_apb.c new file mode 100644 index 000000000..b4f40dc1e --- /dev/null +++ b/FreeRTOS/Demo/RISC-V_IGLOO2_Creative_SoftConsole/drivers/CoreUARTapb/core_uart_apb.c @@ -0,0 +1,296 @@ +/******************************************************************************* + * (c) Copyright 2007-2017 Microsemi SoC Products Group. All rights reserved. + * + * CoreUARTapb driver implementation. See file "core_uart_apb.h" for a + * description of the functions implemented in this file. + * + * SVN $Revision: 9082 $ + * SVN $Date: 2017-04-28 11:51:36 +0530 (Fri, 28 Apr 2017) $ + */ +#include "hal.h" +#include "coreuartapb_regs.h" +#include "core_uart_apb.h" +#include "hal_assert.h" + +#ifdef __cplusplus +extern "C" { +#endif + +#define NULL_INSTANCE ( ( UART_instance_t* ) 0 ) +#define NULL_BUFFER ( ( uint8_t* ) 0 ) + +#define MAX_LINE_CONFIG ( ( uint8_t )( DATA_8_BITS | ODD_PARITY ) ) +#define MAX_BAUD_VALUE ( ( uint16_t )( 0x1FFF ) ) +#define STATUS_ERROR_MASK ( ( uint8_t )( STATUS_PARITYERR_MASK | \ + STATUS_OVERFLOW_MASK | \ + STATUS_FRAMERR_MASK ) ) +#define BAUDVALUE_LSB ( (uint16_t) (0x00FF) ) +#define BAUDVALUE_MSB ( (uint16_t) (0xFF00) ) +#define BAUDVALUE_SHIFT ( (uint8_t) (5) ) + +#define STATUS_ERROR_OFFSET STATUS_PARITYERR_SHIFT + +/***************************************************************************//** + * UART_init() + * See "core_uart_apb.h" for details of how to use this function. + */ +void +UART_init +( + UART_instance_t * this_uart, + addr_t base_addr, + uint16_t baud_value, + uint8_t line_config +) +{ + uint8_t rx_full; + + HAL_ASSERT( this_uart != NULL_INSTANCE ) + HAL_ASSERT( line_config <= MAX_LINE_CONFIG ) + HAL_ASSERT( baud_value <= MAX_BAUD_VALUE ) + + if( ( this_uart != NULL_INSTANCE ) && + ( line_config <= MAX_LINE_CONFIG ) && + ( baud_value <= MAX_BAUD_VALUE ) ) + { + /* + * Store lower 8-bits of baud value in CTRL1. + */ + HAL_set_8bit_reg( base_addr, CTRL1, (uint_fast8_t)(baud_value & + BAUDVALUE_LSB ) ); + + /* + * Extract higher 5-bits of baud value and store in higher 5-bits + * of CTRL2, along with line configuration in lower 3 three bits. + */ + HAL_set_8bit_reg( base_addr, CTRL2, (uint_fast8_t)line_config | + (uint_fast8_t)((baud_value & + BAUDVALUE_MSB) >> BAUDVALUE_SHIFT ) ); + + this_uart->base_address = base_addr; +#ifndef NDEBUG + { + uint8_t config; + uint8_t temp; + uint16_t baud_val; + baud_val = HAL_get_8bit_reg( this_uart->base_address, CTRL1 ); + config = HAL_get_8bit_reg( this_uart->base_address, CTRL2 ); + /* + * To resolve operator precedence between & and << + */ + temp = ( config & (uint8_t)(CTRL2_BAUDVALUE_MASK ) ); + baud_val |= (uint16_t)( (uint16_t)(temp) << BAUDVALUE_SHIFT ); + config &= (uint8_t)(~CTRL2_BAUDVALUE_MASK); + HAL_ASSERT( baud_val == baud_value ); + HAL_ASSERT( config == line_config ); + } +#endif + + /* + * Flush the receive FIFO of data that may have been received before the + * driver was initialized. + */ + rx_full = HAL_get_8bit_reg( this_uart->base_address, STATUS ) & + STATUS_RXFULL_MASK; + while ( rx_full ) + { + HAL_get_8bit_reg( this_uart->base_address, RXDATA ); + rx_full = HAL_get_8bit_reg( this_uart->base_address, STATUS ) & + STATUS_RXFULL_MASK; + } + + /* + * Clear status of the UART instance. + */ + this_uart->status = (uint8_t)0; + } +} + +/***************************************************************************//** + * UART_send() + * See "core_uart_apb.h" for details of how to use this function. + */ +void +UART_send +( + UART_instance_t * this_uart, + const uint8_t * tx_buffer, + size_t tx_size +) +{ + size_t char_idx; + uint8_t tx_ready; + + HAL_ASSERT( this_uart != NULL_INSTANCE ) + HAL_ASSERT( tx_buffer != NULL_BUFFER ) + HAL_ASSERT( tx_size > 0 ) + + if( (this_uart != NULL_INSTANCE) && + (tx_buffer != NULL_BUFFER) && + (tx_size > (size_t)0) ) + { + for ( char_idx = (size_t)0; char_idx < tx_size; char_idx++ ) + { + /* Wait for UART to become ready to transmit. */ + do { + tx_ready = HAL_get_8bit_reg( this_uart->base_address, STATUS ) & + STATUS_TXRDY_MASK; + } while ( !tx_ready ); + /* Send next character in the buffer. */ + HAL_set_8bit_reg( this_uart->base_address, TXDATA, + (uint_fast8_t)tx_buffer[char_idx] ); + } + } +} + +/***************************************************************************//** + * UART_fill_tx_fifo() + * See "core_uart_apb.h" for details of how to use this function. + */ +size_t +UART_fill_tx_fifo +( + UART_instance_t * this_uart, + const uint8_t * tx_buffer, + size_t tx_size +) +{ + uint8_t tx_ready; + size_t size_sent = 0u; + + HAL_ASSERT( this_uart != NULL_INSTANCE ) + HAL_ASSERT( tx_buffer != NULL_BUFFER ) + HAL_ASSERT( tx_size > 0 ) + + /* Fill the UART's Tx FIFO until the FIFO is full or the complete input + * buffer has been written. */ + if( (this_uart != NULL_INSTANCE) && + (tx_buffer != NULL_BUFFER) && + (tx_size > 0u) ) + { + tx_ready = HAL_get_8bit_reg( this_uart->base_address, STATUS ) & + STATUS_TXRDY_MASK; + if ( tx_ready ) + { + do { + HAL_set_8bit_reg( this_uart->base_address, TXDATA, + (uint_fast8_t)tx_buffer[size_sent] ); + size_sent++; + tx_ready = HAL_get_8bit_reg( this_uart->base_address, STATUS ) & + STATUS_TXRDY_MASK; + } while ( (tx_ready) && ( size_sent < tx_size ) ); + } + } + return size_sent; +} + +/***************************************************************************//** + * UART_get_rx() + * See "core_uart_apb.h" for details of how to use this function. + */ +size_t +UART_get_rx +( + UART_instance_t * this_uart, + uint8_t * rx_buffer, + size_t buff_size +) +{ + uint8_t new_status; + uint8_t rx_full; + size_t rx_idx = 0u; + + HAL_ASSERT( this_uart != NULL_INSTANCE ) + HAL_ASSERT( rx_buffer != NULL_BUFFER ) + HAL_ASSERT( buff_size > 0 ) + + if( (this_uart != NULL_INSTANCE) && + (rx_buffer != NULL_BUFFER) && + (buff_size > 0u) ) + { + rx_idx = 0u; + new_status = HAL_get_8bit_reg( this_uart->base_address, STATUS ); + this_uart->status |= new_status; + rx_full = new_status & STATUS_RXFULL_MASK; + while ( ( rx_full ) && ( rx_idx < buff_size ) ) + { + rx_buffer[rx_idx] = HAL_get_8bit_reg( this_uart->base_address, + RXDATA ); + rx_idx++; + new_status = HAL_get_8bit_reg( this_uart->base_address, STATUS ); + this_uart->status |= new_status; + rx_full = new_status & STATUS_RXFULL_MASK; + } + } + return rx_idx; +} + +/***************************************************************************//** + * UART_polled_tx_string() + * See "core_uart_apb.h" for details of how to use this function. + */ +void +UART_polled_tx_string +( + UART_instance_t * this_uart, + const uint8_t * p_sz_string +) +{ + uint32_t char_idx; + uint8_t tx_ready; + + HAL_ASSERT( this_uart != NULL_INSTANCE ) + HAL_ASSERT( p_sz_string != NULL_BUFFER ) + + if( ( this_uart != NULL_INSTANCE ) && ( p_sz_string != NULL_BUFFER ) ) + { + char_idx = 0U; + while( 0U != p_sz_string[char_idx] ) + { + /* Wait for UART to become ready to transmit. */ + do { + tx_ready = HAL_get_8bit_reg( this_uart->base_address, STATUS ) & + STATUS_TXRDY_MASK; + } while ( !tx_ready ); + /* Send next character in the buffer. */ + HAL_set_8bit_reg( this_uart->base_address, TXDATA, + (uint_fast8_t)p_sz_string[char_idx] ); + char_idx++; + } + } +} + +/***************************************************************************//** + * UART_get_rx_status() + * See "core_uart_apb.h" for details of how to use this function. + */ +uint8_t +UART_get_rx_status +( + UART_instance_t * this_uart +) +{ + uint8_t status = UART_APB_INVALID_PARAM; + + HAL_ASSERT( this_uart != NULL_INSTANCE ) + /* + * Extract UART error status and place in lower bits of "status". + * Bit 0 - Parity error status + * Bit 1 - Overflow error status + * Bit 2 - Frame error status + */ + if( this_uart != NULL_INSTANCE ) + { + status = ( ( this_uart->status & STATUS_ERROR_MASK ) >> + STATUS_ERROR_OFFSET ); + /* + * Clear the sticky status for this instance. + */ + this_uart->status = (uint8_t)0; + } + return status; +} + +#ifdef __cplusplus +} +#endif diff --git a/FreeRTOS/Demo/RISC-V_IGLOO2_Creative_SoftConsole/drivers/CoreUARTapb/core_uart_apb.h b/FreeRTOS/Demo/RISC-V_IGLOO2_Creative_SoftConsole/drivers/CoreUARTapb/core_uart_apb.h new file mode 100644 index 000000000..680b68d5b --- /dev/null +++ b/FreeRTOS/Demo/RISC-V_IGLOO2_Creative_SoftConsole/drivers/CoreUARTapb/core_uart_apb.h @@ -0,0 +1,407 @@ +/******************************************************************************* + * (c) Copyright 2007-2017 Microsemi SoC Products Group. All rights reserved. + * + * This file contains the application programming interface for the CoreUARTapb + * bare metal driver. + * + * SVN $Revision: 9082 $ + * SVN $Date: 2017-04-28 11:51:36 +0530 (Fri, 28 Apr 2017) $ + */ +/*=========================================================================*//** + @mainpage CoreUARTapb Bare Metal Driver. + + @section intro_sec Introduction + CoreUARTapb is an implementation of the Universal Asynchronous + Receiver/Transmitter aimed at a minimal FPGA tile usage within an Microsemi + FPGA. The CoreUARTapb bare metal software driver is designed for use in + systems with no operating system. + + The CoreUARTapb driver provides functions for basic polled transmitting and + receiving operations. It also provides functions allowing use of the + CoreUARTapb in interrupt-driven mode, but leaves the management of interrupts + to the calling application, as interrupt enabling and disabling cannot be + controlled through the CoreUARTapb registers. The CoreUARTapb driver is + provided as C source code. + + @section driver_configuration Driver Configuration + Your application software should configure the CoreUARTapb driver, through + calls to the UART_init() function for each CoreUARTapb instance in the + hardware design. The configuration parameters include the CoreUARTapb + hardware instance base address and other runtime parameters, such as baud + rate, bit width, and parity. No CoreUARTapb hardware configuration parameters + are needed by the driver, apart from the CoreUARTapb hardware instance base + address. Hence, no additional configuration files are required to use the driver. + + A CoreUARTapb hardware instance can be generated with fixed baud value, + character size and parity configuration settings as part of the hardware flow. + The baud_value and line_config parameter values passed to the UART_init() + function will not have any effect if fixed values were selected for the + baud value, character size and parity in the hardware configuration of + CoreUARTapb. When fixed values are selected for these hardware configuration + parameters, the driver cannot overwrite the fixed values in the CoreUARTapb + control registers, CTRL1 and CTRL2. + + @section theory_op Theory of Operation + The CoreUARTapb software driver is designed to allow the control of multiple + instances of CoreUARTapb. Each instance of CoreUARTapb in the hardware design + is associated with a single instance of the UART_instance_t structure in the + software. You need to allocate memory for one unique UART_instance_t + structure instance for each CoreUARTapb hardware instance. The contents of + these data structures are initialized during calls to function UART_init(). + A pointer to the structure is passed to subsequent driver functions in order + to identify the CoreUARTapb hardware instance you wish to perform the + requested operation on. + + Note: Do not attempt to directly manipulate the content of UART_instance_t + structures. This structure is only intended to be modified by the driver + function. + + The driver can be used to transmit and receive data once initialized. + Transmit can be performed using the UART_send() function. This function + is blocking, meaning that it will only return once the data passed to + the function has been sent to the CoreUARTapb hardware. Data received + by the CoreUARTapb hardware can be read by the user application using + the UART_get_rx() function. + + The function UART_fill_tx_fifo() is also provided to be used as part of + interrupt-driven transmit. This function fills the CoreUARTapb hardware + transmit FIFO with the content of a data buffer passed as a parameter before + returning. The control of the interrupts must be implemented outside the + driver as the CoreUARTapb hardware does not provide the ability to enable + or disable its interrupt sources. + + The function UART_polled_tx_string() is provided to transmit a NULL + terminated string in polled mode. This function is blocking, meaning that it + will only return once the data passed to the function has been sent to the + CoreUARTapb hardware. + + The function UART_get_rx_status() returns the error status of the CoreUARTapb + receiver. This can be used by applications to take appropriate action in case + of receiver errors. +*//*=========================================================================*/ +#ifndef __CORE_UART_APB_H +#define __CORE_UART_APB_H 1 + +#include "cpu_types.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/***************************************************************************//** + * Data bits length defines: + */ +#define DATA_7_BITS 0x00u +#define DATA_8_BITS 0x01u + +/***************************************************************************//** + * Parity defines: + */ +#define NO_PARITY 0x00u +#define EVEN_PARITY 0x02u +#define ODD_PARITY 0x06u + +/***************************************************************************//** + * Error Status definitions: + */ +#define UART_APB_PARITY_ERROR 0x01u +#define UART_APB_OVERFLOW_ERROR 0x02u +#define UART_APB_FRAMING_ERROR 0x04u +#define UART_APB_NO_ERROR 0x00u +#define UART_APB_INVALID_PARAM 0xFFu + +/***************************************************************************//** + * UART_instance_t + * + * There should be one instance of this structure for each instance of CoreUARTapb + * in your system. This structure instance is used to identify the various UARTs + * in a system and should be passed as first parameter to UART functions to + * identify which UART should perform the requested operation. The 'status' + * element in the structure is used to provide sticky status information. + */ +typedef struct +{ + addr_t base_address; + uint8_t status; +} UART_instance_t; + +/***************************************************************************//** + * The function UART_init() initializes the UART with the configuration passed + * as parameters. The configuration parameters are the baud_value used to + * generate the baud rate and the line configuration (bit length and parity). + * + * @param this_uart The this_uart parameter is a pointer to a UART_instance_t + * structure which holds all data regarding this instance of + * the CoreUARTapb. This pointer will be used to identify + * the target CoreUARTapb hardware instance in subsequent + * calls to the CoreUARTapb functions. + * @param base_addr The base_address parameter is the base address in the + * processor's memory map for the registers of the + * CoreUARTapb instance being initialized. + * @param baud_value The baud_value parameter is used to select the baud rate + * for the UART. The baud value is calculated from the + * frequency of the system clock in hertz and the desired + * baud rate using the following equation: + * + * baud_value = (clock /(baud_rate * 16)) - 1. + * + * The baud_value parameter must be a value in the range 0 + * to 8191 (or 0x0000 to 0x1FFF). + * @param line_config This parameter is the line configuration specifying the + * bit length and parity settings. This is a logical OR of: + * - DATA_7_BITS + * - DATA_8_BITS + * - NO_PARITY + * - EVEN_PARITY + * - ODD_PARITY + * For example, 8 bits even parity would be specified as + * (DATA_8_BITS | EVEN_PARITY). + * @return This function does not return a value. + * Example: + * @code + * #define BAUD_VALUE_57600 25 + * + * #define COREUARTAPB0_BASE_ADDR 0xC3000000UL + * + * UART_instance_t g_uart; + * int main() + * { + * UART_init(&g_uart, COREUARTAPB0_BASE_ADDR, + BAUD_VALUE_57600, (DATA_8_BITS | EVEN_PARITY)); + * } + * @endcode + */ +void +UART_init +( + UART_instance_t * this_uart, + addr_t base_addr, + uint16_t baud_value, + uint8_t line_config +); + +/***************************************************************************//** + * The function UART_send() is used to transmit data. It transfers the contents + * of the transmitter data buffer, passed as a function parameter, into the + * UART's hardware transmitter FIFO. It returns when the full content of the + * transmitter data buffer has been transferred to the UART's transmitter FIFO. + * + * Note: you cannot assume that the data you are sending using this function has + * been received at the other end by the time this function returns. The actual + * transmit over the serial connection will still be taking place at the time of + * the function return. It is safe to release or reuse the memory used as the + * transmit buffer once this function returns. + * + * @param this_uart The this_uart parameter is a pointer to a + * UART_instance_t structure which holds all data regarding + * this instance of the CoreUARTapbUART. + * @param tx_buffer The tx_buffer parameter is a pointer to a buffer + * containing the data to be transmitted. + * @param tx_size The tx_size parameter is the size, in bytes, of + * the data to be transmitted. + * + * @return This function does not return a value. + * + * Example: + * @code + * uint8_t testmsg1[] = {"\n\r\n\r\n\rUART_send() test message 1"}; + * UART_send(&g_uart,(const uint8_t *)&testmsg1,sizeof(testmsg1)); + * @endcode + */ +void +UART_send +( + UART_instance_t * this_uart, + const uint8_t * tx_buffer, + size_t tx_size +); + +/***************************************************************************//** + * The function UART_fill_tx_fifo() fills the UART's transmitter hardware FIFO + * with the data found in the transmitter buffer that is passed in as a + * function parameter. The function returns either when the FIFO is full or + * when the complete contents of the transmitter buffer have been copied into + * the FIFO. It returns the number of bytes copied into the UART's transmitter + * hardware FIFO. This function is intended to be used as part of + * interrupt-driven transmission. + * + * Note: You cannot assume that the data you transmit using this function has + * been received at the other end by the time this function returns. + * The actual transmission over the serial connection will still be + * taking place at the time of the function return. + * + * @param this_uart The this_uart parameter is a pointer to a UART_instance_t + * structure which holds all data regarding this instance of + * the UART. + * @param tx_buffer The tx_buffer parameter is a pointer to a buffer + * containing the data to be transmitted. + * @param tx_size The tx_size parameter is the size in bytes, of the data + * to be transmitted. + * @return This function returns the number of bytes copied + * into the UART's transmitter hardware FIFO. + * + * Example: + * @code + * void send_using_interrupt + * ( + * uint8_t * pbuff, + * size_t tx_size + * ) + * { + * size_t size_in_fifo; + * size_in_fifo = UART_fill_tx_fifo( &g_uart, pbuff, tx_size ); + * } + * @endcode + */ +size_t +UART_fill_tx_fifo +( + UART_instance_t * this_uart, + const uint8_t * tx_buffer, + size_t tx_size +); + +/***************************************************************************//** + * The function UART_get_rx() reads the content of the UART's receiver hardware + * FIFO and stores it in the receiver buffer that is passed in as a function + * parameter. It copies either the full contents of the FIFO into the receiver + * buffer, or just enough data from the FIFO to fill the receiver buffer, + * dependent upon the size of the receiver buffer. The size of the receiver + * buffer is passed in as a function parameter. UART_get_rx() returns the number + * of bytes copied into the receiver buffer. If no data was received at the time + * the function is called, the function returns 0. + * + * Note: This function reads and accumulates the receiver status of the + * CoreUARTapb instance before reading each byte from the receiver's + * data register/FIFO. This allows the driver to maintain a sticky + * record of any receiver errors that occur as the UART receives each + * data byte; receiver errors would otherwise be lost after each read + * from the receiver's data register. A call to the UART_get_rx_status() + * function returns any receiver errors accumulated during the execution + * of the UART_get_rx() function. + * Note: When FIFO mode is disabled in the CoreUARTapb hardware configuration, + * the driver accumulates a sticky record of any parity errors, framing + * errors or overflow errors. When FIFO mode is enabled, the driver + * accumulates a sticky record of overflow errors only; in this case + * interrupts must be used to handle parity errors or framing errors. + * + * @param this_uart The this_uart parameter is a pointer to a UART_instance_t + * structure which holds all data regarding this instance of + * the UART. + * @param rx_buffer The rx_buffer parameter is a pointer to a buffer where the + * received data will be copied. + * @param buff_size The buff_size parameter is the size of the receive buffer + * in bytes. + * @return This function returns the number of bytes copied into the + * receive buffer. + * + * Example: + * @code + * #define MAX_RX_DATA_SIZE 256 + * + * uint8_t rx_data[MAX_RX_DATA_SIZE]; + * uint8_t rx_size = 0; + * + * rx_size = UART_get_rx( &g_uart, rx_data, sizeof(rx_data) ); + * @endcode + */ +size_t +UART_get_rx +( + UART_instance_t * this_uart, + uint8_t * rx_buffer, + size_t buff_size +); + +/***************************************************************************//** + * The function UART_polled_tx_string() is used to transmit a NULL ('\0') + * terminated string. Internally, it polls for the transmit ready status and + * transfers the text starting at the address pointed to by p_sz_string into + * the UART's hardware transmitter FIFO. It is a blocking function and returns + * only when the complete string has been transferred to the UART's transmit + * FIFO. + * + * Note: You cannot assume that the data you transmit using this function + * has been received at the other end by the time this function + * returns. The actual transmission over the serial connection will + * still be taking place at the time of the function return. + * + * @param this_uart The this_uart parameter is a pointer to a + * UART_instance_t structure which holds + * all data regarding this instance of the UART. + * @param p_sz_string The p_sz_string parameter is a pointer to a buffer + * containing the NULL ('\0') terminated string to be + * transmitted. + * @return This function does not return a value. + * + * Example: + * @code + * uint8_t testmsg1[] = {"\r\n\r\nUART_polled_tx_string() test message 1\0"}; + * UART_polled_tx_string(&g_uart,(const uint8_t *)&testmsg1); + * @endcode + */ +void +UART_polled_tx_string +( + UART_instance_t * this_uart, + const uint8_t * p_sz_string +); + +/***************************************************************************//** + * The UART_get_rx_status() function returns the receiver error status of the + * CoreUARTapb instance. It reads both the current error status of the receiver + * and the accumulated error status from preceding calls to the UART_get_rx() + * function and combines them using a bitwise OR. It returns the cumulative + * parity, framing and overflow error status of the receiver, since the + * previous call to UART_get_rx_status(), as an 8-bit encoded value. + * + * Note: The UART_get_rx() function reads and accumulates the receiver status + * of the CoreUARTapb instance before reading each byte from the + * receiver's data register/FIFO. The driver maintains a sticky record + * of the cumulative error status, which persists after the + * UART_get_rx() function returns. The UART_get_rx_status() function + * clears this accumulated record of receiver errors before returning. + * + * @param this_uart The this_uart parameter is a pointer to a UART_instance_t + * structure which holds all data regarding this instance + * of the UART. + * @return This function returns the UART receiver error status as + * an 8-bit encoded value. The returned value is 0 if no + * receiver errors occurred. The driver provides a set of + * bit mask constants which should be compared with and/or + * used to mask the returned value to determine the + * receiver error status. + * When the return value is compared to the following bit + * masks, a non-zero result indicates that the + * corresponding error occurred: + * UART_APB_PARITY_ERROR (bit mask = 0x01) + * UART_APB_OVERFLOW_ERROR (bit mask = 0x02) + * UART_APB_FRAMING_ERROR (bit mask = 0x04) + * When the return value is compared to the following bit + * mask, a non-zero result indicates that no error occurred: + * UART_APB_NO_ERROR (0x00) + * + * Example: + * @code + * UART_instance_t g_uart; + * uint8_t rx_data[MAX_RX_DATA_SIZE]; + * uint8_t err_status; + * err_status = UART_get_err_status(&g_uart); + * + * if(UART_APB_NO_ERROR == err_status ) + * { + * rx_size = UART_get_rx( &g_uart, rx_data, MAX_RX_DATA_SIZE ); + * } + * @endcode + */ +uint8_t +UART_get_rx_status +( + UART_instance_t * this_uart +); + +#ifdef __cplusplus +} +#endif + +#endif /* __CORE_UART_APB_H */ diff --git a/FreeRTOS/Demo/RISC-V_IGLOO2_Creative_SoftConsole/drivers/CoreUARTapb/coreuartapb_regs.h b/FreeRTOS/Demo/RISC-V_IGLOO2_Creative_SoftConsole/drivers/CoreUARTapb/coreuartapb_regs.h new file mode 100644 index 000000000..e6cc8c1da --- /dev/null +++ b/FreeRTOS/Demo/RISC-V_IGLOO2_Creative_SoftConsole/drivers/CoreUARTapb/coreuartapb_regs.h @@ -0,0 +1,130 @@ +/******************************************************************************* + * (c) Copyright 2007-2017 Microsemi SoC Products Group. All rights reserved. + * + * SVN $Revision: 9082 $ + * SVN $Date: 2017-04-28 11:51:36 +0530 (Fri, 28 Apr 2017) $ + */ + +#ifndef __CORE_UART_APB_REGISTERS +#define __CORE_UART_APB_REGISTERS 1 + +#ifdef __cplusplus +extern "C" { +#endif + +/*------------------------------------------------------------------------------ + * TxData register details + */ +#define TXDATA_REG_OFFSET 0x0u + +/* + * TxData bits. + */ +#define TXDATA_OFFSET 0x0u +#define TXDATA_MASK 0xFFu +#define TXDATA_SHIFT 0u + +/*------------------------------------------------------------------------------ + * RxData register details + */ +#define RXDATA_REG_OFFSET 0x4u + +/* + * RxData bits. + */ +#define RXDATA_OFFSET 0x4u +#define RXDATA_MASK 0xFFu +#define RXDATA_SHIFT 0u + +/*------------------------------------------------------------------------------ + * ControReg1 register details + */ +#define CTRL1_REG_OFFSET 0x8u + +/* + * Baud value (Lower 8-bits) + */ +#define CTRL1_BAUDVALUE_OFFSET 0x8u +#define CTRL1_BAUDVALUE_MASK 0xFFu +#define CTRL1_BAUDVALUE_SHIFT 0u + +/*------------------------------------------------------------------------------ + * ControReg2 register details + */ +#define CTRL2_REG_OFFSET 0xCu + +/* + * Bit length + */ +#define CTRL2_BIT_LENGTH_OFFSET 0xCu +#define CTRL2_BIT_LENGTH_MASK 0x01u +#define CTRL2_BIT_LENGTH_SHIFT 0u + +/* + * Parity enable. + */ +#define CTRL2_PARITY_EN_OFFSET 0xCu +#define CTRL2_PARITY_EN_MASK 0x02u +#define CTRL2_PARITY_EN_SHIFT 1u + +/* + * Odd/even parity selection. + */ +#define CTRL2_ODD_EVEN_OFFSET 0xCu +#define CTRL2_ODD_EVEN_MASK 0x04u +#define CTRL2_ODD_EVEN_SHIFT 2u + +/* + * Baud value (Higher 5-bits) + */ +#define CTRL2_BAUDVALUE_OFFSET 0xCu +#define CTRL2_BAUDVALUE_MASK 0xF8u +#define CTRL2_BAUDVALUE_SHIFT 3u + +/*------------------------------------------------------------------------------ + * StatusReg register details + */ +#define StatusReg_REG_OFFSET 0x10u + +#define STATUS_REG_OFFSET 0x10u + +/* + * Transmit ready. + */ +#define STATUS_TXRDY_OFFSET 0x10u +#define STATUS_TXRDY_MASK 0x01u +#define STATUS_TXRDY_SHIFT 0u + +/* + * Receive full. + */ +#define STATUS_RXFULL_OFFSET 0x10u +#define STATUS_RXFULL_MASK 0x02u +#define STATUS_RXFULL_SHIFT 1u + +/* + * Parity error. + */ +#define STATUS_PARITYERR_OFFSET 0x10u +#define STATUS_PARITYERR_MASK 0x04u +#define STATUS_PARITYERR_SHIFT 2u + +/* + * Overflow. + */ +#define STATUS_OVERFLOW_OFFSET 0x10u +#define STATUS_OVERFLOW_MASK 0x08u +#define STATUS_OVERFLOW_SHIFT 3u + +/* + * Frame Error. + */ +#define STATUS_FRAMERR_OFFSET 0x10u +#define STATUS_FRAMERR_MASK 0x10u +#define STATUS_FRAMERR_SHIFT 4u + +#ifdef __cplusplus +} +#endif + +#endif /* __CORE_UART_APB_REGISTERS */ diff --git a/FreeRTOS/Demo/RISC-V_IGLOO2_Creative_SoftConsole/hal/cpu_types.h b/FreeRTOS/Demo/RISC-V_IGLOO2_Creative_SoftConsole/hal/cpu_types.h new file mode 100644 index 000000000..1beae8c96 --- /dev/null +++ b/FreeRTOS/Demo/RISC-V_IGLOO2_Creative_SoftConsole/hal/cpu_types.h @@ -0,0 +1,31 @@ +/******************************************************************************* + * (c) Copyright 2007-2018 Microsemi SoC Products Group. All rights reserved. + * + * SVN $Revision: 9661 $ + * SVN $Date: 2018-01-15 16:13:33 +0530 (Mon, 15 Jan 2018) $ + */ +#ifndef __CPU_TYPES_H +#define __CPU_TYPES_H 1 + +#include + +/*------------------------------------------------------------------------------ + */ +typedef unsigned int size_t; + +/*------------------------------------------------------------------------------ + * addr_t: address type. + * Used to specify the address of peripherals present in the processor's memory + * map. + */ +typedef unsigned int addr_t; + +/*------------------------------------------------------------------------------ + * psr_t: processor state register. + * Used by HAL_disable_interrupts() and HAL_restore_interrupts() to store the + * processor's state between disabling and restoring interrupts. + */ +typedef unsigned int psr_t; + +#endif /* __CPU_TYPES_H */ + diff --git a/FreeRTOS/Demo/RISC-V_IGLOO2_Creative_SoftConsole/hal/hal.h b/FreeRTOS/Demo/RISC-V_IGLOO2_Creative_SoftConsole/hal/hal.h new file mode 100644 index 000000000..5b82ed07d --- /dev/null +++ b/FreeRTOS/Demo/RISC-V_IGLOO2_Creative_SoftConsole/hal/hal.h @@ -0,0 +1,207 @@ +/***************************************************************************//** + * (c) Copyright 2007-2018 Microsemi SoC Products Group. All rights reserved. + * + * Hardware abstraction layer functions. + * + * SVN $Revision: 9661 $ + * SVN $Date: 2018-01-15 16:13:33 +0530 (Mon, 15 Jan 2018) $ + */ +#ifndef HAL_H_ +#define HAL_H_ + +#include "cpu_types.h" +#include "hw_reg_access.h" + +/***************************************************************************//** + * Enable all interrupts at the processor level. + */ +void HAL_enable_interrupts( void ); + +/***************************************************************************//** + * Disable all interrupts at the processor core level. + * Return the interrupts enable state before disabling occured so that it can + * later be restored. + */ +psr_t HAL_disable_interrupts( void ); + +/***************************************************************************//** + * Restore the interrupts enable state at the processor core level. + * This function is normally passed the value returned from a previous call to + * HAL_disable_interrupts(). + */ +void HAL_restore_interrupts( psr_t saved_psr ); + +/***************************************************************************//** + */ +#define FIELD_OFFSET(FIELD_NAME) (FIELD_NAME##_OFFSET) +#define FIELD_SHIFT(FIELD_NAME) (FIELD_NAME##_SHIFT) +#define FIELD_MASK(FIELD_NAME) (FIELD_NAME##_MASK) + +/***************************************************************************//** + * The macro HAL_set_32bit_reg() allows writing a 32 bits wide register. + * + * BASE_ADDR: A variable of type addr_t specifying the base address of the + * peripheral containing the register. + * REG_NAME: A string identifying the register to write. These strings are + * specified in a header file associated with the peripheral. + * VALUE: A variable of type uint32_t containing the value to write. + */ +#define HAL_set_32bit_reg(BASE_ADDR, REG_NAME, VALUE) \ + (HW_set_32bit_reg( ((BASE_ADDR) + (REG_NAME##_REG_OFFSET)), (VALUE) )) + +/***************************************************************************//** + * The macro HAL_get_32bit_reg() is used to read the value of a 32 bits wide + * register. + * + * BASE_ADDR: A variable of type addr_t specifying the base address of the + * peripheral containing the register. + * REG_NAME: A string identifying the register to read. These strings are + * specified in a header file associated with the peripheral. + * RETURN: This function-like macro returns a uint32_t value. + */ +#define HAL_get_32bit_reg(BASE_ADDR, REG_NAME) \ + (HW_get_32bit_reg( ((BASE_ADDR) + (REG_NAME##_REG_OFFSET)) )) + +/***************************************************************************//** + * The macro HAL_set_32bit_reg_field() is used to write a field within a + * 32 bits wide register. The field written can be one or more bits. + * + * BASE_ADDR: A variable of type addr_t specifying the base address of the + * peripheral containing the register. + * FIELD_NAME: A string identifying the register field to write. These strings + * are specified in a header file associated with the peripheral. + * VALUE: A variable of type uint32_t containing the field value to write. + */ +#define HAL_set_32bit_reg_field(BASE_ADDR, FIELD_NAME, VALUE) \ + (HW_set_32bit_reg_field(\ + (BASE_ADDR) + FIELD_OFFSET(FIELD_NAME),\ + FIELD_SHIFT(FIELD_NAME),\ + FIELD_MASK(FIELD_NAME),\ + (VALUE))) + +/***************************************************************************//** + * The macro HAL_get_32bit_reg_field() is used to read a register field from + * within a 32 bit wide peripheral register. The field can be one or more bits. + * + * BASE_ADDR: A variable of type addr_t specifying the base address of the + * peripheral containing the register. + * FIELD_NAME: A string identifying the register field to write. These strings + * are specified in a header file associated with the peripheral. + * RETURN: This function-like macro returns a uint32_t value. + */ +#define HAL_get_32bit_reg_field(BASE_ADDR, FIELD_NAME) \ + (HW_get_32bit_reg_field(\ + (BASE_ADDR) + FIELD_OFFSET(FIELD_NAME),\ + FIELD_SHIFT(FIELD_NAME),\ + FIELD_MASK(FIELD_NAME))) + +/***************************************************************************//** + * The macro HAL_set_16bit_reg() allows writing a 16 bits wide register. + * + * BASE_ADDR: A variable of type addr_t specifying the base address of the + * peripheral containing the register. + * REG_NAME: A string identifying the register to write. These strings are + * specified in a header file associated with the peripheral. + * VALUE: A variable of type uint_fast16_t containing the value to write. + */ +#define HAL_set_16bit_reg(BASE_ADDR, REG_NAME, VALUE) \ + (HW_set_16bit_reg( ((BASE_ADDR) + (REG_NAME##_REG_OFFSET)), (VALUE) )) + +/***************************************************************************//** + * The macro HAL_get_16bit_reg() is used to read the value of a 16 bits wide + * register. + * + * BASE_ADDR: A variable of type addr_t specifying the base address of the + * peripheral containing the register. + * REG_NAME: A string identifying the register to read. These strings are + * specified in a header file associated with the peripheral. + * RETURN: This function-like macro returns a uint16_t value. + */ +#define HAL_get_16bit_reg(BASE_ADDR, REG_NAME) \ + (HW_get_16bit_reg( (BASE_ADDR) + (REG_NAME##_REG_OFFSET) )) + +/***************************************************************************//** + * The macro HAL_set_16bit_reg_field() is used to write a field within a + * 16 bits wide register. The field written can be one or more bits. + * + * BASE_ADDR: A variable of type addr_t specifying the base address of the + * peripheral containing the register. + * FIELD_NAME: A string identifying the register field to write. These strings + * are specified in a header file associated with the peripheral. + * VALUE: A variable of type uint16_t containing the field value to write. + */ +#define HAL_set_16bit_reg_field(BASE_ADDR, FIELD_NAME, VALUE) \ + (HW_set_16bit_reg_field(\ + (BASE_ADDR) + FIELD_OFFSET(FIELD_NAME),\ + FIELD_SHIFT(FIELD_NAME),\ + FIELD_MASK(FIELD_NAME),\ + (VALUE))) + +/***************************************************************************//** + * The macro HAL_get_16bit_reg_field() is used to read a register field from + * within a 8 bit wide peripheral register. The field can be one or more bits. + * + * BASE_ADDR: A variable of type addr_t specifying the base address of the + * peripheral containing the register. + * FIELD_NAME: A string identifying the register field to write. These strings + * are specified in a header file associated with the peripheral. + * RETURN: This function-like macro returns a uint16_t value. + */ +#define HAL_get_16bit_reg_field(BASE_ADDR, FIELD_NAME) \ + (HW_get_16bit_reg_field(\ + (BASE_ADDR) + FIELD_OFFSET(FIELD_NAME),\ + FIELD_SHIFT(FIELD_NAME),\ + FIELD_MASK(FIELD_NAME))) + +/***************************************************************************//** + * The macro HAL_set_8bit_reg() allows writing a 8 bits wide register. + * + * BASE_ADDR: A variable of type addr_t specifying the base address of the + * peripheral containing the register. + * REG_NAME: A string identifying the register to write. These strings are + * specified in a header file associated with the peripheral. + * VALUE: A variable of type uint_fast8_t containing the value to write. + */ +#define HAL_set_8bit_reg(BASE_ADDR, REG_NAME, VALUE) \ + (HW_set_8bit_reg( ((BASE_ADDR) + (REG_NAME##_REG_OFFSET)), (VALUE) )) + +/***************************************************************************//** + * The macro HAL_get_8bit_reg() is used to read the value of a 8 bits wide + * register. + * + * BASE_ADDR: A variable of type addr_t specifying the base address of the + * peripheral containing the register. + * REG_NAME: A string identifying the register to read. These strings are + * specified in a header file associated with the peripheral. + * RETURN: This function-like macro returns a uint8_t value. + */ +#define HAL_get_8bit_reg(BASE_ADDR, REG_NAME) \ + (HW_get_8bit_reg( (BASE_ADDR) + (REG_NAME##_REG_OFFSET) )) + +/***************************************************************************//** + */ +#define HAL_set_8bit_reg_field(BASE_ADDR, FIELD_NAME, VALUE) \ + (HW_set_8bit_reg_field(\ + (BASE_ADDR) + FIELD_OFFSET(FIELD_NAME),\ + FIELD_SHIFT(FIELD_NAME),\ + FIELD_MASK(FIELD_NAME),\ + (VALUE))) + +/***************************************************************************//** + * The macro HAL_get_8bit_reg_field() is used to read a register field from + * within a 8 bit wide peripheral register. The field can be one or more bits. + * + * BASE_ADDR: A variable of type addr_t specifying the base address of the + * peripheral containing the register. + * FIELD_NAME: A string identifying the register field to write. These strings + * are specified in a header file associated with the peripheral. + * RETURN: This function-like macro returns a uint8_t value. + */ +#define HAL_get_8bit_reg_field(BASE_ADDR, FIELD_NAME) \ + (HW_get_8bit_reg_field(\ + (BASE_ADDR) + FIELD_OFFSET(FIELD_NAME),\ + FIELD_SHIFT(FIELD_NAME),\ + FIELD_MASK(FIELD_NAME))) + +#endif /*HAL_H_*/ + diff --git a/FreeRTOS/Demo/RISC-V_IGLOO2_Creative_SoftConsole/hal/hal_assert.h b/FreeRTOS/Demo/RISC-V_IGLOO2_Creative_SoftConsole/hal/hal_assert.h new file mode 100644 index 000000000..db8ab7703 --- /dev/null +++ b/FreeRTOS/Demo/RISC-V_IGLOO2_Creative_SoftConsole/hal/hal_assert.h @@ -0,0 +1,29 @@ +/******************************************************************************* + * (c) Copyright 2008-2018 Microsemi SoC Products Group. All rights reserved. + * + * SVN $Revision: 9661 $ + * SVN $Date: 2018-01-15 16:13:33 +0530 (Mon, 15 Jan 2018) $ + */ +#ifndef HAL_ASSERT_HEADER +#define HAL_ASSERT_HEADER + +#define NDEBUG 1 + +#if defined(NDEBUG) +/***************************************************************************//** + * HAL_ASSERT() is defined out when the NDEBUG symbol is used. + ******************************************************************************/ +#define HAL_ASSERT(CHECK) + +#else +/***************************************************************************//** + * Default behaviour for HAL_ASSERT() macro: + *------------------------------------------------------------------------------ + The behaviour is toolchain specific and project setting specific. + ******************************************************************************/ +#define HAL_ASSERT(CHECK) ASSERT(CHECK); + +#endif /* NDEBUG */ + +#endif /* HAL_ASSERT_HEADER */ + diff --git a/FreeRTOS/Demo/RISC-V_IGLOO2_Creative_SoftConsole/hal/hal_irq.c b/FreeRTOS/Demo/RISC-V_IGLOO2_Creative_SoftConsole/hal/hal_irq.c new file mode 100644 index 000000000..52f63016e --- /dev/null +++ b/FreeRTOS/Demo/RISC-V_IGLOO2_Creative_SoftConsole/hal/hal_irq.c @@ -0,0 +1,36 @@ +/***************************************************************************//** + * (c) Copyright 2007-2018 Microsemi SoC Products Group. All rights reserved. + * + * Legacy interrupt control functions for the Microsemi driver library hardware + * abstraction layer. + * + * SVN $Revision: 9661 $ + * SVN $Date: 2018-01-15 16:13:33 +0530 (Mon, 15 Jan 2018) $ + */ +#include "hal.h" +#include "riscv_hal.h" + +/*------------------------------------------------------------------------------ + * + */ +void HAL_enable_interrupts(void) { + __enable_irq(); +} + +/*------------------------------------------------------------------------------ + * + */ +psr_t HAL_disable_interrupts(void) { + psr_t psr; + psr = read_csr(mstatus); + __disable_irq(); + return(psr); +} + +/*------------------------------------------------------------------------------ + * + */ +void HAL_restore_interrupts(psr_t saved_psr) { + write_csr(mstatus, saved_psr); +} + diff --git a/FreeRTOS/Demo/RISC-V_IGLOO2_Creative_SoftConsole/hal/hw_macros.h b/FreeRTOS/Demo/RISC-V_IGLOO2_Creative_SoftConsole/hal/hw_macros.h new file mode 100644 index 000000000..2149544ca --- /dev/null +++ b/FreeRTOS/Demo/RISC-V_IGLOO2_Creative_SoftConsole/hal/hw_macros.h @@ -0,0 +1,97 @@ +/******************************************************************************* + * (c) Copyright 2007-2018 Microsemi SoC Products Group. All rights reserved. + * + * Hardware registers access macros. + * + * THE MACROS DEFINED IN THIS FILE ARE DEPRECATED. DO NOT USED FOR NEW + * DEVELOPMENT. + * + * These macros are used to access peripheral's registers. They allow access to + * 8, 16 and 32 bit wide registers. All accesses to peripheral registers should + * be done through these macros in order to ease porting across different + * processors/bus architectures. + * + * Some of these macros also allow to access a specific register field. + * + * SVN $Revision: 9661 $ + * SVN $Date: 2018-01-15 16:13:33 +0530 (Mon, 15 Jan 2018) $ + */ +#ifndef __HW_REGISTER_MACROS_H +#define __HW_REGISTER_MACROS_H 1 + +/*------------------------------------------------------------------------------ + * 32 bits registers access: + */ +#define HW_get_uint32_reg(BASE_ADDR, REG_OFFSET) (*((uint32_t volatile *)(BASE_ADDR + REG_OFFSET##_REG_OFFSET))) + +#define HW_set_uint32_reg(BASE_ADDR, REG_OFFSET, VALUE) (*((uint32_t volatile *)(BASE_ADDR + REG_OFFSET##_REG_OFFSET)) = (VALUE)) + +#define HW_set_uint32_reg_field(BASE_ADDR, FIELD, VALUE) \ + (*((uint32_t volatile *)(BASE_ADDR + FIELD##_OFFSET)) = \ + ( \ + (uint32_t) \ + ( \ + (*((uint32_t volatile *)(BASE_ADDR + FIELD##_OFFSET))) & ~FIELD##_MASK) | \ + (uint32_t)(((VALUE) << FIELD##_SHIFT) & FIELD##_MASK) \ + ) \ + ) + +#define HW_get_uint32_reg_field( BASE_ADDR, FIELD ) \ + (( (*((uint32_t volatile *)(BASE_ADDR + FIELD##_OFFSET))) & FIELD##_MASK) >> FIELD##_SHIFT) + +/*------------------------------------------------------------------------------ + * 32 bits memory access: + */ +#define HW_get_uint32(BASE_ADDR) (*((uint32_t volatile *)(BASE_ADDR))) + +#define HW_set_uint32(BASE_ADDR, VALUE) (*((uint32_t volatile *)(BASE_ADDR)) = (VALUE)) + +/*------------------------------------------------------------------------------ + * 16 bits registers access: + */ +#define HW_get_uint16_reg(BASE_ADDR, REG_OFFSET) (*((uint16_t volatile *)(BASE_ADDR + REG_OFFSET##_REG_OFFSET))) + +#define HW_set_uint16_reg(BASE_ADDR, REG_OFFSET, VALUE) (*((uint16_t volatile *)(BASE_ADDR + REG_OFFSET##_REG_OFFSET)) = (VALUE)) + +#define HW_set_uint16_reg_field(BASE_ADDR, FIELD, VALUE) \ + (*((uint16_t volatile *)(BASE_ADDR + FIELD##_OFFSET)) = \ + ( \ + (uint16_t) \ + ( \ + (*((uint16_t volatile *)(BASE_ADDR + FIELD##_OFFSET))) & ~FIELD##_MASK) | \ + (uint16_t)(((VALUE) << FIELD##_SHIFT) & FIELD##_MASK) \ + ) \ + ) + +#define HW_get_uint16_reg_field( BASE_ADDR, FIELD ) \ + (( (*((uint16_t volatile *)(BASE_ADDR + FIELD##_OFFSET))) & FIELD##_MASK) >> FIELD##_SHIFT) + +/*------------------------------------------------------------------------------ + * 8 bits registers access: + */ +#define HW_get_uint8_reg(BASE_ADDR, REG_OFFSET) (*((uint8_t volatile *)(BASE_ADDR + REG_OFFSET##_REG_OFFSET))) + +#define HW_set_uint8_reg(BASE_ADDR, REG_OFFSET, VALUE) (*((uint8_t volatile *)(BASE_ADDR + REG_OFFSET##_REG_OFFSET)) = (VALUE)) + +#define HW_set_uint8_reg_field(BASE_ADDR, FIELD, VALUE) \ + (*((uint8_t volatile *)(BASE_ADDR + FIELD##_OFFSET)) = \ + ( \ + (uint8_t) \ + ( \ + (*((uint8_t volatile *)(BASE_ADDR + FIELD##_OFFSET))) & ~FIELD##_MASK) | \ + (uint8_t)(((VALUE) << FIELD##_SHIFT) & FIELD##_MASK) \ + ) \ + ) + +#define HW_get_uint8_reg_field( BASE_ADDR, FIELD ) \ + (( (*((uint8_t volatile *)(BASE_ADDR + FIELD##_OFFSET))) & FIELD##_MASK) >> FIELD##_SHIFT) + +/*------------------------------------------------------------------------------ + * 8 bits memory access: + */ +#define HW_get_uint8(BASE_ADDR) (*((uint8_t volatile *)(BASE_ADDR))) + +#define HW_set_uint8(BASE_ADDR, VALUE) (*((uint8_t volatile *)(BASE_ADDR)) = (VALUE)) + +#endif /* __HW_REGISTER_MACROS_H */ + diff --git a/FreeRTOS/Demo/RISC-V_IGLOO2_Creative_SoftConsole/hal/hw_reg_access.S b/FreeRTOS/Demo/RISC-V_IGLOO2_Creative_SoftConsole/hal/hw_reg_access.S new file mode 100644 index 000000000..68d93dd4c --- /dev/null +++ b/FreeRTOS/Demo/RISC-V_IGLOO2_Creative_SoftConsole/hal/hw_reg_access.S @@ -0,0 +1,209 @@ +/***************************************************************************//** + * (c) Copyright 2007-2018 Microsemi SoC Products Group. All rights reserved. + * + * Hardware registers access functions. + * The implementation of these function is platform and toolchain specific. + * The functions declared here are implemented using assembler as part of the + * processor/toolchain specific HAL. + * + * SVN $Revision: 9661 $ + * SVN $Date: 2018-01-15 16:13:33 +0530 (Mon, 15 Jan 2018) $ + */ + +.section .text + .globl HW_set_32bit_reg + .globl HW_get_32bit_reg + .globl HW_set_32bit_reg_field + .globl HW_get_32bit_reg_field + .globl HW_set_16bit_reg + .globl HW_get_16bit_reg + .globl HW_set_16bit_reg_field + .globl HW_get_16bit_reg_field + .globl HW_set_8bit_reg + .globl HW_get_8bit_reg + .globl HW_set_8bit_reg_field + .globl HW_get_8bit_reg_field + + +/***************************************************************************//** + * HW_set_32bit_reg is used to write the content of a 32 bits wide peripheral + * register. + * + * a0: addr_t reg_addr + * a1: uint32_t value + */ +HW_set_32bit_reg: + sw a1, 0(a0) + ret + +/***************************************************************************//** + * HW_get_32bit_reg is used to read the content of a 32 bits wide peripheral + * register. + * + * R0: addr_t reg_addr + * @return 32 bits value read from the peripheral register. + */ +HW_get_32bit_reg: + lw a0, 0(a0) + ret + +/***************************************************************************//** + * HW_set_32bit_reg_field is used to set the content of a field in a 32 bits + * wide peripheral register. + * + * a0: addr_t reg_addr + * a1: int_fast8_t shift + * a2: uint32_t mask + * a3: uint32_t value + */ +HW_set_32bit_reg_field: + mv t3, a3 + sll t3, t3, a1 + and t3, t3, a2 + lw t1, 0(a0) + mv t2, a2 + not t2, t2 + and t1, t1, t2 + or t1, t1, t3 + sw t1, 0(a0) + ret + +/***************************************************************************//** + * HW_get_32bit_reg_field is used to read the content of a field out of a + * 32 bits wide peripheral register. + * + * a0: addr_t reg_addr + * a1: int_fast8_t shift + * a2: uint32_t mask + * + * @return 32 bits value containing the register field value specified + * as parameter. + */ +HW_get_32bit_reg_field: + lw a0, 0(a0) + and a0, a0, a2 + srl a0, a0, a1 + ret + +/***************************************************************************//** + * HW_set_16bit_reg is used to write the content of a 16 bits wide peripheral + * register. + * + * a0: addr_t reg_addr + * a1: uint_fast16_t value + */ +HW_set_16bit_reg: + sh a1, 0(a0) + ret + +/***************************************************************************//** + * HW_get_16bit_reg is used to read the content of a 16 bits wide peripheral + * register. + * + * a0: addr_t reg_addr + * @return 16 bits value read from the peripheral register. + */ +HW_get_16bit_reg: + lh a0, (a0) + ret + +/***************************************************************************//** + * HW_set_16bit_reg_field is used to set the content of a field in a 16 bits + * wide peripheral register. + * + * a0: addr_t reg_addr + * a1: int_fast8_t shift + * a2: uint_fast16_t mask + * a3: uint_fast16_t value + * @param value Value to be written in the specified field. + */ +HW_set_16bit_reg_field: + mv t3, a3 + sll t3, t3, a1 + and t3, t3, a2 + lh t1, 0(a0) + mv t2, a2 + not t2, t2 + and t1, t1, t2 + or t1, t1, t3 + sh t1, 0(a0) + ret + +/***************************************************************************//** + * HW_get_16bit_reg_field is used to read the content of a field from a + * 16 bits wide peripheral register. + * + * a0: addr_t reg_addr + * a1: int_fast8_t shift + * a2: uint_fast16_t mask + * + * @return 16 bits value containing the register field value specified + * as parameter. + */ +HW_get_16bit_reg_field: + lh a0, 0(a0) + and a0, a0, a2 + srl a0, a0, a1 + ret + +/***************************************************************************//** + * HW_set_8bit_reg is used to write the content of a 8 bits wide peripheral + * register. + * + * a0: addr_t reg_addr + * a1: uint_fast8_t value + */ +HW_set_8bit_reg: + sb a1, 0(a0) + ret + +/***************************************************************************//** + * HW_get_8bit_reg is used to read the content of a 8 bits wide peripheral + * register. + * + * a0: addr_t reg_addr + * @return 8 bits value read from the peripheral register. + */ +HW_get_8bit_reg: + lb a0, 0(a0) + ret + +/***************************************************************************//** + * HW_set_8bit_reg_field is used to set the content of a field in a 8 bits + * wide peripheral register. + * + * a0: addr_t reg_addr, + * a1: int_fast8_t shift + * a2: uint_fast8_t mask + * a3: uint_fast8_t value + */ +HW_set_8bit_reg_field: + mv t3, a3 + sll t3, t3, a1 + and t3, t3, a2 + lb t1, 0(a0) + mv t2, a2 + not t2, t2 + and t1, t1, t2 + or t1, t1, t3 + sb t1, 0(a0) + ret + +/***************************************************************************//** + * HW_get_8bit_reg_field is used to read the content of a field from a + * 8 bits wide peripheral register. + * + * a0: addr_t reg_addr + * a1: int_fast8_t shift + * a2: uint_fast8_t mask + * + * @return 8 bits value containing the register field value specified + * as parameter. + */ +HW_get_8bit_reg_field: + lb a0, 0(a0) + and a0, a0, a2 + srl a0, a0, a1 + ret + +.end diff --git a/FreeRTOS/Demo/RISC-V_IGLOO2_Creative_SoftConsole/hal/hw_reg_access.h b/FreeRTOS/Demo/RISC-V_IGLOO2_Creative_SoftConsole/hal/hw_reg_access.h new file mode 100644 index 000000000..bc3dd654a --- /dev/null +++ b/FreeRTOS/Demo/RISC-V_IGLOO2_Creative_SoftConsole/hal/hw_reg_access.h @@ -0,0 +1,229 @@ +/***************************************************************************//** + * (c) Copyright 2007-2018 Microsemi SoC Products Group. All rights reserved. + * + * Hardware registers access functions. + * The implementation of these function is platform and toolchain specific. + * The functions declared here are implemented using assembler as part of the + * processor/toolchain specific HAL. + * + * SVN $Revision: 9661 $ + * SVN $Date: 2018-01-15 16:13:33 +0530 (Mon, 15 Jan 2018) $ + */ +#ifndef HW_REG_ACCESS +#define HW_REG_ACCESS + +#include "cpu_types.h" +/***************************************************************************//** + * HW_set_32bit_reg is used to write the content of a 32 bits wide peripheral + * register. + * + * @param reg_addr Address in the processor's memory map of the register to + * write. + * @param value Value to be written into the peripheral register. + */ +void +HW_set_32bit_reg +( + addr_t reg_addr, + uint32_t value +); + +/***************************************************************************//** + * HW_get_32bit_reg is used to read the content of a 32 bits wide peripheral + * register. + * + * @param reg_addr Address in the processor's memory map of the register to + * read. + * @return 32 bits value read from the peripheral register. + */ +uint32_t +HW_get_32bit_reg +( + addr_t reg_addr +); + +/***************************************************************************//** + * HW_set_32bit_reg_field is used to set the content of a field in a 32 bits + * wide peripheral register. + * + * @param reg_addr Address in the processor's memory map of the register to + * be written. + * @param shift Bit offset of the register field to be read within the + * register. + * @param mask Bit mask to be applied to the raw register value to filter + * out the other register fields values. + * @param value Value to be written in the specified field. + */ +void +HW_set_32bit_reg_field +( + addr_t reg_addr, + int_fast8_t shift, + uint32_t mask, + uint32_t value +); + +/***************************************************************************//** + * HW_get_32bit_reg_field is used to read the content of a field out of a + * 32 bits wide peripheral register. + * + * @param reg_addr Address in the processor's memory map of the register to + * read. + * @param shift Bit offset of the register field to be written within the + * register. + * @param mask Bit mask to be applied to the raw register value to filter + * out the other register fields values. + * + * @return 32 bits value containing the register field value specified + * as parameter. + */ +uint32_t +HW_get_32bit_reg_field +( + addr_t reg_addr, + int_fast8_t shift, + uint32_t mask +); + +/***************************************************************************//** + * HW_set_16bit_reg is used to write the content of a 16 bits wide peripheral + * register. + * + * @param reg_addr Address in the processor's memory map of the register to + * write. + * @param value Value to be written into the peripheral register. + */ +void +HW_set_16bit_reg +( + addr_t reg_addr, + uint_fast16_t value +); + +/***************************************************************************//** + * HW_get_16bit_reg is used to read the content of a 16 bits wide peripheral + * register. + * + * @param reg_addr Address in the processor's memory map of the register to + * read. + * @return 16 bits value read from the peripheral register. + */ +uint16_t +HW_get_16bit_reg +( + addr_t reg_addr +); + +/***************************************************************************//** + * HW_set_16bit_reg_field is used to set the content of a field in a 16 bits + * wide peripheral register. + * + * @param reg_addr Address in the processor's memory map of the register to + * be written. + * @param shift Bit offset of the register field to be read within the + * register. + * @param mask Bit mask to be applied to the raw register value to filter + * out the other register fields values. + * @param value Value to be written in the specified field. + */ +void HW_set_16bit_reg_field +( + addr_t reg_addr, + int_fast8_t shift, + uint_fast16_t mask, + uint_fast16_t value +); + +/***************************************************************************//** + * HW_get_16bit_reg_field is used to read the content of a field from a + * 16 bits wide peripheral register. + * + * @param reg_addr Address in the processor's memory map of the register to + * read. + * @param shift Bit offset of the register field to be written within the + * register. + * @param mask Bit mask to be applied to the raw register value to filter + * out the other register fields values. + * + * @return 16 bits value containing the register field value specified + * as parameter. + */ +uint16_t HW_get_16bit_reg_field +( + addr_t reg_addr, + int_fast8_t shift, + uint_fast16_t mask +); + +/***************************************************************************//** + * HW_set_8bit_reg is used to write the content of a 8 bits wide peripheral + * register. + * + * @param reg_addr Address in the processor's memory map of the register to + * write. + * @param value Value to be written into the peripheral register. + */ +void +HW_set_8bit_reg +( + addr_t reg_addr, + uint_fast8_t value +); + +/***************************************************************************//** + * HW_get_8bit_reg is used to read the content of a 8 bits wide peripheral + * register. + * + * @param reg_addr Address in the processor's memory map of the register to + * read. + * @return 8 bits value read from the peripheral register. + */ +uint8_t +HW_get_8bit_reg +( + addr_t reg_addr +); + +/***************************************************************************//** + * HW_set_8bit_reg_field is used to set the content of a field in a 8 bits + * wide peripheral register. + * + * @param reg_addr Address in the processor's memory map of the register to + * be written. + * @param shift Bit offset of the register field to be read within the + * register. + * @param mask Bit mask to be applied to the raw register value to filter + * out the other register fields values. + * @param value Value to be written in the specified field. + */ +void HW_set_8bit_reg_field +( + addr_t reg_addr, + int_fast8_t shift, + uint_fast8_t mask, + uint_fast8_t value +); + +/***************************************************************************//** + * HW_get_8bit_reg_field is used to read the content of a field from a + * 8 bits wide peripheral register. + * + * @param reg_addr Address in the processor's memory map of the register to + * read. + * @param shift Bit offset of the register field to be written within the + * register. + * @param mask Bit mask to be applied to the raw register value to filter + * out the other register fields values. + * + * @return 8 bits value containing the register field value specified + * as parameter. + */ +uint8_t HW_get_8bit_reg_field +( + addr_t reg_addr, + int_fast8_t shift, + uint_fast8_t mask +); + +#endif /* HW_REG_ACCESS */ + diff --git a/FreeRTOS/Demo/RISC-V_IGLOO2_Creative_SoftConsole/hw_platform.h b/FreeRTOS/Demo/RISC-V_IGLOO2_Creative_SoftConsole/hw_platform.h new file mode 100644 index 000000000..268eba61f --- /dev/null +++ b/FreeRTOS/Demo/RISC-V_IGLOO2_Creative_SoftConsole/hw_platform.h @@ -0,0 +1,119 @@ +/******************************************************************************* + * (c) Copyright 2016-2017 Microsemi Corporation. All rights reserved. + * + * Platform definitions + * Version based on requirements of RISCV-HAL + * + * SVN $Revision: 9587 $ + * SVN $Date: 2017-11-16 12:53:31 +0530 (Thu, 16 Nov 2017) $ + */ + /*=========================================================================*//** + @mainpage Sample file detailing how hw_platform.h should be constructed for + the Mi-V processors. + + @section intro_sec Introduction + The hw_platform.h is to be located in the project root directory. + Currently this file must be hand crafted when using the Mi-V Soft Processor. + + You can use this file as sample. + Rename this file from sample_hw_platform.h to hw_platform.h and store it in + the root folder of your project. Then customize it per your HW design. + + @section driver_configuration Project configuration Instructions + 1. Change SYS_CLK_FREQ define to frequency of Mi-V Soft processor clock + 2 Add all other core BASE addresses + 3. Add peripheral Core Interrupt to Mi-V Soft processor interrupt mappings + 4. Define MSCC_STDIO_UART_BASE_ADDR if you want a CoreUARTapb mapped to STDIO +*//*=========================================================================*/ + +#ifndef HW_PLATFORM_H +#define HW_PLATFORM_H + +/***************************************************************************//** + * Soft-processor clock definition + * This is the only clock brought over from the Mi-V Soft processor Libero design. + */ +#ifndef SYS_CLK_FREQ +#define SYS_CLK_FREQ 83000000UL +#endif + +/***************************************************************************//** + * Non-memory Peripheral base addresses + * Format of define is: + * __BASE_ADDR + */ +#define COREUARTAPB0_BASE_ADDR 0x70001000UL +#define COREGPIO_IN_BASE_ADDR 0x70002000UL +#define CORETIMER0_BASE_ADDR 0x70003000UL +#define CORETIMER1_BASE_ADDR 0x70004000UL +#define COREGPIO_OUT_BASE_ADDR 0x70005000UL +#define FLASH_CORE_SPI_BASE 0x70006000UL +#define CORE16550_BASE_ADDR 0x70007000UL + +/***************************************************************************//** + * Peripheral Interrupts are mapped to the corresponding Mi-V Soft processor + * interrupt from the Libero design. + * There can be up to 31 external interrupts (IRQ[30:0] pins) on the Mi-V Soft + * processor.The Mi-V Soft processor external interrupts are defined in the + * riscv_plic.h + * These are of the form + * typedef enum +{ + NoInterrupt_IRQn = 0, + External_1_IRQn = 1, + External_2_IRQn = 2, + . + . + . + External_31_IRQn = 31 +} IRQn_Type; + + The interrupt 0 on RISC-V processor is not used. The pin IRQ[0] should map to + External_1_IRQn likewise IRQ[30] should map to External_31_IRQn + * Format of define is: + * __ + */ + +#define TIMER0_IRQn External_30_IRQn +#define TIMER1_IRQn External_31_IRQn + +/**************************************************************************** + * Baud value to achieve a 115200 baud rate with a 83MHz system clock. + * This value is calculated using the following equation: + * BAUD_VALUE = (CLOCK / (16 * BAUD_RATE)) - 1 + *****************************************************************************/ +#define BAUD_VALUE_115200 (SYS_CLK_FREQ / (16 * 115200)) - 1 + +/***************************************************************************//** + * User edit section- Edit sections below if required + */ +#ifdef MSCC_STDIO_THRU_CORE_UART_APB +/* + * A base address mapping for the STDIO printf/scanf mapping to CortUARTapb + * must be provided if it is being used + * + * e.g. #define MSCC_STDIO_UART_BASE_ADDR COREUARTAPB1_BASE_ADDR + */ +#define MSCC_STDIO_UART_BASE_ADDR COREUARTAPB0_BASE_ADDR + +#ifndef MSCC_STDIO_UART_BASE_ADDR +#error MSCC_STDIO_UART_BASE_ADDR not defined- e.g. #define MSCC_STDIO_UART_BASE_ADDR COREUARTAPB1_BASE_ADDR +#endif + +#ifndef MSCC_STDIO_BAUD_VALUE +/* + * The MSCC_STDIO_BAUD_VALUE define should be set in your project's settings to + * specify the baud value used by the standard output CoreUARTapb instance for + * generating the UART's baud rate if you want a different baud rate from the + * default of 115200 baud + */ +#define MSCC_STDIO_BAUD_VALUE 115200 +#endif /*MSCC_STDIO_BAUD_VALUE*/ + +#endif /* end of MSCC_STDIO_THRU_CORE_UART_APB */ +/******************************************************************************* + * End of user edit section + */ +#endif /* HW_PLATFORM_H */ + + diff --git a/FreeRTOS/Demo/RISC-V_IGLOO2_Creative_SoftConsole/main.c b/FreeRTOS/Demo/RISC-V_IGLOO2_Creative_SoftConsole/main.c new file mode 100644 index 000000000..4ec3a71ad --- /dev/null +++ b/FreeRTOS/Demo/RISC-V_IGLOO2_Creative_SoftConsole/main.c @@ -0,0 +1,136 @@ +#include "FreeRTOS.h" +#include "task.h" +#include "queue.h" +#include "timers.h" + +#include "hw_platform.h" +#include "core_uart_apb.h" +#include "task.h" + +const char * g_hello_msg = "\r\nFreeRTOS Example\r\n"; + + +/* A block time of zero simply means "don't block". */ +#define mainDONT_BLOCK ( 0UL ) + +/****************************************************************************** + * CoreUARTapb instance data. + *****************************************************************************/ +UART_instance_t g_uart; +/*-----------------------------------------------------------*/ + +static void vUartTestTask1( void *pvParameters ); +static void vUartTestTask2( void *pvParameters ); + +/* + * FreeRTOS hook for when malloc fails, enable in FreeRTOSConfig. + */ +void vApplicationMallocFailedHook( void ); + +/* + * FreeRTOS hook for when FreeRtos is idling, enable in FreeRTOSConfig. + */ +void vApplicationIdleHook( void ); + +/* + * FreeRTOS hook for when a stack overflow occurs, enable in FreeRTOSConfig. + */ +void vApplicationStackOverflowHook( TaskHandle_t pxTask, char *pcTaskName ); + +/*-----------------------------------------------------------*/ + +int main( void ) +{ + PLIC_init(); + + /************************************************************************** + * Initialize CoreUART with its base address, baud value, and line + * configuration. + *************************************************************************/ + UART_init(&g_uart, COREUARTAPB0_BASE_ADDR, BAUD_VALUE_115200, + (DATA_8_BITS | NO_PARITY) ); + + UART_polled_tx_string( &g_uart, (const uint8_t *)"\r\n\r\n Sample Demonstration of FreeRTOS port for Mi-V processor.\r\n\r\n" ); + UART_polled_tx_string( &g_uart, (const uint8_t *)" This project creates two tasks and runs them at regular intervals.\r\n" ); + + /* Create the two test tasks. */ + xTaskCreate( vUartTestTask1, "UArt1", 1000, NULL, uartPRIMARY_PRIORITY, NULL ); + xTaskCreate( vUartTestTask2, "UArt2", 1000, NULL, uartPRIMARY_PRIORITY, NULL ); + + /* Start the kernel. From here on, only tasks and interrupts will run. */ + vTaskStartScheduler(); + + /* Exit FreeRTOS */ + return 0; +} + +/*-----------------------------------------------------------*/ + +void vApplicationMallocFailedHook( void ) +{ + /* vApplicationMallocFailedHook() will only be called if + configUSE_MALLOC_FAILED_HOOK is set to 1 in FreeRTOSConfig.h. It is a hook + function that will get called if a call to pvPortMalloc() fails. + pvPortMalloc() is called internally by the kernel whenever a task, queue, + timer or semaphore is created. It is also called by various parts of the + demo application. If heap_1.c or heap_2.c are used, then the size of the + heap available to pvPortMalloc() is defined by configTOTAL_HEAP_SIZE in + FreeRTOSConfig.h, and the xPortGetFreeHeapSize() API function can be used + to query the size of free heap space that remains (although it does not + provide information on how the remaining heap might be fragmented). */ + taskDISABLE_INTERRUPTS(); + for( ;; ); +} +/*-----------------------------------------------------------*/ + +void vApplicationIdleHook( void ) +{ + /* vApplicationIdleHook() will only be called if configUSE_IDLE_HOOK is set + to 1 in FreeRTOSConfig.h. It will be called on each iteration of the idle + task. It is essential that code added to this hook function never attempts + to block in any way (for example, call xQueueReceive() with a block time + specified, or call vTaskDelay()). If the application makes use of the + vTaskDelete() API function (as this demo application does) then it is also + important that vApplicationIdleHook() is permitted to return to its calling + function, because it is the responsibility of the idle task to clean up + memory allocated by the kernel to any task that has since been deleted. */ +} +/*-----------------------------------------------------------*/ + +void vApplicationStackOverflowHook( TaskHandle_t pxTask, char *pcTaskName ) +{ + ( void ) pcTaskName; + ( void ) pxTask; + + /* Run time stack overflow checking is performed if + configCHECK_FOR_STACK_OVERFLOW is defined to 1 or 2. This hook + function is called if a stack overflow is detected. */ + taskDISABLE_INTERRUPTS(); + for( ;; ); +} +/*-----------------------------------------------------------*/ + +static void vUartTestTask1( void *pvParameters ) +{ + ( void ) pvParameters; + + for( ;; ) + { + UART_polled_tx_string( &g_uart, (const uint8_t *)"Task - 1\r\n" ); + vTaskDelay(10); + } +} + + +/*-----------------------------------------------------------*/ + +static void vUartTestTask2( void *pvParameters ) +{ + ( void ) pvParameters; + + for( ;; ) + { + UART_polled_tx_string( &g_uart, (const uint8_t *)"Task - 2\r\n" ); + vTaskDelay(5); + } +} diff --git a/FreeRTOS/Demo/RISC-V_IGLOO2_Creative_SoftConsole/riscv_hal/encoding.h b/FreeRTOS/Demo/RISC-V_IGLOO2_Creative_SoftConsole/riscv_hal/encoding.h new file mode 100644 index 000000000..aa379ee5a --- /dev/null +++ b/FreeRTOS/Demo/RISC-V_IGLOO2_Creative_SoftConsole/riscv_hal/encoding.h @@ -0,0 +1,596 @@ +/******************************************************************************* + * (c) Copyright 2016-2018 Microsemi SoC Products Group. All rights reserved. + * + * @file encodings.h + * @author Microsemi SoC Products Group + * @brief Mi-V soft processor register bit mask and shift constants encodings. + * + * SVN $Revision: 9825 $ + * SVN $Date: 2018-03-19 10:31:41 +0530 (Mon, 19 Mar 2018) $ + */ +#ifndef RISCV_CSR_ENCODING_H +#define RISCV_CSR_ENCODING_H + +#ifdef __cplusplus +extern "C" { +#endif + +#define MSTATUS_UIE 0x00000001 +#define MSTATUS_SIE 0x00000002 +#define MSTATUS_HIE 0x00000004 +#define MSTATUS_MIE 0x00000008 +#define MSTATUS_UPIE 0x00000010 +#define MSTATUS_SPIE 0x00000020 +#define MSTATUS_HPIE 0x00000040 +#define MSTATUS_MPIE 0x00000080 +#define MSTATUS_SPP 0x00000100 +#define MSTATUS_HPP 0x00000600 +#define MSTATUS_MPP 0x00001800 +#define MSTATUS_FS 0x00006000 +#define MSTATUS_XS 0x00018000 +#define MSTATUS_MPRV 0x00020000 +#define MSTATUS_SUM 0x00040000 /*changed in v1.10*/ +#define MSTATUS_MXR 0x00080000 /*changed in v1.10*/ +#define MSTATUS_TVM 0x00100000 /*changed in v1.10*/ +#define MSTATUS_TW 0x00200000 /*changed in v1.10*/ +#define MSTATUS_TSR 0x00400000 /*changed in v1.10*/ +#define MSTATUS_RES 0x7F800000 /*changed in v1.10*/ +#define MSTATUS32_SD 0x80000000 +#define MSTATUS64_SD 0x8000000000000000 + +#define MCAUSE32_CAUSE 0x7FFFFFFF +#define MCAUSE64_CAUSE 0x7FFFFFFFFFFFFFFF +#define MCAUSE32_INT 0x80000000 +#define MCAUSE64_INT 0x8000000000000000 + +#define SSTATUS_UIE 0x00000001 +#define SSTATUS_SIE 0x00000002 +#define SSTATUS_UPIE 0x00000010 +#define SSTATUS_SPIE 0x00000020 +#define SSTATUS_SPP 0x00000100 +#define SSTATUS_FS 0x00006000 +#define SSTATUS_XS 0x00018000 +#define SSTATUS_PUM 0x00040000 +#define SSTATUS32_SD 0x80000000 +#define SSTATUS64_SD 0x8000000000000000 + +#define MIP_SSIP (1u << IRQ_S_SOFT) +#define MIP_HSIP (1u << IRQ_H_SOFT) +#define MIP_MSIP (1u << IRQ_M_SOFT) +#define MIP_STIP (1u << IRQ_S_TIMER) +#define MIP_HTIP (1u << IRQ_H_TIMER) +#define MIP_MTIP (1u << IRQ_M_TIMER) +#define MIP_SEIP (1u << IRQ_S_EXT) +#define MIP_HEIP (1u << IRQ_H_EXT) +#define MIP_MEIP (1u << IRQ_M_EXT) + +#define SIP_SSIP MIP_SSIP +#define SIP_STIP MIP_STIP + +#define PRV_U 0 +#define PRV_S 1 +#define PRV_H 2 +#define PRV_M 3 + +#define VM_MBARE 0 +#define VM_MBB 1 +#define VM_MBBID 2 +#define VM_SV32 8 +#define VM_SV39 9 +#define VM_SV48 10 + +#define IRQ_S_SOFT 1 +#define IRQ_H_SOFT 2 +#define IRQ_M_SOFT 3 +#define IRQ_S_TIMER 5 +#define IRQ_H_TIMER 6 +#define IRQ_M_TIMER 7 +#define IRQ_S_EXT 9 +#define IRQ_H_EXT 10 +#define IRQ_M_EXT 11 + +#define DEFAULT_RSTVEC 0x00001000 +#define DEFAULT_NMIVEC 0x00001004 +#define DEFAULT_MTVEC 0x00001010 +#define CONFIG_STRING_ADDR 0x0000100C +#define EXT_IO_BASE 0x40000000 +#define DRAM_BASE 0x80000000 + +/* page table entry (PTE) fields */ +#define PTE_V 0x001 /* Valid */ +#define PTE_TYPE 0x01E /* Type */ +#define PTE_R 0x020 /* Referenced */ +#define PTE_D 0x040 /* Dirty */ +#define PTE_SOFT 0x380 /* Reserved for Software */ + +#define PTE_TYPE_TABLE 0x00 +#define PTE_TYPE_TABLE_GLOBAL 0x02 +#define PTE_TYPE_URX_SR 0x04 +#define PTE_TYPE_URWX_SRW 0x06 +#define PTE_TYPE_UR_SR 0x08 +#define PTE_TYPE_URW_SRW 0x0A +#define PTE_TYPE_URX_SRX 0x0C +#define PTE_TYPE_URWX_SRWX 0x0E +#define PTE_TYPE_SR 0x10 +#define PTE_TYPE_SRW 0x12 +#define PTE_TYPE_SRX 0x14 +#define PTE_TYPE_SRWX 0x16 +#define PTE_TYPE_SR_GLOBAL 0x18 +#define PTE_TYPE_SRW_GLOBAL 0x1A +#define PTE_TYPE_SRX_GLOBAL 0x1C +#define PTE_TYPE_SRWX_GLOBAL 0x1E + +#define PTE_PPN_SHIFT 10 + +#define PTE_TABLE(PTE) ((0x0000000AU >> ((PTE) & 0x1F)) & 1) +#define PTE_UR(PTE) ((0x0000AAA0U >> ((PTE) & 0x1F)) & 1) +#define PTE_UW(PTE) ((0x00008880U >> ((PTE) & 0x1F)) & 1) +#define PTE_UX(PTE) ((0x0000A0A0U >> ((PTE) & 0x1F)) & 1) +#define PTE_SR(PTE) ((0xAAAAAAA0U >> ((PTE) & 0x1F)) & 1) +#define PTE_SW(PTE) ((0x88888880U >> ((PTE) & 0x1F)) & 1) +#define PTE_SX(PTE) ((0xA0A0A000U >> ((PTE) & 0x1F)) & 1) + +#define PTE_CHECK_PERM(PTE, SUPERVISOR, STORE, FETCH) \ + ((STORE) ? ((SUPERVISOR) ? PTE_SW(PTE) : PTE_UW(PTE)) : \ + (FETCH) ? ((SUPERVISOR) ? PTE_SX(PTE) : PTE_UX(PTE)) : \ + ((SUPERVISOR) ? PTE_SR(PTE) : PTE_UR(PTE))) + +#ifdef __riscv + +#if __riscv_xlen == 64 +# define MSTATUS_SD MSTATUS64_SD +# define SSTATUS_SD SSTATUS64_SD +# define MCAUSE_INT MCAUSE64_INT +# define MCAUSE_CAUSE MCAUSE64_CAUSE +# define RISCV_PGLEVEL_BITS 9 +#else +# define MSTATUS_SD MSTATUS32_SD +# define SSTATUS_SD SSTATUS32_SD +# define RISCV_PGLEVEL_BITS 10 +# define MCAUSE_INT MCAUSE32_INT +# define MCAUSE_CAUSE MCAUSE32_CAUSE +#endif + +#define RISCV_PGSHIFT 12 +#define RISCV_PGSIZE (1 << RISCV_PGSHIFT) + +#ifndef __ASSEMBLER__ + +#ifdef __GNUC__ + +#define read_csr(reg) ({ unsigned long __tmp; \ + asm volatile ("csrr %0, " #reg : "=r"(__tmp)); \ + __tmp; }) + +#define write_csr(reg, val) ({ \ + if (__builtin_constant_p(val) && (unsigned long)(val) < 32) \ + asm volatile ("csrw " #reg ", %0" :: "i"(val)); \ + else \ + asm volatile ("csrw " #reg ", %0" :: "r"(val)); }) + +#define swap_csr(reg, val) ({ unsigned long __tmp; \ + if (__builtin_constant_p(val) && (unsigned long)(val) < 32) \ + asm volatile ("csrrw %0, " #reg ", %1" : "=r"(__tmp) : "i"(val)); \ + else \ + asm volatile ("csrrw %0, " #reg ", %1" : "=r"(__tmp) : "r"(val)); \ + __tmp; }) + +#define set_csr(reg, bit) ({ unsigned long __tmp; \ + if (__builtin_constant_p(bit) && (unsigned long)(bit) < 32) \ + asm volatile ("csrrs %0, " #reg ", %1" : "=r"(__tmp) : "i"(bit)); \ + else \ + asm volatile ("csrrs %0, " #reg ", %1" : "=r"(__tmp) : "r"(bit)); \ + __tmp; }) + +#define clear_csr(reg, bit) ({ unsigned long __tmp; \ + if (__builtin_constant_p(bit) && (unsigned long)(bit) < 32) \ + asm volatile ("csrrc %0, " #reg ", %1" : "=r"(__tmp) : "i"(bit)); \ + else \ + asm volatile ("csrrc %0, " #reg ", %1" : "=r"(__tmp) : "r"(bit)); \ + __tmp; }) + +#define rdtime() read_csr(time) +#define rdcycle() read_csr(cycle) +#define rdinstret() read_csr(instret) + +#ifdef __riscv_atomic + +#define MASK(nr) (1UL << nr) +#define MASK_NOT(nr) (~(1UL << nr)) + +/** + * atomic_read - read atomic variable + * @v: pointer of type int + * + * Atomically reads the value of @v. + */ +static inline int atomic_read(const int *v) +{ + return *((volatile int *)(v)); +} + +/** + * atomic_set - set atomic variable + * @v: pointer of type int + * @i: required value + * + * Atomically sets the value of @v to @i. + */ +static inline void atomic_set(int *v, int i) +{ + *v = i; +} + +/** + * atomic_add - add integer to atomic variable + * @i: integer value to add + * @v: pointer of type int + * + * Atomically adds @i to @v. + */ +static inline void atomic_add(int i, int *v) +{ + __asm__ __volatile__ ( + "amoadd.w zero, %1, %0" + : "+A" (*v) + : "r" (i)); +} + +static inline int atomic_fetch_add(unsigned int mask, int *v) +{ + int out; + + __asm__ __volatile__ ( + "amoadd.w %2, %1, %0" + : "+A" (*v), "=r" (out) + : "r" (mask)); + return out; +} + +/** + * atomic_sub - subtract integer from atomic variable + * @i: integer value to subtract + * @v: pointer of type int + * + * Atomically subtracts @i from @v. + */ +static inline void atomic_sub(int i, int *v) +{ + atomic_add(-i, v); +} + +static inline int atomic_fetch_sub(unsigned int mask, int *v) +{ + int out; + + __asm__ __volatile__ ( + "amosub.w %2, %1, %0" + : "+A" (*v), "=r" (out) + : "r" (mask)); + return out; +} + +/** + * atomic_add_return - add integer to atomic variable + * @i: integer value to add + * @v: pointer of type int + * + * Atomically adds @i to @v and returns the result + */ +static inline int atomic_add_return(int i, int *v) +{ + register int c; + __asm__ __volatile__ ( + "amoadd.w %0, %2, %1" + : "=r" (c), "+A" (*v) + : "r" (i)); + return (c + i); +} + +/** + * atomic_sub_return - subtract integer from atomic variable + * @i: integer value to subtract + * @v: pointer of type int + * + * Atomically subtracts @i from @v and returns the result + */ +static inline int atomic_sub_return(int i, int *v) +{ + return atomic_add_return(-i, v); +} + +/** + * atomic_inc - increment atomic variable + * @v: pointer of type int + * + * Atomically increments @v by 1. + */ +static inline void atomic_inc(int *v) +{ + atomic_add(1, v); +} + +/** + * atomic_dec - decrement atomic variable + * @v: pointer of type int + * + * Atomically decrements @v by 1. + */ +static inline void atomic_dec(int *v) +{ + atomic_add(-1, v); +} + +static inline int atomic_inc_return(int *v) +{ + return atomic_add_return(1, v); +} + +static inline int atomic_dec_return(int *v) +{ + return atomic_sub_return(1, v); +} + +/** + * atomic_sub_and_test - subtract value from variable and test result + * @i: integer value to subtract + * @v: pointer of type int + * + * Atomically subtracts @i from @v and returns + * true if the result is zero, or false for all + * other cases. + */ +static inline int atomic_sub_and_test(int i, int *v) +{ + return (atomic_sub_return(i, v) == 0); +} + +/** + * atomic_inc_and_test - increment and test + * @v: pointer of type int + * + * Atomically increments @v by 1 + * and returns true if the result is zero, or false for all + * other cases. + */ +static inline int atomic_inc_and_test(int *v) +{ + return (atomic_inc_return(v) == 0); +} + +/** + * atomic_dec_and_test - decrement and test + * @v: pointer of type int + * + * Atomically decrements @v by 1 and + * returns true if the result is 0, or false for all other + * cases. + */ +static inline int atomic_dec_and_test(int *v) +{ + return (atomic_dec_return(v) == 0); +} + +/** + * atomic_add_negative - add and test if negative + * @i: integer value to add + * @v: pointer of type int + * + * Atomically adds @i to @v and returns true + * if the result is negative, or false when + * result is greater than or equal to zero. + */ +static inline int atomic_add_negative(int i, int *v) +{ + return (atomic_add_return(i, v) < 0); +} + +static inline int atomic_xchg(int *v, int n) +{ + register int c; + __asm__ __volatile__ ( + "amoswap.w %0, %2, %1" + : "=r" (c), "+A" (*v) + : "r" (n)); + return c; +} + +/** + * atomic_and - Atomically clear bits in atomic variable + * @mask: Mask of the bits to be retained + * @v: pointer of type int + * + * Atomically retains the bits set in @mask from @v + */ +static inline void atomic_and(unsigned int mask, int *v) +{ + __asm__ __volatile__ ( + "amoand.w zero, %1, %0" + : "+A" (*v) + : "r" (mask)); +} + +static inline int atomic_fetch_and(unsigned int mask, int *v) +{ + int out; + __asm__ __volatile__ ( + "amoand.w %2, %1, %0" + : "+A" (*v), "=r" (out) + : "r" (mask)); + return out; +} + +/** + * atomic_or - Atomically set bits in atomic variable + * @mask: Mask of the bits to be set + * @v: pointer of type int + * + * Atomically sets the bits set in @mask in @v + */ +static inline void atomic_or(unsigned int mask, int *v) +{ + __asm__ __volatile__ ( + "amoor.w zero, %1, %0" + : "+A" (*v) + : "r" (mask)); +} + +static inline int atomic_fetch_or(unsigned int mask, int *v) +{ + int out; + __asm__ __volatile__ ( + "amoor.w %2, %1, %0" + : "+A" (*v), "=r" (out) + : "r" (mask)); + return out; +} + +/** + * atomic_xor - Atomically flips bits in atomic variable + * @mask: Mask of the bits to be flipped + * @v: pointer of type int + * + * Atomically flips the bits set in @mask in @v + */ +static inline void atomic_xor(unsigned int mask, int *v) +{ + __asm__ __volatile__ ( + "amoxor.w zero, %1, %0" + : "+A" (*v) + : "r" (mask)); +} + +static inline int atomic_fetch_xor(unsigned int mask, int *v) +{ + int out; + __asm__ __volatile__ ( + "amoxor.w %2, %1, %0" + : "+A" (*v), "=r" (out) + : "r" (mask)); + return out; +} + +/*----------------------------------------------------*/ + +/** + * test_and_set_bit - Set a bit and return its old value + * @nr: Bit to set + * @addr: Address to count from + * + * This operation is atomic and cannot be reordered. + * It also implies a memory barrier. + */ +static inline int test_and_set_bit(int nr, volatile unsigned long *addr) +{ + unsigned long __res, __mask; + __mask = MASK(nr); + __asm__ __volatile__ ( \ + "amoor.w %0, %2, %1" \ + : "=r" (__res), "+A" (*addr) \ + : "r" (__mask)); \ + + return ((__res & __mask) != 0); +} + + +/** + * test_and_clear_bit - Clear a bit and return its old value + * @nr: Bit to clear + * @addr: Address to count from + * + * This operation is atomic and cannot be reordered. + * It also implies a memory barrier. + */ +static inline int test_and_clear_bit(int nr, volatile unsigned long *addr) +{ + unsigned long __res, __mask; + __mask = MASK_NOT(nr); + __asm__ __volatile__ ( \ + "amoand.w %0, %2, %1" \ + : "=r" (__res), "+A" (*addr) \ + : "r" (__mask)); \ + + return ((__res & __mask) != 0); +} + +/** + * test_and_change_bit - Change a bit and return its old value + * @nr: Bit to change + * @addr: Address to count from + * + * This operation is atomic and cannot be reordered. + * It also implies a memory barrier. + */ +static inline int test_and_change_bit(int nr, volatile unsigned long *addr) +{ + + unsigned long __res, __mask; + __mask = MASK(nr); + __asm__ __volatile__ ( \ + "amoxor.w %0, %2, %1" \ + : "=r" (__res), "+A" (*addr) \ + : "r" (__mask)); \ + + return ((__res & __mask) != 0); +} + +/** + * set_bit - Atomically set a bit in memory + * @nr: the bit to set + * @addr: the address to start counting from + * + * This function is atomic and may not be reordered. + */ + +static inline void set_bit(int nr, volatile unsigned long *addr) +{ + __asm__ __volatile__ ( \ + "AMOOR.w zero, %1, %0" \ + : "+A" (*addr) \ + : "r" (MASK(nr))); +} + +/** + * clear_bit - Clears a bit in memory + * @nr: Bit to clear + * @addr: Address to start counting from + * + * clear_bit() is atomic and may not be reordered. + */ +static inline void clear_bit(int nr, volatile unsigned long *addr) +{ + __asm__ __volatile__ ( \ + "AMOAND.w zero, %1, %0" \ + : "+A" (*addr) \ + : "r" (MASK_NOT(nr))); +} + +/** + * change_bit - Toggle a bit in memory + * @nr: Bit to change + * @addr: Address to start counting from + * + * change_bit() is atomic and may not be reordered. + */ +static inline void change_bit(int nr, volatile unsigned long *addr) +{ + __asm__ __volatile__ ( \ + "AMOXOR.w zero, %1, %0" \ + : "+A" (*addr) \ + : "r" (MASK(nr))); +} + +#endif /* __riscv_atomic */ + +#endif /*__GNUC__*/ + +#endif /*__ASSEMBLER__*/ + +#endif /*__riscv*/ + +#ifdef __cplusplus +} +#endif + +#endif /*RISCV_CSR_ENCODING_H*/ + diff --git a/FreeRTOS/Demo/RISC-V_IGLOO2_Creative_SoftConsole/riscv_hal/entry.S b/FreeRTOS/Demo/RISC-V_IGLOO2_Creative_SoftConsole/riscv_hal/entry.S new file mode 100644 index 000000000..6e3ef92a7 --- /dev/null +++ b/FreeRTOS/Demo/RISC-V_IGLOO2_Creative_SoftConsole/riscv_hal/entry.S @@ -0,0 +1,160 @@ +/******************************************************************************* + * (c) Copyright 2016-2018 Microsemi SoC Products Group. All rights reserved. + * + * @file entry.S + * @author Microsemi SoC Products Group + * @brief Mi-V soft processor vectors, trap handling and startup code. + * + * SVN $Revision: 9947 $ + * SVN $Date: 2018-04-30 20:28:49 +0530 (Mon, 30 Apr 2018) $ + */ +#ifndef ENTRY_S +#define ENTRY_S + +#include "encoding.h" + +#if __riscv_xlen == 64 +# define LREG ld +# define SREG sd +# define REGBYTES 8 +#else +# define LREG lw +# define SREG sw +# define REGBYTES 4 +#endif + + .section .text.entry + .globl _start + +_start: + j handle_reset + +nmi_vector: + j nmi_vector + +trap_vector: + j trap_entry + +handle_reset: + la t0, trap_entry + csrw mtvec, t0 + csrwi mstatus, 0 + csrwi mie, 0 + +/*Floating point support configuration*/ + +#ifdef __riscv_flen + csrr t0, mstatus + lui t1, 0xffffa + addi t1, t1, -1 + and t0, t0, t1 + lui t1, 0x4 + or t1, t0, t1 + csrw mstatus, t1 + + lui t0, 0x0 + fscsr t0 +#endif +.option push + +# Ensure the instruction is not optimized, since gp is not yet set + +.option norelax + # initialize global pointer + la gp, __global_pointer$ + +.option pop + + # initialize stack pointer + la sp, __stack_top + + # perform the rest of initialization in C + j _init + + +trap_entry: + addi sp, sp, -32*REGBYTES + + SREG x1, 0 * REGBYTES(sp) + SREG x2, 1 * REGBYTES(sp) + SREG x3, 2 * REGBYTES(sp) + SREG x4, 3 * REGBYTES(sp) + SREG x5, 4 * REGBYTES(sp) + SREG x6, 5 * REGBYTES(sp) + SREG x7, 6 * REGBYTES(sp) + SREG x8, 7 * REGBYTES(sp) + SREG x9, 8 * REGBYTES(sp) + SREG x10, 9 * REGBYTES(sp) + SREG x11, 10 * REGBYTES(sp) + SREG x12, 11 * REGBYTES(sp) + SREG x13, 12 * REGBYTES(sp) + SREG x14, 13 * REGBYTES(sp) + SREG x15, 14 * REGBYTES(sp) + SREG x16, 15 * REGBYTES(sp) + SREG x17, 16 * REGBYTES(sp) + SREG x18, 17 * REGBYTES(sp) + SREG x19, 18 * REGBYTES(sp) + SREG x20, 19 * REGBYTES(sp) + SREG x21, 20 * REGBYTES(sp) + SREG x22, 21 * REGBYTES(sp) + SREG x23, 22 * REGBYTES(sp) + SREG x24, 23 * REGBYTES(sp) + SREG x25, 24 * REGBYTES(sp) + SREG x26, 25 * REGBYTES(sp) + SREG x27, 26 * REGBYTES(sp) + SREG x28, 27 * REGBYTES(sp) + SREG x29, 28 * REGBYTES(sp) + SREG x30, 29 * REGBYTES(sp) + SREG x31, 30 * REGBYTES(sp) + + + csrr t0, mepc + SREG t0, 31 * REGBYTES(sp) + + csrr a0, mcause + csrr a1, mepc + mv a2, sp + jal handle_trap + csrw mepc, a0 + + # Remain in M-mode after mret + li t0, MSTATUS_MPP + csrs mstatus, t0 + + LREG x1, 0 * REGBYTES(sp) + LREG x2, 1 * REGBYTES(sp) + LREG x3, 2 * REGBYTES(sp) + LREG x4, 3 * REGBYTES(sp) + LREG x5, 4 * REGBYTES(sp) + LREG x6, 5 * REGBYTES(sp) + LREG x7, 6 * REGBYTES(sp) + LREG x8, 7 * REGBYTES(sp) + LREG x9, 8 * REGBYTES(sp) + LREG x10, 9 * REGBYTES(sp) + LREG x11, 10 * REGBYTES(sp) + LREG x12, 11 * REGBYTES(sp) + LREG x13, 12 * REGBYTES(sp) + LREG x14, 13 * REGBYTES(sp) + LREG x15, 14 * REGBYTES(sp) + LREG x16, 15 * REGBYTES(sp) + LREG x17, 16 * REGBYTES(sp) + LREG x18, 17 * REGBYTES(sp) + LREG x19, 18 * REGBYTES(sp) + LREG x20, 19 * REGBYTES(sp) + LREG x21, 20 * REGBYTES(sp) + LREG x22, 21 * REGBYTES(sp) + LREG x23, 22 * REGBYTES(sp) + LREG x24, 23 * REGBYTES(sp) + LREG x25, 24 * REGBYTES(sp) + LREG x26, 25 * REGBYTES(sp) + LREG x27, 26 * REGBYTES(sp) + LREG x28, 27 * REGBYTES(sp) + LREG x29, 28 * REGBYTES(sp) + LREG x30, 29 * REGBYTES(sp) + LREG x31, 30 * REGBYTES(sp) + + addi sp, sp, 32*REGBYTES + mret + +#endif + diff --git a/FreeRTOS/Demo/RISC-V_IGLOO2_Creative_SoftConsole/riscv_hal/init.c b/FreeRTOS/Demo/RISC-V_IGLOO2_Creative_SoftConsole/riscv_hal/init.c new file mode 100644 index 000000000..8c5998f4d --- /dev/null +++ b/FreeRTOS/Demo/RISC-V_IGLOO2_Creative_SoftConsole/riscv_hal/init.c @@ -0,0 +1,80 @@ +/******************************************************************************* + * (c) Copyright 2016-2018 Microsemi SoC Products Group. All rights reserved. + * + * @file init.c + * @author Microsemi SoC Products Group + * @brief Mi-V soft processor memory section initializations and start-up code. + * + * SVN $Revision: 9661 $ + * SVN $Date: 2018-01-15 16:13:33 +0530 (Mon, 15 Jan 2018) $ + */ + +#include +#include +#include + +#include "encoding.h" + +#ifdef __cplusplus +extern "C" { +#endif + +extern uint32_t __sdata_load; +extern uint32_t __sdata_start; +extern uint32_t __sdata_end; + +extern uint32_t __data_load; +extern uint32_t __data_start; +extern uint32_t __data_end; + +extern uint32_t __sbss_start; +extern uint32_t __sbss_end; +extern uint32_t __bss_start; +extern uint32_t __bss_end; + + +static void copy_section(uint32_t * p_load, uint32_t * p_vma, uint32_t * p_vma_end) +{ + while(p_vma <= p_vma_end) + { + *p_vma = *p_load; + ++p_load; + ++p_vma; + } +} + +static void zero_section(uint32_t * start, uint32_t * end) +{ + uint32_t * p_zero = start; + + while(p_zero <= end) + { + *p_zero = 0; + ++p_zero; + } +} + +void _init(void) +{ + extern int main(int, char**); + const char *argv0 = "hello"; + char *argv[] = {(char *)argv0, NULL, NULL}; + + copy_section(&__sdata_load, &__sdata_start, &__sdata_end); + copy_section(&__data_load, &__data_start, &__data_end); + zero_section(&__sbss_start, &__sbss_end); + zero_section(&__bss_start, &__bss_end); + + main(1, argv); +} + +/* Function called after main() finishes */ +void +_fini() +{ +} + +#ifdef __cplusplus +} +#endif + diff --git a/FreeRTOS/Demo/RISC-V_IGLOO2_Creative_SoftConsole/riscv_hal/microsemi-riscv-igloo2.ld b/FreeRTOS/Demo/RISC-V_IGLOO2_Creative_SoftConsole/riscv_hal/microsemi-riscv-igloo2.ld new file mode 100644 index 000000000..11d069715 --- /dev/null +++ b/FreeRTOS/Demo/RISC-V_IGLOO2_Creative_SoftConsole/riscv_hal/microsemi-riscv-igloo2.ld @@ -0,0 +1,137 @@ +/******************************************************************************* + * (c) Copyright 2016-2018 Microsemi SoC Products Group. All rights reserved. + * + * file name : microsemi-riscv-igloo2.ld + * Mi-V soft processor linker script for creating a SoftConsole downloadable + * image executing in eNVM. + * + * This linker script assumes that the eNVM is connected at on the Mi-V soft + * processor memory space. + * + * SVN $Revision: 9661 $ + * SVN $Date: 2018-01-15 16:13:33 +0530 (Mon, 15 Jan 2018) $ + */ + +OUTPUT_ARCH( "riscv" ) +ENTRY(_start) + + +MEMORY +{ + envm (rx) : ORIGIN = 0x60000000, LENGTH = 240k + ram (rwx) : ORIGIN = 0x80000000, LENGTH = 64k +} + +RAM_START_ADDRESS = 0x80000000; /* Must be the same value MEMORY region ram ORIGIN above. */ +RAM_SIZE = 64k; /* Must be the same value MEMORY region ram LENGTH above. */ +STACK_SIZE = 2k; /* needs to be calculated for your application */ +HEAP_SIZE = 2k; /* needs to be calculated for your application */ + +SECTIONS +{ + .text : ALIGN(0x10) + { + KEEP (*(SORT_NONE(.text.entry))) + . = ALIGN(0x10); + *(.text .text.* .gnu.linkonce.t.*) + *(.plt) + . = ALIGN(0x10); + + KEEP (*crtbegin.o(.ctors)) + KEEP (*(EXCLUDE_FILE (*crtend.o) .ctors)) + KEEP (*(SORT(.ctors.*))) + KEEP (*crtend.o(.ctors)) + KEEP (*crtbegin.o(.dtors)) + KEEP (*(EXCLUDE_FILE (*crtend.o) .dtors)) + KEEP (*(SORT(.dtors.*))) + KEEP (*crtend.o(.dtors)) + + *(.rodata .rodata.* .gnu.linkonce.r.*) + *(.gcc_except_table) + *(.eh_frame_hdr) + *(.eh_frame) + + KEEP (*(.init)) + KEEP (*(.fini)) + + PROVIDE_HIDDEN (__preinit_array_start = .); + KEEP (*(.preinit_array)) + PROVIDE_HIDDEN (__preinit_array_end = .); + PROVIDE_HIDDEN (__init_array_start = .); + KEEP (*(SORT(.init_array.*))) + KEEP (*(.init_array)) + PROVIDE_HIDDEN (__init_array_end = .); + PROVIDE_HIDDEN (__fini_array_start = .); + KEEP (*(.fini_array)) + KEEP (*(SORT(.fini_array.*))) + PROVIDE_HIDDEN (__fini_array_end = .); + . = ALIGN(0x10); + + } >envm + + /* short/global data section */ + .sdata : ALIGN(0x10) + { + __sdata_load = LOADADDR(.sdata); + __sdata_start = .; + PROVIDE( __global_pointer$ = . + 0x800); + *(.srodata.cst16) *(.srodata.cst8) *(.srodata.cst4) *(.srodata.cst2) + *(.srodata*) + *(.sdata .sdata.* .gnu.linkonce.s.*) + . = ALIGN(0x10); + __sdata_end = .; + } >ram AT>envm + + /* data section */ + .data : ALIGN(0x10) + { + __data_load = LOADADDR(.data); + __data_start = .; + *(.got.plt) *(.got) + *(.shdata) + *(.data .data.* .gnu.linkonce.d.*) + . = ALIGN(0x10); + __data_end = .; + } >ram AT>envm + + /* sbss section */ + .sbss : ALIGN(0x10) + { + __sbss_start = .; + *(.sbss .sbss.* .gnu.linkonce.sb.*) + *(.scommon) + . = ALIGN(0x10); + __sbss_end = .; + } > ram + + /* sbss section */ + .bss : ALIGN(0x10) + { + __bss_start = .; + *(.shbss) + *(.bss .bss.* .gnu.linkonce.b.*) + *(COMMON) + . = ALIGN(0x10); + __bss_end = .; + } > ram + + /* End of uninitialized data segment */ + _end = .; + + .heap : ALIGN(0x10) + { + __heap_start = .; + . += HEAP_SIZE; + __heap_end = .; + . = ALIGN(0x10); + _heap_end = __heap_end; + } > ram + + .stack : ALIGN(0x10) + { + __stack_bottom = .; + . += STACK_SIZE; + __stack_top = .; + } > ram +} + diff --git a/FreeRTOS/Demo/RISC-V_IGLOO2_Creative_SoftConsole/riscv_hal/microsemi-riscv-ram.ld b/FreeRTOS/Demo/RISC-V_IGLOO2_Creative_SoftConsole/riscv_hal/microsemi-riscv-ram.ld new file mode 100644 index 000000000..d63709e68 --- /dev/null +++ b/FreeRTOS/Demo/RISC-V_IGLOO2_Creative_SoftConsole/riscv_hal/microsemi-riscv-ram.ld @@ -0,0 +1,137 @@ +/******************************************************************************* + * (c) Copyright 2016-2018 Microsemi SoC Products Group. All rights reserved. + * + * file name : microsemi-riscv-ram.ld + * Mi-V soft processor linker script for creating a SoftConsole downloadable + * debug image executing in SRAM. + * + * This linker script assumes that the SRAM is connected at on the Mi-V soft + * processor memory space. The start address and size of the memory space must + * be correct as per the Libero design. + * + * SVN $Revision: 9661 $ + * SVN $Date: 2018-01-15 16:13:33 +0530 (Mon, 15 Jan 2018) $ + */ + +OUTPUT_ARCH( "riscv" ) +ENTRY(_start) + + +MEMORY +{ + ram (rwx) : ORIGIN = 0x80000000, LENGTH = 512k +} + +RAM_START_ADDRESS = 0x80000000; /* Must be the same value MEMORY region ram ORIGIN above. */ +RAM_SIZE = 512k; /* Must be the same value MEMORY region ram LENGTH above. */ +STACK_SIZE = 64k; /* needs to be calculated for your application */ +HEAP_SIZE = 64k; /* needs to be calculated for your application */ + +SECTIONS +{ + .text : ALIGN(0x10) + { + KEEP (*(SORT_NONE(.text.entry))) + . = ALIGN(0x10); + *(.text .text.* .gnu.linkonce.t.*) + *(.plt) + . = ALIGN(0x10); + + KEEP (*crtbegin.o(.ctors)) + KEEP (*(EXCLUDE_FILE (*crtend.o) .ctors)) + KEEP (*(SORT(.ctors.*))) + KEEP (*crtend.o(.ctors)) + KEEP (*crtbegin.o(.dtors)) + KEEP (*(EXCLUDE_FILE (*crtend.o) .dtors)) + KEEP (*(SORT(.dtors.*))) + KEEP (*crtend.o(.dtors)) + + *(.rodata .rodata.* .gnu.linkonce.r.*) + *(.gcc_except_table) + *(.eh_frame_hdr) + *(.eh_frame) + + KEEP (*(.init)) + KEEP (*(.fini)) + + PROVIDE_HIDDEN (__preinit_array_start = .); + KEEP (*(.preinit_array)) + PROVIDE_HIDDEN (__preinit_array_end = .); + PROVIDE_HIDDEN (__init_array_start = .); + KEEP (*(SORT(.init_array.*))) + KEEP (*(.init_array)) + PROVIDE_HIDDEN (__init_array_end = .); + PROVIDE_HIDDEN (__fini_array_start = .); + KEEP (*(.fini_array)) + KEEP (*(SORT(.fini_array.*))) + PROVIDE_HIDDEN (__fini_array_end = .); + . = ALIGN(0x10); + + } > ram + + /* short/global data section */ + .sdata : ALIGN(0x10) + { + __sdata_load = LOADADDR(.sdata); + __sdata_start = .; + PROVIDE( __global_pointer$ = . + 0x800); + *(.srodata.cst16) *(.srodata.cst8) *(.srodata.cst4) *(.srodata.cst2) + *(.srodata*) + *(.sdata .sdata.* .gnu.linkonce.s.*) + . = ALIGN(0x10); + __sdata_end = .; + } > ram + + /* data section */ + .data : ALIGN(0x10) + { + __data_load = LOADADDR(.data); + __data_start = .; + *(.got.plt) *(.got) + *(.shdata) + *(.data .data.* .gnu.linkonce.d.*) + . = ALIGN(0x10); + __data_end = .; + } > ram + + /* sbss section */ + .sbss : ALIGN(0x10) + { + __sbss_start = .; + *(.sbss .sbss.* .gnu.linkonce.sb.*) + *(.scommon) + . = ALIGN(0x10); + __sbss_end = .; + } > ram + + /* sbss section */ + .bss : ALIGN(0x10) + { + __bss_start = .; + *(.shbss) + *(.bss .bss.* .gnu.linkonce.b.*) + *(COMMON) + . = ALIGN(0x10); + __bss_end = .; + } > ram + + /* End of uninitialized data segment */ + _end = .; + + .heap : ALIGN(0x10) + { + __heap_start = .; + . += HEAP_SIZE; + __heap_end = .; + . = ALIGN(0x10); + _heap_end = __heap_end; + } > ram + + .stack : ALIGN(0x10) + { + __stack_bottom = .; + . += STACK_SIZE; + __stack_top = .; + } > ram +} + diff --git a/FreeRTOS/Demo/RISC-V_IGLOO2_Creative_SoftConsole/riscv_hal/riscv_hal.c b/FreeRTOS/Demo/RISC-V_IGLOO2_Creative_SoftConsole/riscv_hal/riscv_hal.c new file mode 100644 index 000000000..f7be82c09 --- /dev/null +++ b/FreeRTOS/Demo/RISC-V_IGLOO2_Creative_SoftConsole/riscv_hal/riscv_hal.c @@ -0,0 +1,251 @@ +/******************************************************************************* + * (c) Copyright 2016-2018 Microsemi SoC Products Group. All rights reserved. + * + * @file riscv_hal.c + * @author Microsemi SoC Products Group + * @brief Implementation of Hardware Abstraction Layer for Mi-V soft processors + * + * SVN $Revision: 9835 $ + * SVN $Date: 2018-03-19 19:11:35 +0530 (Mon, 19 Mar 2018) $ + */ +#include +#include +#include + +#include "riscv_hal.h" + +#ifdef __cplusplus +extern "C" { +#endif + +#define RTC_PRESCALER 100UL + +#define SUCCESS 0U +#define ERROR 1U + +/*------------------------------------------------------------------------------ + * + */ +uint8_t Invalid_IRQHandler(void); +uint8_t External_1_IRQHandler(void); +uint8_t External_2_IRQHandler(void); +uint8_t External_3_IRQHandler(void); +uint8_t External_4_IRQHandler(void); +uint8_t External_5_IRQHandler(void); +uint8_t External_6_IRQHandler(void); +uint8_t External_7_IRQHandler(void); +uint8_t External_8_IRQHandler(void); +uint8_t External_9_IRQHandler(void); +uint8_t External_10_IRQHandler(void); +uint8_t External_11_IRQHandler(void); +uint8_t External_12_IRQHandler(void); +uint8_t External_13_IRQHandler(void); +uint8_t External_14_IRQHandler(void); +uint8_t External_15_IRQHandler(void); +uint8_t External_16_IRQHandler(void); +uint8_t External_17_IRQHandler(void); +uint8_t External_18_IRQHandler(void); +uint8_t External_19_IRQHandler(void); +uint8_t External_20_IRQHandler(void); +uint8_t External_21_IRQHandler(void); +uint8_t External_22_IRQHandler(void); +uint8_t External_23_IRQHandler(void); +uint8_t External_24_IRQHandler(void); +uint8_t External_25_IRQHandler(void); +uint8_t External_26_IRQHandler(void); +uint8_t External_27_IRQHandler(void); +uint8_t External_28_IRQHandler(void); +uint8_t External_29_IRQHandler(void); +uint8_t External_30_IRQHandler(void); +uint8_t External_31_IRQHandler(void); + +/*------------------------------------------------------------------------------ + * + */ +extern void Software_IRQHandler(void); + +/*------------------------------------------------------------------------------ + * Increment value for the mtimecmp register in order to achieve a system tick + * interrupt as specified through the SysTick_Config() function. + */ +static uint64_t g_systick_increment = 0U; + +/*------------------------------------------------------------------------------ + * Disable all interrupts. + */ +void __disable_irq(void) +{ + clear_csr(mstatus, MSTATUS_MPIE); + clear_csr(mstatus, MSTATUS_MIE); +} + +/*------------------------------------------------------------------------------ + * Enabler all interrupts. + */ +void __enable_irq(void) +{ + set_csr(mstatus, MSTATUS_MIE); +} + +/*------------------------------------------------------------------------------ + * Configure the machine timer to generate an interrupt. + */ +uint32_t SysTick_Config(uint32_t ticks) +{ + uint32_t ret_val = ERROR; + + g_systick_increment = (uint64_t)(ticks) / RTC_PRESCALER; + + if (g_systick_increment > 0U) + { + uint32_t mhart_id = read_csr(mhartid); + + PRCI->MTIMECMP[mhart_id] = PRCI->MTIME + g_systick_increment; + + set_csr(mie, MIP_MTIP); + + __enable_irq(); + + ret_val = SUCCESS; + } + + return ret_val; +} + +/*------------------------------------------------------------------------------ + * RISC-V interrupt handler for machine timer interrupts. + */ +static void handle_m_timer_interrupt(void) +{ + clear_csr(mie, MIP_MTIP); + + SysTick_Handler(); + + PRCI->MTIMECMP[read_csr(mhartid)] = PRCI->MTIME + g_systick_increment; + + set_csr(mie, MIP_MTIP); +} + +/*------------------------------------------------------------------------------ + * RISC-V interrupt handler for external interrupts. + */ +uint8_t (*ext_irq_handler_table[32])(void) = +{ + Invalid_IRQHandler, + External_1_IRQHandler, + External_2_IRQHandler, + External_3_IRQHandler, + External_4_IRQHandler, + External_5_IRQHandler, + External_6_IRQHandler, + External_7_IRQHandler, + External_8_IRQHandler, + External_9_IRQHandler, + External_10_IRQHandler, + External_11_IRQHandler, + External_12_IRQHandler, + External_13_IRQHandler, + External_14_IRQHandler, + External_15_IRQHandler, + External_16_IRQHandler, + External_17_IRQHandler, + External_18_IRQHandler, + External_19_IRQHandler, + External_20_IRQHandler, + External_21_IRQHandler, + External_22_IRQHandler, + External_23_IRQHandler, + External_24_IRQHandler, + External_25_IRQHandler, + External_26_IRQHandler, + External_27_IRQHandler, + External_28_IRQHandler, + External_29_IRQHandler, + External_30_IRQHandler, + External_31_IRQHandler +}; + +/*------------------------------------------------------------------------------ + * + */ +static void handle_m_ext_interrupt(void) +{ + uint32_t int_num = PLIC_ClaimIRQ(); + uint8_t disable = EXT_IRQ_KEEP_ENABLED; + + disable = ext_irq_handler_table[int_num](); + + PLIC_CompleteIRQ(int_num); + + if(EXT_IRQ_DISABLE == disable) + { + PLIC_DisableIRQ((IRQn_Type)int_num); + } +} + +static void handle_m_soft_interrupt(void) +{ + Software_IRQHandler(); + + /*Clear software interrupt*/ + PRCI->MSIP[0] = 0x00U; +} + +/*------------------------------------------------------------------------------ + * Trap/Interrupt handler + */ +uintptr_t handle_trap(uintptr_t mcause, uintptr_t mepc) +{ + if ((mcause & MCAUSE_INT) && ((mcause & MCAUSE_CAUSE) == IRQ_M_EXT)) + { + handle_m_ext_interrupt(); + } + else if ((mcause & MCAUSE_INT) && ((mcause & MCAUSE_CAUSE) == IRQ_M_TIMER)) + { + handle_m_timer_interrupt(); + } + else if ( (mcause & MCAUSE_INT) && ((mcause & MCAUSE_CAUSE) == IRQ_M_SOFT)) + { + handle_m_soft_interrupt(); + } + else + { +#ifndef NDEBUG + /* + Arguments supplied to this function are mcause, mepc (exception PC) and stack pointer + based onprivileged-isa specification + mcause values and meanings are: + 0 Instruction address misaligned (mtval/mbadaddr is the address) + 1 Instruction access fault (mtval/mbadaddr is the address) + 2 Illegal instruction (mtval/mbadaddr contains the offending instruction opcode) + 3 Breakpoint + 4 Load address misaligned (mtval/mbadaddr is the address) + 5 Load address fault (mtval/mbadaddr is the address) + 6 Store/AMO address fault (mtval/mbadaddr is the address) + 7 Store/AMO access fault (mtval/mbadaddr is the address) + 8 Environment call from U-mode + 9 Environment call from S-mode + A Environment call from M-mode + B Instruction page fault + C Load page fault (mtval/mbadaddr is the address) + E Store page fault (mtval/mbadaddr is the address) + */ + + uintptr_t mip = read_csr(mip); /* interrupt pending */ + uintptr_t mbadaddr = read_csr(mbadaddr); /* additional info and meaning depends on mcause */ + uintptr_t mtvec = read_csr(mtvec); /* trap vector */ + uintptr_t mscratch = read_csr(mscratch); /* temporary, sometimes might hold temporary value of a0 */ + uintptr_t mstatus = read_csr(mstatus); /* status contains many smaller fields: */ + + /* breakpoint*/ + __asm("ebreak"); +#else + _exit(1 + mcause); +#endif + } + return mepc; +} + +#ifdef __cplusplus +} +#endif diff --git a/FreeRTOS/Demo/RISC-V_IGLOO2_Creative_SoftConsole/riscv_hal/riscv_hal.h b/FreeRTOS/Demo/RISC-V_IGLOO2_Creative_SoftConsole/riscv_hal/riscv_hal.h new file mode 100644 index 000000000..7c3835fe3 --- /dev/null +++ b/FreeRTOS/Demo/RISC-V_IGLOO2_Creative_SoftConsole/riscv_hal/riscv_hal.h @@ -0,0 +1,55 @@ +/******************************************************************************* + * (c) Copyright 2016-2018 Microsemi SoC Products Group. All rights reserved. + * + * @file riscv_hal.h + * @author Microsemi SoC Products Group + * @brief Hardware Abstraction Layer functions for Mi-V soft processors + * + * SVN $Revision: 9835 $ + * SVN $Date: 2018-03-19 19:11:35 +0530 (Mon, 19 Mar 2018) $ + */ + +#ifndef RISCV_HAL_H +#define RISCV_HAL_H + +#include "riscv_plic.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/* + *Return value from External IRQ handler. This will be used to disable the External + *interrupt. + */ +#define EXT_IRQ_KEEP_ENABLED 0U +#define EXT_IRQ_DISABLE 1U + +/*------------------------------------------------------------------------------ + * Interrupt enable/disable. + */ +void __disable_irq(void); +void __enable_irq(void); + +/*------------------------------------------------------------------------------ + * System tick handler. This is generated from the RISC-V machine timer. + */ +void SysTick_Handler(void); + +/*------------------------------------------------------------------------------ + * System tick configuration. + * Configures the machine timer to generate a system tick interrupt at regular + * intervals. + * Takes the number of system clock ticks between interrupts. + * + * Returns 0 if successful. + * Returns 1 if the interrupt interval cannot be achieved. + */ +uint32_t SysTick_Config(uint32_t ticks); + +#ifdef __cplusplus +} +#endif + +#endif /* RISCV_HAL_H */ + diff --git a/FreeRTOS/Demo/RISC-V_IGLOO2_Creative_SoftConsole/riscv_hal/riscv_hal_stubs.c b/FreeRTOS/Demo/RISC-V_IGLOO2_Creative_SoftConsole/riscv_hal/riscv_hal_stubs.c new file mode 100644 index 000000000..29a4f407e --- /dev/null +++ b/FreeRTOS/Demo/RISC-V_IGLOO2_Creative_SoftConsole/riscv_hal/riscv_hal_stubs.c @@ -0,0 +1,227 @@ +/******************************************************************************* + * (c) Copyright 2016-2018 Microsemi SoC Products Group. All rights reserved. + * + * @file riscv_hal_stubs.c + * @author Microsemi SoC Products Group + * @brief Mi-V soft processor Interrupt Function stubs. + * The functions below will only be linked with the application code if the user + * does not provide an implementation for these functions. These functions are + * defined with weak linking so that they can be overridden by a function with + * same prototype in the user's application code. + * + * SVN $Revision: 9835 $ + * SVN $Date: 2018-03-19 19:11:35 +0530 (Mon, 19 Mar 2018) $ + */ +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/*Weakly linked handler. Will be replaced with user's definition if provided*/ +__attribute__((weak)) void Software_IRQHandler(void) +{ + _exit(10); +} + +/*Weakly linked handler. Will be replaced with user's definition if provided*/ +__attribute__((weak)) void SysTick_Handler(void) +{ + /*Default handler*/ +} + +/*Weakly linked handler. Will be replaced with user's definition if provided*/ +__attribute__((weak)) uint8_t Invalid_IRQHandler(void) +{ + return(0U); /*Default handler*/ +} + +/*Weakly linked handler. Will be replaced with user's definition if provided*/ +__attribute__((weak)) uint8_t External_1_IRQHandler(void) +{ + return(0U); /*Default handler*/ +} + +/*Weakly linked handler. Will be replaced with user's definition if provided*/ +__attribute__((weak)) uint8_t External_2_IRQHandler(void) +{ + return(0U); /*Default handler*/ +} + +/*Weakly linked handler. Will be replaced with user's definition if provided*/ +__attribute__((weak)) uint8_t External_3_IRQHandler(void) +{ + return(0U); /*Default handler*/ +} + +/*Weakly linked handler. Will be replaced with user's definition if provided*/ +__attribute__((weak)) uint8_t External_4_IRQHandler(void) +{ + return(0U); /*Default handler*/ +} + +/*Weakly linked handler. Will be replaced with user's definition if provided*/ +__attribute__((weak)) uint8_t External_5_IRQHandler(void) +{ + return(0U); /*Default handler*/ +} + +/*Weakly linked handler. Will be replaced with user's definition if provided*/ +__attribute__((weak)) uint8_t External_6_IRQHandler(void) +{ + return(0U); /*Default handler*/ +} + +/*Weakly linked handler. Will be replaced with user's definition if provided*/ +__attribute__((weak)) uint8_t External_7_IRQHandler(void) +{ + return(0U); /*Default handler*/ +} + +/*Weakly linked handler. Will be replaced with user's definition if provided*/ +__attribute__((weak)) uint8_t External_8_IRQHandler(void) +{ + return(0U); /*Default handler*/ +} + +/*Weakly linked handler. Will be replaced with user's definition if provided*/ +__attribute__((weak)) uint8_t External_9_IRQHandler(void) +{ + return(0U); /*Default handler*/ +} + +/*Weakly linked handler. Will be replaced with user's definition if provided*/ +__attribute__((weak)) uint8_t External_10_IRQHandler(void) +{ + return(0U); /*Default handler*/ +} + +/*Weakly linked handler. Will be replaced with user's definition if provided*/ +__attribute__((weak)) uint8_t External_11_IRQHandler(void) +{ + return(0U); /*Default handler*/ +} + +/*Weakly linked handler. Will be replaced with user's definition if provided*/ +__attribute__((weak)) uint8_t External_12_IRQHandler(void) +{ + return(0U); /*Default handler*/ +} + +/*Weakly linked handler. Will be replaced with user's definition if provided*/ +__attribute__((weak)) uint8_t External_13_IRQHandler(void) +{ + return(0U); /*Default handler*/ +} + +/*Weakly linked handler. Will be replaced with user's definition if provided*/ +__attribute__((weak)) uint8_t External_14_IRQHandler(void) +{ + return(0U); /*Default handler*/ +} + +/*Weakly linked handler. Will be replaced with user's definition if provided*/ +__attribute__((weak)) uint8_t External_15_IRQHandler(void) +{ + return(0U); /*Default handler*/ +} + +/*Weakly linked handler. Will be replaced with user's definition if provided*/ +__attribute__((weak)) uint8_t External_16_IRQHandler(void) +{ + return(0U); /*Default handler*/ +} + +/*Weakly linked handler. Will be replaced with user's definition if provided*/ +__attribute__((weak)) uint8_t External_17_IRQHandler(void) +{ + return(0U); /*Default handler*/ +} + +/*Weakly linked handler. Will be replaced with user's definition if provided*/ +__attribute__((weak)) uint8_t External_18_IRQHandler(void) +{ + return(0U); /*Default handler*/ +} + +/*Weakly linked handler. Will be replaced with user's definition if provided*/ +__attribute__((weak)) uint8_t External_19_IRQHandler(void) +{ + return(0U); /*Default handler*/ +} + +/*Weakly linked handler. Will be replaced with user's definition if provided*/ +__attribute__((weak)) uint8_t External_20_IRQHandler(void) +{ + return(0U); /*Default handler*/ +} + +/*Weakly linked handler. Will be replaced with user's definition if provided*/ +__attribute__((weak)) uint8_t External_21_IRQHandler(void) +{ + return(0U); /*Default handler*/ +} + +/*Weakly linked handler. Will be replaced with user's definition if provided*/ +__attribute__((weak)) uint8_t External_22_IRQHandler(void) +{ + return(0U); /*Default handler*/ +} + +/*Weakly linked handler. Will be replaced with user's definition if provided*/ +__attribute__((weak)) uint8_t External_23_IRQHandler(void) +{ + return(0U); /*Default handler*/ +} + +/*Weakly linked handler. Will be replaced with user's definition if provided*/ +__attribute__((weak)) uint8_t External_24_IRQHandler(void) +{ + return(0U); /*Default handler*/ +} + +/*Weakly linked handler. Will be replaced with user's definition if provided*/ +__attribute__((weak)) uint8_t External_25_IRQHandler(void) +{ + return(0U); /*Default handler*/ +} + +/*Weakly linked handler. Will be replaced with user's definition if provided*/ +__attribute__((weak)) uint8_t External_26_IRQHandler(void) +{ + return(0U); /*Default handler*/ +} + +/*Weakly linked handler. Will be replaced with user's definition if provided*/ +__attribute__((weak)) uint8_t External_27_IRQHandler(void) +{ + return(0U); /*Default handler*/ +} + +/*Weakly linked handler. Will be replaced with user's definition if provided*/ +__attribute__((weak)) uint8_t External_28_IRQHandler(void) +{ + return(0U); /*Default handler*/ +} + +/*Weakly linked handler. Will be replaced with user's definition if provided*/ +__attribute__((weak)) uint8_t External_29_IRQHandler(void) +{ + return(0U); /*Default handler*/ +} + +/*Weakly linked handler. Will be replaced with user's definition if provided*/ +__attribute__((weak)) uint8_t External_30_IRQHandler(void) +{ + return(0U); /*Default handler*/ +} + +/*Weakly linked handler. Will be replaced with user's definition if provide*/ +__attribute__((weak)) uint8_t External_31_IRQHandler(void) +{ + return(0U); /*Default handler*/ +} + +#ifdef __cplusplus +} +#endif diff --git a/FreeRTOS/Demo/RISC-V_IGLOO2_Creative_SoftConsole/riscv_hal/riscv_plic.h b/FreeRTOS/Demo/RISC-V_IGLOO2_Creative_SoftConsole/riscv_hal/riscv_plic.h new file mode 100644 index 000000000..2d0951891 --- /dev/null +++ b/FreeRTOS/Demo/RISC-V_IGLOO2_Creative_SoftConsole/riscv_hal/riscv_plic.h @@ -0,0 +1,249 @@ +/******************************************************************************* + * (c) Copyright 2016-2018 Microsemi SoC Products Group. All rights reserved. + * + * @file riscv_plic.h + * @author Microsemi SoC Products Group + * @brief Mi-V soft processor PLIC and PRCI access data structures and functions. + * + * SVN $Revision: 9838 $ + * SVN $Date: 2018-03-19 19:22:54 +0530 (Mon, 19 Mar 2018) $ + */ +#ifndef RISCV_PLIC_H +#define RISCV_PLIC_H + +#include + +#include "encoding.h" + +#ifdef __cplusplus +extern "C" { +#endif + +#define PLIC_NUM_SOURCES 31 +#define PLIC_NUM_PRIORITIES 0 + +/*============================================================================== + * Interrupt numbers: + */ +typedef enum +{ + NoInterrupt_IRQn = 0, + External_1_IRQn = 1, + External_2_IRQn = 2, + External_3_IRQn = 3, + External_4_IRQn = 4, + External_5_IRQn = 5, + External_6_IRQn = 6, + External_7_IRQn = 7, + External_8_IRQn = 8, + External_9_IRQn = 9, + External_10_IRQn = 10, + External_11_IRQn = 11, + External_12_IRQn = 12, + External_13_IRQn = 13, + External_14_IRQn = 14, + External_15_IRQn = 15, + External_16_IRQn = 16, + External_17_IRQn = 17, + External_18_IRQn = 18, + External_19_IRQn = 19, + External_20_IRQn = 20, + External_21_IRQn = 21, + External_22_IRQn = 22, + External_23_IRQn = 23, + External_24_IRQn = 24, + External_25_IRQn = 25, + External_26_IRQn = 26, + External_27_IRQn = 27, + External_28_IRQn = 28, + External_29_IRQn = 29, + External_30_IRQn = 30, + External_31_IRQn = 31 +} IRQn_Type; + + +/*============================================================================== + * PLIC: Platform Level Interrupt Controller + */ +#define PLIC_BASE_ADDR 0x40000000UL + +typedef struct +{ + volatile uint32_t PRIORITY_THRESHOLD; + volatile uint32_t CLAIM_COMPLETE; + volatile uint32_t reserved[1022]; +} IRQ_Target_Type; + +typedef struct +{ + volatile uint32_t ENABLES[32]; +} Target_Enables_Type; + +typedef struct +{ + /*-------------------- Source Priority --------------------*/ + volatile uint32_t SOURCE_PRIORITY[1024]; + + /*-------------------- Pending array --------------------*/ + volatile const uint32_t PENDING_ARRAY[32]; + volatile uint32_t RESERVED1[992]; + + /*-------------------- Target enables --------------------*/ + volatile Target_Enables_Type TARGET_ENABLES[15808]; + + volatile uint32_t RESERVED2[16384]; + + /*--- Target Priority threshold and claim/complete---------*/ + IRQ_Target_Type TARGET[15872]; + +} PLIC_Type; + + +#define PLIC ((PLIC_Type *)PLIC_BASE_ADDR) + +/*============================================================================== + * PRCI: Power, Reset, Clock, Interrupt + */ +#define PRCI_BASE 0x44000000UL + +typedef struct +{ + volatile uint32_t MSIP[4095]; + volatile uint32_t reserved; + volatile uint64_t MTIMECMP[4095]; + volatile const uint64_t MTIME; +} PRCI_Type; + +#define PRCI ((PRCI_Type *)PRCI_BASE) + +/*============================================================================== + * The function PLIC_init() initializes the PLIC controller and enables the + * global external interrupt bit. + */ +static inline void PLIC_init(void) +{ + uint32_t inc; + unsigned long hart_id = read_csr(mhartid); + + /* Disable all interrupts for the current hart. */ + for(inc = 0; inc < ((PLIC_NUM_SOURCES + 32u) / 32u); ++inc) + { + PLIC->TARGET_ENABLES[hart_id].ENABLES[inc] = 0; + } + + /* Set priorities to zero. */ + /* Should this really be done??? Calling PLIC_init() on one hart will cause + * the priorities previously set by other harts to be messed up. */ + for(inc = 0; inc < PLIC_NUM_SOURCES; ++inc) + { + PLIC->SOURCE_PRIORITY[inc] = 0; + } + + /* Set the threshold to zero. */ + PLIC->TARGET[hart_id].PRIORITY_THRESHOLD = 0; + + /* Enable machine external interrupts. */ + set_csr(mie, MIP_MEIP); +} + +/*============================================================================== + * The function PLIC_EnableIRQ() enables the external interrupt for the interrupt + * number indicated by the parameter IRQn. + */ +static inline void PLIC_EnableIRQ(IRQn_Type IRQn) +{ + unsigned long hart_id = read_csr(mhartid); + uint32_t current = PLIC->TARGET_ENABLES[hart_id].ENABLES[IRQn / 32]; + current |= (uint32_t)1 << (IRQn % 32); + PLIC->TARGET_ENABLES[hart_id].ENABLES[IRQn / 32] = current; +} + +/*============================================================================== + * The function PLIC_DisableIRQ() disables the external interrupt for the interrupt + * number indicated by the parameter IRQn. + + * NOTE: + * This function can be used to disable the external interrupt from outside + * external interrupt handler function. + * This function MUST NOT be used from within the External Interrupt handler. + * If you wish to disable the external interrupt while the interrupt handler + * for that external interrupt is executing then you must use the return value + * EXT_IRQ_DISABLE to return from the extern interrupt handler. + */ +static inline void PLIC_DisableIRQ(IRQn_Type IRQn) +{ + unsigned long hart_id = read_csr(mhartid); + uint32_t current = PLIC->TARGET_ENABLES[hart_id].ENABLES[IRQn / 32]; + + current &= ~((uint32_t)1 << (IRQn % 32)); + + PLIC->TARGET_ENABLES[hart_id].ENABLES[IRQn / 32] = current; +} + +/*============================================================================== + * The function PLIC_SetPriority() sets the priority for the external interrupt + * for the interrupt number indicated by the parameter IRQn. + */ +static inline void PLIC_SetPriority(IRQn_Type IRQn, uint32_t priority) +{ + PLIC->SOURCE_PRIORITY[IRQn] = priority; +} + +/*============================================================================== + * The function PLIC_GetPriority() returns the priority for the external interrupt + * for the interrupt number indicated by the parameter IRQn. + */ +static inline uint32_t PLIC_GetPriority(IRQn_Type IRQn) +{ + return PLIC->SOURCE_PRIORITY[IRQn]; +} + +/*============================================================================== + * The function PLIC_ClaimIRQ() claims the interrupt from the PLIC controller. + */ +static inline uint32_t PLIC_ClaimIRQ(void) +{ + unsigned long hart_id = read_csr(mhartid); + + return PLIC->TARGET[hart_id].CLAIM_COMPLETE; +} + +/*============================================================================== + * The function PLIC_CompleteIRQ() indicates to the PLIC controller the interrupt + * is processed and claim is complete. + */ +static inline void PLIC_CompleteIRQ(uint32_t source) +{ + unsigned long hart_id = read_csr(mhartid); + + PLIC->TARGET[hart_id].CLAIM_COMPLETE = source; +} + +/*============================================================================== + * The function raise_soft_interrupt() raises a synchronous software interrupt by + * writing into the MSIP register. + */ +static inline void raise_soft_interrupt() +{ + unsigned long hart_id = read_csr(mhartid); + + /*You need to make sure that the global interrupt is enabled*/ + set_csr(mie, MIP_MSIP); /*Enable software interrupt bit */ + PRCI->MSIP[hart_id] = 0x01; /*raise soft interrupt for hart0*/ +} + +/*============================================================================== + * The function clear_soft_interrupt() clears a synchronous software interrupt by + * clearing the MSIP register. + */ +static inline void clear_soft_interrupt() +{ + unsigned long hart_id = read_csr(mhartid); + PRCI->MSIP[hart_id] = 0x00; /*clear soft interrupt for hart0*/ +} + +#ifdef __cplusplus +} +#endif + +#endif /* RISCV_PLIC_H */ diff --git a/FreeRTOS/Demo/RISC-V_IGLOO2_Creative_SoftConsole/riscv_hal/sample_hw_platform.h b/FreeRTOS/Demo/RISC-V_IGLOO2_Creative_SoftConsole/riscv_hal/sample_hw_platform.h new file mode 100644 index 000000000..2990bd0c0 --- /dev/null +++ b/FreeRTOS/Demo/RISC-V_IGLOO2_Creative_SoftConsole/riscv_hal/sample_hw_platform.h @@ -0,0 +1,120 @@ +/******************************************************************************* + * (c) Copyright 2016-2018 Microsemi Corporation. All rights reserved. + * + * Platform definitions + * Version based on requirements of RISCV-HAL + * + * SVN $Revision: 9946 $ + * SVN $Date: 2018-04-30 20:26:55 +0530 (Mon, 30 Apr 2018) $ + */ + /*=========================================================================*//** + @mainpage Sample file detailing how hw_platform.h should be constructed for + the Mi-V processors. + + @section intro_sec Introduction + The hw_platform.h is to be located in the project root directory. + Currently this file must be hand crafted when using the Mi-V Soft Processor. + + You can use this file as sample. + Rename this file from sample_hw_platform.h to hw_platform.h and store it in + the root folder of your project. Then customize it per your HW design. + + @section driver_configuration Project configuration Instructions + 1. Change SYS_CLK_FREQ define to frequency of Mi-V Soft processor clock + 2 Add all other core BASE addresses + 3. Add peripheral Core Interrupt to Mi-V Soft processor interrupt mappings + 4. Define MSCC_STDIO_UART_BASE_ADDR if you want a CoreUARTapb mapped to STDIO +*//*=========================================================================*/ + +#ifndef HW_PLATFORM_H +#define HW_PLATFORM_H + +/***************************************************************************//** + * Soft-processor clock definition + * This is the only clock brought over from the Mi-V Soft processor Libero design. + */ +#ifndef SYS_CLK_FREQ +#define SYS_CLK_FREQ 83000000UL +#endif + + +/***************************************************************************//** + * Non-memory Peripheral base addresses + * Format of define is: + * __BASE_ADDR + */ +#define COREUARTAPB0_BASE_ADDR 0x70001000UL +#define COREGPIO_IN_BASE_ADDR 0x70002000UL +#define CORETIMER0_BASE_ADDR 0x70003000UL +#define CORETIMER1_BASE_ADDR 0x70004000UL +#define COREGPIO_OUT_BASE_ADDR 0x70005000UL +#define FLASH_CORE_SPI_BASE 0x70006000UL +#define CORE16550_BASE_ADDR 0x70007000UL + +/***************************************************************************//** + * Peripheral Interrupts are mapped to the corresponding Mi-V Soft processor + * interrupt from the Libero design. + * There can be up to 31 external interrupts (IRQ[30:0] pins) on the Mi-V Soft + * processor.The Mi-V Soft processor external interrupts are defined in the + * riscv_plic.h + * These are of the form + * typedef enum +{ + NoInterrupt_IRQn = 0, + External_1_IRQn = 1, + External_2_IRQn = 2, + . + . + . + External_31_IRQn = 31 +} IRQn_Type; + + The interrupt 0 on RISC-V processor is not used. The pin IRQ[0] should map to + External_1_IRQn likewise IRQ[30] should map to External_31_IRQn + * Format of define is: + * __ + */ + +#define TIMER0_IRQn External_30_IRQn +#define TIMER1_IRQn External_31_IRQn + +/**************************************************************************** + * Baud value to achieve a 115200 baud rate with a 83MHz system clock. + * This value is calculated using the following equation: + * BAUD_VALUE = (CLOCK / (16 * BAUD_RATE)) - 1 + *****************************************************************************/ +#define BAUD_VALUE_115200 (SYS_CLK_FREQ / (16 * 115200)) - 1 + +/***************************************************************************//** + * User edit section- Edit sections below if required + */ +#ifdef MSCC_STDIO_THRU_CORE_UART_APB +/* + * A base address mapping for the STDIO printf/scanf mapping to CortUARTapb + * must be provided if it is being used + * + * e.g. #define MSCC_STDIO_UART_BASE_ADDR COREUARTAPB1_BASE_ADDR + */ +#define MSCC_STDIO_UART_BASE_ADDR COREUARTAPB0_BASE_ADDR + +#ifndef MSCC_STDIO_UART_BASE_ADDR +#error MSCC_STDIO_UART_BASE_ADDR not defined- e.g. #define MSCC_STDIO_UART_BASE_ADDR COREUARTAPB1_BASE_ADDR +#endif + +#ifndef MSCC_STDIO_BAUD_VALUE +/* + * The MSCC_STDIO_BAUD_VALUE define should be set in your project's settings to + * specify the baud value used by the standard output CoreUARTapb instance for + * generating the UART's baud rate if you want a different baud rate from the + * default of 115200 baud + */ +#define MSCC_STDIO_BAUD_VALUE 115200 +#endif /*MSCC_STDIO_BAUD_VALUE*/ + +#endif /* end of MSCC_STDIO_THRU_CORE_UART_APB */ +/******************************************************************************* + * End of user edit section + */ +#endif /* HW_PLATFORM_H */ + + diff --git a/FreeRTOS/Demo/RISC-V_IGLOO2_Creative_SoftConsole/riscv_hal/syscall.c b/FreeRTOS/Demo/RISC-V_IGLOO2_Creative_SoftConsole/riscv_hal/syscall.c new file mode 100644 index 000000000..4c99f8086 --- /dev/null +++ b/FreeRTOS/Demo/RISC-V_IGLOO2_Creative_SoftConsole/riscv_hal/syscall.c @@ -0,0 +1,266 @@ +/******************************************************************************* + * (c) Copyright 2016-2018 Microsemi SoC Products Group. All rights reserved. + * + * @file syscall.c + * @author Microsemi SoC Products Group + * @brief Stubs for system calls. + * + * SVN $Revision: 9661 $ + * SVN $Date: 2018-01-15 16:13:33 +0530 (Mon, 15 Jan 2018) $ + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "encoding.h" + +#ifdef MSCC_STDIO_THRU_CORE_UART_APB + +#include "core_uart_apb.h" +#include "hw_platform.h" + +#endif /*MSCC_STDIO_THRU_CORE_UART_APB*/ + +#ifdef __cplusplus +extern "C" { +#endif + +#ifdef MSCC_STDIO_THRU_CORE_UART_APB + +/*------------------------------------------------------------------------------ + * CoreUARTapb instance data for the CoreUARTapb instance used for standard + * output. + */ +static UART_instance_t g_stdio_uart; + +/*============================================================================== + * Flag used to indicate if the UART driver needs to be initialized. + */ +static int g_stdio_uart_init_done = 0; +#endif /*MSCC_STDIO_THRU_CORE_UART_APB*/ + +#undef errno +int errno; + +char *__env[1] = { 0 }; +char **environ = __env; + +void write_hex(int fd, uint32_t hex) +{ + uint8_t ii; + uint8_t jj; + char towrite; + uint8_t digit; + + write( fd , "0x", 2 ); + + for (ii = 8 ; ii > 0; ii--) + { + jj = ii-1; + digit = ((hex & (0xF << (jj*4))) >> (jj*4)); + towrite = digit < 0xA ? ('0' + digit) : ('A' + (digit - 0xA)); + write( fd, &towrite, 1); + } +} + + +void _exit(int code) +{ +#ifdef MSCC_STDIO_THRU_CORE_UART_APB + const char * message = "\nProgam has exited with code:"; + + write(STDERR_FILENO, message, strlen(message)); + write_hex(STDERR_FILENO, code); +#endif + + while (1); +} + +void *_sbrk(ptrdiff_t incr) +{ + extern char _end[]; + extern char _heap_end[]; + static char *curbrk = _end; + + if ((curbrk + incr < _end) || (curbrk + incr > _heap_end)) + { + return ((char *) - 1); + } + + curbrk += incr; + return curbrk - incr; +} + +int _isatty(int fd) +{ + if (fd == STDOUT_FILENO || fd == STDERR_FILENO) + { + return 1; + } + + errno = EBADF; + return 0; +} + +static int stub(int err) +{ + errno = err; + return -1; +} + +int _open(const char* name, int flags, int mode) +{ + return stub(ENOENT); +} + +int _openat(int dirfd, const char* name, int flags, int mode) +{ + return stub(ENOENT); +} + +int _close(int fd) +{ + return stub(EBADF); +} + +int _execve(const char* name, char* const argv[], char* const env[]) +{ + return stub(ENOMEM); +} + +int _fork() +{ + return stub(EAGAIN); +} + +int _fstat(int fd, struct stat *st) +{ + if (isatty(fd)) + { + st->st_mode = S_IFCHR; + return 0; + } + + return stub(EBADF); +} + +int _getpid() +{ + return 1; +} + +int _kill(int pid, int sig) +{ + return stub(EINVAL); +} + +int _link(const char *old_name, const char *new_name) +{ + return stub(EMLINK); +} + +off_t _lseek(int fd, off_t ptr, int dir) +{ + if (_isatty(fd)) + { + return 0; + } + + return stub(EBADF); +} + +ssize_t _read(int fd, void* ptr, size_t len) +{ +#ifdef MSCC_STDIO_THRU_CORE_UART_APB + if (_isatty(fd)) + { + /*-------------------------------------------------------------------------- + * Initialize the UART driver if it is the first time this function is + * called. + */ + if ( !g_stdio_uart_init_done ) + { + /****************************************************************************** + * Baud value: + * This value is calculated using the following equation: + * BAUD_VALUE = (CLOCK / (16 * BAUD_RATE)) - 1 + *****************************************************************************/ + UART_init( &g_stdio_uart, MSCC_STDIO_UART_BASE_ADDR, ((SYS_CLK_FREQ/(16 * MSCC_STDIO_BAUD_VALUE))-1), (DATA_8_BITS | NO_PARITY)); + g_stdio_uart_init_done = 1; + } + + return UART_get_rx(&g_stdio_uart, (uint8_t*) ptr, len); + } +#endif + + return stub(EBADF); +} + +int _stat(const char* file, struct stat* st) +{ + return stub(EACCES); +} + +clock_t _times(struct tms* buf) +{ + return stub(EACCES); +} + +int _unlink(const char* name) +{ + return stub(ENOENT); +} + +int _wait(int* status) +{ + return stub(ECHILD); +} + +ssize_t _write(int fd, const void* ptr, size_t len) +{ + +#ifdef MSCC_STDIO_THRU_CORE_UART_APB + const uint8_t * current = (const uint8_t *) ptr; + size_t jj; + + if (_isatty(fd)) + { + /*-------------------------------------------------------------------------- + * Initialize the UART driver if it is the first time this function is + * called. + */ + if ( !g_stdio_uart_init_done ) + { + /****************************************************************************** + * Baud value: + * This value is calculated using the following equation: + * BAUD_VALUE = (CLOCK / (16 * BAUD_RATE)) - 1 + *****************************************************************************/ + UART_init( &g_stdio_uart, MSCC_STDIO_UART_BASE_ADDR, ((SYS_CLK_FREQ/(16 * MSCC_STDIO_BAUD_VALUE))-1), (DATA_8_BITS | NO_PARITY)); + g_stdio_uart_init_done = 1; + } + + for (jj = 0; jj < len; jj++) + { + UART_send(&g_stdio_uart, current + jj, 1); + if (current[jj] == '\n') + { + UART_send(&g_stdio_uart, (const uint8_t *)"\r", 1); + } + } + return len; + } +#endif + + return stub(EBADF); +} + +#ifdef __cplusplus +} +#endif -- 2.39.5