Add files via upload

This commit is contained in:
NawfalMotii79
2026-03-19 01:21:46 +00:00
committed by GitHub
parent b33a9bcd37
commit b17e29e810
92 changed files with 24741 additions and 0 deletions
@@ -0,0 +1,255 @@
#MicroXplorer Configuration settings - do not modify
CAD.formats=
CAD.pinconfig=
CAD.provider=
File.Version=6
GPIO.groupedBy=Group By Peripherals
I2C1.IPParameters=Timing
I2C1.Timing=0x00707CBB
KeepUserPlacement=false
Mcu.CPN=STM32F746ZGT6
Mcu.Family=STM32F7
Mcu.IP0=CORTEX_M7
Mcu.IP1=I2C1
Mcu.IP2=NVIC
Mcu.IP3=RCC
Mcu.IP4=SPI1
Mcu.IP5=SYS
Mcu.IP6=TIM1
Mcu.IP7=USART2
Mcu.IPNb=8
Mcu.Name=STM32F746ZGTx
Mcu.Package=LQFP144
Mcu.Pin0=PC14/OSC32_IN
Mcu.Pin1=PC15/OSC32_OUT
Mcu.Pin10=PA5
Mcu.Pin11=PA6
Mcu.Pin12=PA7
Mcu.Pin13=PC4
Mcu.Pin14=PC5
Mcu.Pin15=PB14
Mcu.Pin16=PB15
Mcu.Pin17=PD10
Mcu.Pin18=PD11
Mcu.Pin19=PD12
Mcu.Pin2=PH0/OSC_IN
Mcu.Pin20=PD13
Mcu.Pin21=PC6
Mcu.Pin22=PC7
Mcu.Pin23=PA8
Mcu.Pin24=PA9
Mcu.Pin25=PA10
Mcu.Pin26=PA11
Mcu.Pin27=PA13
Mcu.Pin28=PA14
Mcu.Pin29=PD0
Mcu.Pin3=PH1/OSC_OUT
Mcu.Pin30=PD1
Mcu.Pin31=PD2
Mcu.Pin32=PD3
Mcu.Pin33=PB4
Mcu.Pin34=PB5
Mcu.Pin35=PB6
Mcu.Pin36=PB7
Mcu.Pin37=VP_SYS_VS_Systick
Mcu.Pin38=VP_TIM1_VS_ClockSourceINT
Mcu.Pin4=PC0
Mcu.Pin5=PC1
Mcu.Pin6=PC2
Mcu.Pin7=PC3
Mcu.Pin8=PA2
Mcu.Pin9=PA3
Mcu.PinsNb=39
Mcu.ThirdPartyNb=0
Mcu.UserConstants=
Mcu.UserName=STM32F746ZGTx
MxCube.Version=6.8.1
MxDb.Version=DB.6.0.81
NVIC.BusFault_IRQn=true\:0\:0\:false\:false\:true\:false\:false\:false
NVIC.DebugMonitor_IRQn=true\:0\:0\:false\:false\:true\:false\:false\:false
NVIC.ForceEnableDMAVector=true
NVIC.HardFault_IRQn=true\:0\:0\:false\:false\:true\:false\:false\:false
NVIC.MemoryManagement_IRQn=true\:0\:0\:false\:false\:true\:false\:false\:false
NVIC.NonMaskableInt_IRQn=true\:0\:0\:false\:false\:true\:false\:false\:false
NVIC.PendSV_IRQn=true\:0\:0\:false\:false\:true\:false\:false\:false
NVIC.PriorityGroup=NVIC_PRIORITYGROUP_4
NVIC.SVCall_IRQn=true\:0\:0\:false\:false\:true\:false\:false\:false
NVIC.SysTick_IRQn=true\:15\:0\:false\:false\:true\:false\:true\:false
NVIC.UsageFault_IRQn=true\:0\:0\:false\:false\:true\:false\:false\:false
PA10.Locked=true
PA10.Signal=GPIO_Output
PA11.Locked=true
PA11.Signal=GPIO_Output
PA13.Mode=Serial_Wire
PA13.Signal=SYS_JTMS-SWDIO
PA14.Mode=Serial_Wire
PA14.Signal=SYS_JTCK-SWCLK
PA2.Mode=Asynchronous
PA2.Signal=USART2_TX
PA3.Mode=Asynchronous
PA3.Signal=USART2_RX
PA5.Mode=Full_Duplex_Master
PA5.Signal=SPI1_SCK
PA6.Mode=Full_Duplex_Master
PA6.Signal=SPI1_MISO
PA7.Mode=Full_Duplex_Master
PA7.Signal=SPI1_MOSI
PA8.Locked=true
PA8.Signal=GPIO_Output
PA9.Locked=true
PA9.Signal=GPIO_Output
PB14.Locked=true
PB14.Signal=GPIO_Output
PB15.Locked=true
PB15.Signal=GPIO_Output
PB4.Locked=true
PB4.Signal=GPIO_Output
PB5.Locked=true
PB5.Signal=GPIO_Output
PB6.Mode=I2C
PB6.Signal=I2C1_SCL
PB7.Mode=I2C
PB7.Signal=I2C1_SDA
PC0.Locked=true
PC0.Signal=GPIO_Input
PC1.Locked=true
PC1.Signal=GPIO_Input
PC14/OSC32_IN.Mode=LSE-External-Oscillator
PC14/OSC32_IN.Signal=RCC_OSC32_IN
PC15/OSC32_OUT.Mode=LSE-External-Oscillator
PC15/OSC32_OUT.Signal=RCC_OSC32_OUT
PC2.Locked=true
PC2.Signal=GPIO_Input
PC3.Locked=true
PC3.Signal=GPIO_Input
PC4.Locked=true
PC4.Signal=GPIO_Output
PC5.Locked=true
PC5.Signal=GPIO_Output
PC6.Locked=true
PC6.Signal=GPIO_Output
PC7.Locked=true
PC7.Signal=GPIO_Output
PD0.Locked=true
PD0.Signal=GPIO_Output
PD1.Locked=true
PD1.Signal=GPIO_Output
PD10.Locked=true
PD10.Signal=GPIO_Output
PD11.Locked=true
PD11.Signal=GPIO_Output
PD12.Locked=true
PD12.Signal=GPIO_Output
PD13.Locked=true
PD13.Signal=GPIO_Output
PD2.Locked=true
PD2.Signal=GPIO_Output
PD3.Locked=true
PD3.Signal=GPIO_Output
PH0/OSC_IN.Mode=HSE-External-Oscillator
PH0/OSC_IN.Signal=RCC_OSC_IN
PH1/OSC_OUT.Mode=HSE-External-Oscillator
PH1/OSC_OUT.Signal=RCC_OSC_OUT
PinOutPanel.RotationAngle=0
ProjectManager.AskForMigrate=true
ProjectManager.BackupPrevious=false
ProjectManager.CompilerOptimize=6
ProjectManager.ComputerToolchain=false
ProjectManager.CoupleFile=false
ProjectManager.CustomerFirmwarePackage=
ProjectManager.DefaultFWLocation=true
ProjectManager.DeletePrevious=true
ProjectManager.DeviceId=STM32F746ZGTx
ProjectManager.FirmwarePackage=STM32Cube FW_F7 V1.17.2
ProjectManager.FreePins=false
ProjectManager.HalAssertFull=false
ProjectManager.HeapSize=0x200
ProjectManager.KeepUserCode=true
ProjectManager.LastFirmware=true
ProjectManager.LibraryCopy=1
ProjectManager.MainLocation=Core/Src
ProjectManager.NoMain=false
ProjectManager.PreviousToolchain=STM32CubeIDE
ProjectManager.ProjectBuild=false
ProjectManager.ProjectFileName=RADAR_C_Cpp.ioc
ProjectManager.ProjectName=RADAR_C_Cpp
ProjectManager.ProjectStructure=
ProjectManager.RegisterCallBack=
ProjectManager.StackSize=0x400
ProjectManager.TargetToolchain=STM32CubeIDE
ProjectManager.ToolChainLocation=
ProjectManager.UnderRoot=true
ProjectManager.functionlistsort=1-SystemClock_Config-RCC-false-HAL-false,2-MX_GPIO_Init-GPIO-false-HAL-true,3-MX_I2C1_Init-I2C1-false-HAL-true,4-MX_SPI1_Init-SPI1-false-HAL-true,5-MX_TIM1_Init-TIM1-false-HAL-true,6-MX_USART2_UART_Init-USART2-false-HAL-true,0-MX_CORTEX_M7_Init-CORTEX_M7-false-HAL-true
RCC.AHBFreq_Value=64000000
RCC.APB1CLKDivider=RCC_HCLK_DIV2
RCC.APB1Freq_Value=32000000
RCC.APB1TimFreq_Value=64000000
RCC.APB2Freq_Value=64000000
RCC.APB2TimFreq_Value=64000000
RCC.CECFreq_Value=32786.88524590164
RCC.CortexFreq_Value=64000000
RCC.EthernetFreq_Value=64000000
RCC.FCLKCortexFreq_Value=64000000
RCC.FamilyName=M
RCC.HCLKFreq_Value=64000000
RCC.HSE_VALUE=8000000
RCC.HSI_VALUE=16000000
RCC.I2C1Freq_Value=32000000
RCC.I2C2Freq_Value=32000000
RCC.I2C3Freq_Value=32000000
RCC.I2C4Freq_Value=32000000
RCC.I2SFreq_Value=192000000
RCC.IPParameters=AHBFreq_Value,APB1CLKDivider,APB1Freq_Value,APB1TimFreq_Value,APB2Freq_Value,APB2TimFreq_Value,CECFreq_Value,CortexFreq_Value,EthernetFreq_Value,FCLKCortexFreq_Value,FamilyName,HCLKFreq_Value,HSE_VALUE,HSI_VALUE,I2C1Freq_Value,I2C2Freq_Value,I2C3Freq_Value,I2C4Freq_Value,I2SFreq_Value,LCDTFToutputFreq_Value,LPTIM1Freq_Value,LSI_VALUE,MCO2PinFreq_Value,PLLCLKFreq_Value,PLLI2SPCLKFreq_Value,PLLI2SQCLKFreq_Value,PLLI2SRCLKFreq_Value,PLLI2SRoutputFreq_Value,PLLM,PLLN,PLLQCLKFreq_Value,PLLQoutputFreq_Value,PLLSAIPCLKFreq_Value,PLLSAIQCLKFreq_Value,PLLSAIRCLKFreq_Value,PLLSAIoutputFreq_Value,PLLSourceVirtual,RNGFreq_Value,SAI1Freq_Value,SAI2Freq_Value,SDMMCFreq_Value,SPDIFRXFreq_Value,SYSCLKFreq_VALUE,SYSCLKSource,UART4Freq_Value,UART5Freq_Value,UART7Freq_Value,UART8Freq_Value,USART1Freq_Value,USART2Freq_Value,USART3Freq_Value,USART6Freq_Value,USBFreq_Value,VCOI2SOutputFreq_Value,VCOInputFreq_Value,VCOOutputFreq_Value,VCOSAIOutputFreq_Value
RCC.LCDTFToutputFreq_Value=96000000
RCC.LPTIM1Freq_Value=32000000
RCC.LSI_VALUE=32000
RCC.MCO2PinFreq_Value=64000000
RCC.PLLCLKFreq_Value=64000000
RCC.PLLI2SPCLKFreq_Value=192000000
RCC.PLLI2SQCLKFreq_Value=192000000
RCC.PLLI2SRCLKFreq_Value=192000000
RCC.PLLI2SRoutputFreq_Value=192000000
RCC.PLLM=4
RCC.PLLN=64
RCC.PLLQCLKFreq_Value=64000000
RCC.PLLQoutputFreq_Value=64000000
RCC.PLLSAIPCLKFreq_Value=192000000
RCC.PLLSAIQCLKFreq_Value=192000000
RCC.PLLSAIRCLKFreq_Value=192000000
RCC.PLLSAIoutputFreq_Value=192000000
RCC.PLLSourceVirtual=RCC_PLLSOURCE_HSE
RCC.RNGFreq_Value=64000000
RCC.SAI1Freq_Value=192000000
RCC.SAI2Freq_Value=192000000
RCC.SDMMCFreq_Value=64000000
RCC.SPDIFRXFreq_Value=192000000
RCC.SYSCLKFreq_VALUE=64000000
RCC.SYSCLKSource=RCC_SYSCLKSOURCE_PLLCLK
RCC.UART4Freq_Value=32000000
RCC.UART5Freq_Value=32000000
RCC.UART7Freq_Value=32000000
RCC.UART8Freq_Value=32000000
RCC.USART1Freq_Value=64000000
RCC.USART2Freq_Value=32000000
RCC.USART3Freq_Value=32000000
RCC.USART6Freq_Value=64000000
RCC.USBFreq_Value=64000000
RCC.VCOI2SOutputFreq_Value=384000000
RCC.VCOInputFreq_Value=2000000
RCC.VCOOutputFreq_Value=128000000
RCC.VCOSAIOutputFreq_Value=384000000
SPI1.BaudRatePrescaler=SPI_BAUDRATEPRESCALER_16
SPI1.CalculateBaudRate=4.0 MBits/s
SPI1.DataSize=SPI_DATASIZE_8BIT
SPI1.Direction=SPI_DIRECTION_2LINES
SPI1.IPParameters=VirtualType,Mode,Direction,CalculateBaudRate,BaudRatePrescaler,DataSize
SPI1.Mode=SPI_MODE_MASTER
SPI1.VirtualType=VM_MASTER
USART2.IPParameters=VirtualMode-Asynchronous
USART2.VirtualMode-Asynchronous=VM_ASYNC
VP_SYS_VS_Systick.Mode=SysTick
VP_SYS_VS_Systick.Signal=SYS_VS_Systick
VP_TIM1_VS_ClockSourceINT.Mode=Internal
VP_TIM1_VS_ClockSourceINT.Signal=TIM1_VS_ClockSourceINT
board=custom
isbadioc=false
@@ -0,0 +1,185 @@
/*
******************************************************************************
**
** @file : LinkerScript.ld
**
** @author : Auto-generated by STM32CubeIDE
**
** @brief : Linker script for STM32F746ZGTx Device from STM32F7 series
** 1024Kbytes FLASH
** 320Kbytes RAM
**
** Set heap size, stack size and stack location according
** to application requirements.
**
** Set memory bank area and size if external memory is used
**
** Target : STMicroelectronics STM32
**
** Distribution: The file is distributed as is, without any warranty
** of any kind.
**
******************************************************************************
** @attention
**
** Copyright (c) 2025 STMicroelectronics.
** All rights reserved.
**
** This software is licensed under terms that can be found in the LICENSE file
** in the root directory of this software component.
** If no LICENSE file comes with this software, it is provided AS-IS.
**
******************************************************************************
*/
/* Entry Point */
ENTRY(Reset_Handler)
/* Highest address of the user mode stack */
_estack = ORIGIN(RAM) + LENGTH(RAM); /* end of "RAM" Ram type memory */
_Min_Heap_Size = 0x200; /* required amount of heap */
_Min_Stack_Size = 0x400; /* required amount of stack */
/* Memories definition */
MEMORY
{
RAM (xrw) : ORIGIN = 0x20000000, LENGTH = 320K
FLASH (rx) : ORIGIN = 0x8000000, LENGTH = 1024K
}
/* Sections */
SECTIONS
{
/* The startup code into "FLASH" Rom type memory */
.isr_vector :
{
. = ALIGN(4);
KEEP(*(.isr_vector)) /* Startup code */
. = ALIGN(4);
} >FLASH
/* The program code and other data into "FLASH" Rom type memory */
.text :
{
. = ALIGN(4);
*(.text) /* .text sections (code) */
*(.text*) /* .text* sections (code) */
*(.glue_7) /* glue arm to thumb code */
*(.glue_7t) /* glue thumb to arm code */
*(.eh_frame)
KEEP (*(.init))
KEEP (*(.fini))
. = ALIGN(4);
_etext = .; /* define a global symbols at end of code */
} >FLASH
/* Constant data into "FLASH" Rom type memory */
.rodata :
{
. = ALIGN(4);
*(.rodata) /* .rodata sections (constants, strings, etc.) */
*(.rodata*) /* .rodata* sections (constants, strings, etc.) */
. = ALIGN(4);
} >FLASH
.ARM.extab : {
. = ALIGN(4);
*(.ARM.extab* .gnu.linkonce.armextab.*)
. = ALIGN(4);
} >FLASH
.ARM : {
. = ALIGN(4);
__exidx_start = .;
*(.ARM.exidx*)
__exidx_end = .;
. = ALIGN(4);
} >FLASH
.preinit_array :
{
. = ALIGN(4);
PROVIDE_HIDDEN (__preinit_array_start = .);
KEEP (*(.preinit_array*))
PROVIDE_HIDDEN (__preinit_array_end = .);
. = ALIGN(4);
} >FLASH
.init_array :
{
. = ALIGN(4);
PROVIDE_HIDDEN (__init_array_start = .);
KEEP (*(SORT(.init_array.*)))
KEEP (*(.init_array*))
PROVIDE_HIDDEN (__init_array_end = .);
. = ALIGN(4);
} >FLASH
.fini_array :
{
. = ALIGN(4);
PROVIDE_HIDDEN (__fini_array_start = .);
KEEP (*(SORT(.fini_array.*)))
KEEP (*(.fini_array*))
PROVIDE_HIDDEN (__fini_array_end = .);
. = ALIGN(4);
} >FLASH
/* Used by the startup to initialize data */
_sidata = LOADADDR(.data);
/* Initialized data sections into "RAM" Ram type memory */
.data :
{
. = ALIGN(4);
_sdata = .; /* create a global symbol at data start */
*(.data) /* .data sections */
*(.data*) /* .data* sections */
*(.RamFunc) /* .RamFunc sections */
*(.RamFunc*) /* .RamFunc* sections */
. = ALIGN(4);
_edata = .; /* define a global symbol at data end */
} >RAM AT> FLASH
/* Uninitialized data section into "RAM" Ram type memory */
. = ALIGN(4);
.bss :
{
/* This is used by the startup in order to initialize the .bss section */
_sbss = .; /* define a global symbol at bss start */
__bss_start__ = _sbss;
*(.bss)
*(.bss*)
*(COMMON)
. = ALIGN(4);
_ebss = .; /* define a global symbol at bss end */
__bss_end__ = _ebss;
} >RAM
/* User_heap_stack section, used to check that there is enough "RAM" Ram type memory left */
._user_heap_stack :
{
. = ALIGN(8);
PROVIDE ( end = . );
PROVIDE ( _end = . );
. = . + _Min_Heap_Size;
. = . + _Min_Stack_Size;
. = ALIGN(8);
} >RAM
/* Remove information from the compiler libraries */
/DISCARD/ :
{
libc.a ( * )
libm.a ( * )
libgcc.a ( * )
}
.ARM.attributes 0 : { *(.ARM.attributes) }
}
@@ -0,0 +1,185 @@
/*
******************************************************************************
**
** @file : LinkerScript.ld (debug in RAM dedicated)
**
** @author : Auto-generated by STM32CubeIDE
**
** @brief : Linker script for STM32F746ZGTx Device from STM32F7 series
** 1024Kbytes FLASH
** 320Kbytes RAM
**
** Set heap size, stack size and stack location according
** to application requirements.
**
** Set memory bank area and size if external memory is used
**
** Target : STMicroelectronics STM32
**
** Distribution: The file is distributed as is, without any warranty
** of any kind.
**
******************************************************************************
** @attention
**
** Copyright (c) 2025 STMicroelectronics.
** All rights reserved.
**
** This software is licensed under terms that can be found in the LICENSE file
** in the root directory of this software component.
** If no LICENSE file comes with this software, it is provided AS-IS.
**
******************************************************************************
*/
/* Entry Point */
ENTRY(Reset_Handler)
/* Highest address of the user mode stack */
_estack = ORIGIN(RAM) + LENGTH(RAM); /* end of "RAM" Ram type memory */
_Min_Heap_Size = 0x200; /* required amount of heap */
_Min_Stack_Size = 0x400; /* required amount of stack */
/* Memories definition */
MEMORY
{
RAM (xrw) : ORIGIN = 0x20000000, LENGTH = 320K
FLASH (rx) : ORIGIN = 0x8000000, LENGTH = 1024K
}
/* Sections */
SECTIONS
{
/* The startup code into "RAM" Ram type memory */
.isr_vector :
{
. = ALIGN(4);
KEEP(*(.isr_vector)) /* Startup code */
. = ALIGN(4);
} >RAM
/* The program code and other data into "RAM" Ram type memory */
.text :
{
. = ALIGN(4);
*(.text) /* .text sections (code) */
*(.text*) /* .text* sections (code) */
*(.glue_7) /* glue arm to thumb code */
*(.glue_7t) /* glue thumb to arm code */
*(.eh_frame)
*(.RamFunc) /* .RamFunc sections */
*(.RamFunc*) /* .RamFunc* sections */
KEEP (*(.init))
KEEP (*(.fini))
. = ALIGN(4);
_etext = .; /* define a global symbols at end of code */
} >RAM
/* Constant data into "RAM" Ram type memory */
.rodata :
{
. = ALIGN(4);
*(.rodata) /* .rodata sections (constants, strings, etc.) */
*(.rodata*) /* .rodata* sections (constants, strings, etc.) */
. = ALIGN(4);
} >RAM
.ARM.extab : {
. = ALIGN(4);
*(.ARM.extab* .gnu.linkonce.armextab.*)
. = ALIGN(4);
} >RAM
.ARM : {
. = ALIGN(4);
__exidx_start = .;
*(.ARM.exidx*)
__exidx_end = .;
. = ALIGN(4);
} >RAM
.preinit_array :
{
. = ALIGN(4);
PROVIDE_HIDDEN (__preinit_array_start = .);
KEEP (*(.preinit_array*))
PROVIDE_HIDDEN (__preinit_array_end = .);
. = ALIGN(4);
} >RAM
.init_array :
{
. = ALIGN(4);
PROVIDE_HIDDEN (__init_array_start = .);
KEEP (*(SORT(.init_array.*)))
KEEP (*(.init_array*))
PROVIDE_HIDDEN (__init_array_end = .);
. = ALIGN(4);
} >RAM
.fini_array :
{
. = ALIGN(4);
PROVIDE_HIDDEN (__fini_array_start = .);
KEEP (*(SORT(.fini_array.*)))
KEEP (*(.fini_array*))
PROVIDE_HIDDEN (__fini_array_end = .);
. = ALIGN(4);
} >RAM
/* Used by the startup to initialize data */
_sidata = LOADADDR(.data);
/* Initialized data sections into "RAM" Ram type memory */
.data :
{
. = ALIGN(4);
_sdata = .; /* create a global symbol at data start */
*(.data) /* .data sections */
*(.data*) /* .data* sections */
. = ALIGN(4);
_edata = .; /* define a global symbol at data end */
} >RAM
/* Uninitialized data section into "RAM" Ram type memory */
. = ALIGN(4);
.bss :
{
/* This is used by the startup in order to initialize the .bss section */
_sbss = .; /* define a global symbol at bss start */
__bss_start__ = _sbss;
*(.bss)
*(.bss*)
*(COMMON)
. = ALIGN(4);
_ebss = .; /* define a global symbol at bss end */
__bss_end__ = _ebss;
} >RAM
/* User_heap_stack section, used to check that there is enough "RAM" Ram type memory left */
._user_heap_stack :
{
. = ALIGN(8);
PROVIDE ( end = . );
PROVIDE ( _end = . );
. = . + _Min_Heap_Size;
. = . + _Min_Stack_Size;
. = ALIGN(8);
} >RAM
/* Remove information from the compiler libraries */
/DISCARD/ :
{
libc.a ( * )
libm.a ( * )
libgcc.a ( * )
}
.ARM.attributes 0 : { *(.ARM.attributes) }
}
@@ -0,0 +1,693 @@
/**
* MIT License
*
* Copyright (c) 2020 Jimmy Pentz
*
* Reach me at: github.com/jgpentz, jpentz1(at)gmail.com
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sells
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
/* ADAR1000 4-Channel, X Band and Ku Band Beamformer */
// ----------------------------------------------------------------------------
// Includes
// ----------------------------------------------------------------------------
#include "main.h"
#include "stm32f7xx_hal.h"
#include "stm32f7xx_hal_spi.h"
#include "stm32f7xx_hal_gpio.h"
#include "adar1000.h"
// ----------------------------------------------------------------------------
// Preprocessor Definitions and Constants
// ----------------------------------------------------------------------------
// VM_GAIN is 15 dB of gain in 128 steps. ~0.12 dB per step.
// A 15 dB attenuator can be applied on top of these values.
const uint8_t VM_GAIN[128] = {
0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F,
0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f,
0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f,
0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f,
0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, 0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f,
0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58, 0x59, 0x5a, 0x5b, 0x5c, 0x5d, 0x5e, 0x5f,
0x60, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e, 0x6f,
0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, 0x79, 0x7a, 0x7b, 0x7c, 0x7d, 0x7e, 0x7f,
};
// VM_I and VM_Q are the settings for the vector modulator. 128 steps in 360 degrees. ~2.813 degrees per step.
const uint8_t VM_I[128] = {
0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3E, 0x3E, 0x3D, 0x3D, 0x3C, 0x3C, 0x3B, 0x3A, 0x39, 0x38, 0x37,
0x36, 0x35, 0x34, 0x33, 0x32, 0x30, 0x2F, 0x2E, 0x2C, 0x2B, 0x2A, 0x28, 0x27, 0x25, 0x24, 0x22,
0x21, 0x01, 0x03, 0x04, 0x06, 0x07, 0x08, 0x0A, 0x0B, 0x0D, 0x0E, 0x0F, 0x11, 0x12, 0x13, 0x14,
0x16, 0x17, 0x18, 0x19, 0x19, 0x1A, 0x1B, 0x1C, 0x1C, 0x1D, 0x1E, 0x1E, 0x1E, 0x1F, 0x1F, 0x1F,
0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1E, 0x1E, 0x1D, 0x1D, 0x1C, 0x1C, 0x1B, 0x1A, 0x19, 0x18, 0x17,
0x16, 0x15, 0x14, 0x13, 0x12, 0x10, 0x0F, 0x0E, 0x0C, 0x0B, 0x0A, 0x08, 0x07, 0x05, 0x04, 0x02,
0x01, 0x21, 0x23, 0x24, 0x26, 0x27, 0x28, 0x2A, 0x2B, 0x2D, 0x2E, 0x2F, 0x31, 0x32, 0x33, 0x34,
0x36, 0x37, 0x38, 0x39, 0x39, 0x3A, 0x3B, 0x3C, 0x3C, 0x3D, 0x3E, 0x3E, 0x3E, 0x3F, 0x3F, 0x3F,
};
const uint8_t VM_Q[128] = {
0x20, 0x21, 0x23, 0x24, 0x26, 0x27, 0x28, 0x2A, 0x2B, 0x2D, 0x2E, 0x2F, 0x30, 0x31, 0x33, 0x34,
0x35, 0x36, 0x37, 0x38, 0x38, 0x39, 0x3A, 0x3A, 0x3B, 0x3C, 0x3C, 0x3C, 0x3D, 0x3D, 0x3D, 0x3D,
0x3D, 0x3D, 0x3D, 0x3D, 0x3D, 0x3C, 0x3C, 0x3C, 0x3B, 0x3A, 0x3A, 0x39, 0x38, 0x38, 0x37, 0x36,
0x35, 0x34, 0x33, 0x31, 0x30, 0x2F, 0x2E, 0x2D, 0x2B, 0x2A, 0x28, 0x27, 0x26, 0x24, 0x23, 0x21,
0x20, 0x01, 0x03, 0x04, 0x06, 0x07, 0x08, 0x0A, 0x0B, 0x0D, 0x0E, 0x0F, 0x10, 0x11, 0x13, 0x14,
0x15, 0x16, 0x17, 0x18, 0x18, 0x19, 0x1A, 0x1A, 0x1B, 0x1C, 0x1C, 0x1C, 0x1D, 0x1D, 0x1D, 0x1D,
0x1D, 0x1D, 0x1D, 0x1D, 0x1D, 0x1C, 0x1C, 0x1C, 0x1B, 0x1A, 0x1A, 0x19, 0x18, 0x18, 0x17, 0x16,
0x15, 0x14, 0x13, 0x11, 0x10, 0x0F, 0x0E, 0x0D, 0x0B, 0x0A, 0x08, 0x07, 0x06, 0x04, 0x03, 0x01,
};
// ----------------------------------------------------------------------------
// Function Definitions
// ----------------------------------------------------------------------------
/**
* @brief Initialize the ADC on the ADAR by setting the ADC with a 2 MHz clk,
* and then enable it.
*
* @param p_adar[in] Adar pointer Which specifies the device and what function
* to use for SPI transfer.
* @param broadcast Send the message as a broadcast to all ADARs in the SPI chain
* if this set to BROADCAST_ON.
*
* @warning This is setup to only read temperature sensor data, not the power detectors.
*/
void Adar_AdcInit(const AdarDevice * p_adar, uint8_t broadcast)
{
uint8_t data;
data = ADAR1000_ADC_2MHZ_CLK | ADAR1000_ADC_EN;
Adar_Write(p_adar, REG_ADC_CONTROL, data, broadcast);
}
/**
* @brief Read a byte of data from the ADAR.
*
* @param p_adar[in] Adar pointer Which specifies the device and what function
* to use for SPI transfer.
* @param broadcast Send the message as a broadcast to all ADARs in the SPI chain
* if this set to BROADCAST_ON.
*
* @return Returns a byte of data that has been converted from the temperature sensor.
*
* @warning This is setup to only read temperature sensor data, not the power detectors.
*/
uint8_t Adar_AdcRead(const AdarDevice * p_adar, uint8_t broadcast)
{
uint8_t data;
// Start the ADC conversion
Adar_Write(p_adar, REG_ADC_CONTROL, ADAR1000_ADC_ST_CONV, broadcast);
// This is blocking for now... wait until data is converted, then read it
while (!(Adar_Read(p_adar, REG_ADC_CONTROL) & 0x01))
{
}
data = Adar_Read(p_adar, REG_ADC_OUT);
return(data);
}
/**
* @brief Requests the device info from a specific ADAR and stores it in the
* provided AdarDeviceInfo struct.
*
* @param p_adar[in] Adar pointer Which specifies the device and what function
* to use for SPI transfer.
* @param info[out] Struct that contains the device info fields.
*
* @return Returns ADAR_ERROR_NOERROR if information was successfully received and stored in the struct.
*/
uint8_t Adar_GetDeviceInfo(const AdarDevice * p_adar, AdarDeviceInfo * info)
{
*((uint8_t *)info) = Adar_Read(p_adar, 0x002);
info->chip_type = Adar_Read(p_adar, 0x003);
info->product_id = ((uint16_t)Adar_Read(p_adar, 0x004)) << 8;
info->product_id |= ((uint16_t)Adar_Read(p_adar, 0x005)) & 0x00ff;
info->scratchpad = Adar_Read(p_adar, 0x00A);
info->spi_rev = Adar_Read(p_adar, 0x00B);
info->vendor_id = ((uint16_t)Adar_Read(p_adar, 0x00C)) << 8;
info->vendor_id |= ((uint16_t)Adar_Read(p_adar, 0x00D)) & 0x00ff;
info->rev_id = Adar_Read(p_adar, 0x045);
return(ADAR_ERROR_NOERROR);
}
/**
* @brief Read the data that is stored in a single ADAR register.
*
* @param p_adar[in] Adar pointer Which specifies the device and what function
* to use for SPI transfer.
* @param mem_addr Memory address of the register you wish to read from.
*
* @return Returns the byte of data that is stored in the desired register.
*
* @warning This function will clear ADDR_ASCN bits.
* @warning The ADAR does not allow for block reads.
*/
uint8_t Adar_Read(const AdarDevice * p_adar, uint32_t mem_addr)
{
uint8_t instruction[3];
// Set SDO active
Adar_Write(p_adar, REG_INTERFACE_CONFIG_A, INTERFACE_CONFIG_A_SDO_ACTIVE, 0);
instruction[0] = 0x80 | ((p_adar->dev_addr & 0x03) << 5);
instruction[0] |= ((0xff00 & mem_addr) >> 8);
instruction[1] = (0xff & mem_addr);
instruction[2] = 0x00;
p_adar->Transfer(instruction, p_adar->p_rx_buffer, ADAR1000_RD_SIZE);
// Set SDO Inactive
Adar_Write(p_adar, REG_INTERFACE_CONFIG_A, 0, 0);
return(p_adar->p_rx_buffer[2]);
}
/**
* @brief Block memory write to an ADAR device.
*
* @pre ADDR_ASCN bits in register zero must be set!
*
* @param p_adar[in] Adar pointer Which specifies the device and what function
* to use for SPI transfer.
* @param mem_addr Memory address of the register you wish to read from.
* @param p_data Pointer to block of data to transfer (must have two unused bytes preceding the data for instruction).
* @param size Size of data in bytes, including the two additional leading bytes.
*
* @warning First two bytes of data will be corrupted if you do not provide two unused leading bytes!
*/
void Adar_ReadBlock(const AdarDevice * p_adar, uint16_t mem_addr, uint8_t * p_data, uint32_t size)
{
// Set SDO active
Adar_Write(p_adar, REG_INTERFACE_CONFIG_A, INTERFACE_CONFIG_A_SDO_ACTIVE | INTERFACE_CONFIG_A_ADDR_ASCN, 0);
// Prepare command
p_data[0] = 0x80 | ((p_adar->dev_addr & 0x03) << 5);
p_data[0] |= ((mem_addr) >> 8) & 0x1F;
p_data[1] = (0xFF & mem_addr);
// Start the transfer
p_adar->Transfer(p_data, p_data, size);
Adar_Write(p_adar, REG_INTERFACE_CONFIG_A, 0, 0);
// Return nothing since we assume this is non-blocking and won't wait around
}
/**
* @brief Sets the Rx/Tx bias currents for the LNA, VM, and VGA to be in either
* low power setting or nominal setting.
*
* @param p_adar[in] Adar pointer Which specifies the device and what function
* to use for SPI transfer.
* @param p_bias[in] An AdarBiasCurrents struct filled with bias settings
* as seen in the datasheet Table 6. SPI Settings for
* Different Power Modules
* @param broadcast Send the message as a broadcast to all ADARs in the SPI chain
* if this set to BROADCAST_ON.
*
* @return Returns ADAR_ERR_NOERROR if the bias currents were set
*/
uint8_t Adar_SetBiasCurrents(const AdarDevice * p_adar, AdarBiasCurrents * p_bias, uint8_t broadcast)
{
uint8_t bias = 0;
// RX LNA/VGA/VM bias
bias = (p_bias->rx_lna & 0x0f);
Adar_Write(p_adar, REG_BIAS_CURRENT_RX_LNA, bias, broadcast); // RX LNA bias
bias = (p_bias->rx_vga & 0x07 << 3) | (p_bias->rx_vm & 0x07);
Adar_Write(p_adar, REG_BIAS_CURRENT_RX, bias, broadcast); // RX VM/VGA bias
// TX VGA/VM/DRV bias
bias = (p_bias->tx_vga & 0x07 << 3) | (p_bias->tx_vm & 0x07);
Adar_Write(p_adar, REG_BIAS_CURRENT_TX, bias, broadcast); // TX VM/VGA bias
bias = (p_bias->tx_drv & 0x07);
Adar_Write(p_adar, REG_BIAS_CURRENT_TX_DRV, bias, broadcast); // TX DRV bias
return(ADAR_ERROR_NOERROR);
}
/**
* @brief Set the bias ON and bias OFF voltages for the four PA's and one LNA.
*
* @pre This will set all 5 bias ON values and all 5 bias OFF values at once.
* To enable these bias values, please see the data sheet and ensure that the BIAS_CTRL,
* LNA_BIAS_OUT_EN, TR_SOURCE, TX_EN, RX_EN, TR (input to chip), and PA_ON (input to chip)
* bits have all been properly set.
*
* @param p_adar[in] Adar pointer Which specifies the device and what function
* to use for SPI transfer.
* @param bias_on_voltage Array that contains the bias ON voltages.
* @param bias_off_voltage Array that contains the bias OFF voltages.
*
* @return Returns ADAR_ERR_NOERROR if the bias currents were set
*/
uint8_t Adar_SetBiasVoltages(const AdarDevice * p_adar, uint8_t bias_on_voltage[5], uint8_t bias_off_voltage[5])
{
Adar_SetBit(p_adar, 0x30, 6, BROADCAST_OFF);
Adar_SetBit(p_adar, 0x31, 2, BROADCAST_OFF);
Adar_SetBit(p_adar, 0x38, 5, BROADCAST_OFF);
Adar_Write(p_adar, REG_PA_CH1_BIAS_ON,bias_on_voltage[0], BROADCAST_OFF);
Adar_Write(p_adar, REG_PA_CH2_BIAS_ON,bias_on_voltage[1], BROADCAST_OFF);
Adar_Write(p_adar, REG_PA_CH3_BIAS_ON,bias_on_voltage[2], BROADCAST_OFF);
Adar_Write(p_adar, REG_PA_CH4_BIAS_ON,bias_on_voltage[3], BROADCAST_OFF);
Adar_Write(p_adar, REG_PA_CH1_BIAS_OFF,bias_off_voltage[0], BROADCAST_OFF);
Adar_Write(p_adar, REG_PA_CH2_BIAS_OFF,bias_off_voltage[1], BROADCAST_OFF);
Adar_Write(p_adar, REG_PA_CH3_BIAS_OFF,bias_off_voltage[2], BROADCAST_OFF);
Adar_Write(p_adar, REG_PA_CH4_BIAS_OFF,bias_off_voltage[3], BROADCAST_OFF);
Adar_SetBit(p_adar, 0x30, 4, BROADCAST_OFF);
Adar_SetBit(p_adar, 0x30, 6, BROADCAST_OFF);
Adar_SetBit(p_adar, 0x31, 2, BROADCAST_OFF);
Adar_SetBit(p_adar, 0x38, 5, BROADCAST_OFF);
Adar_Write(p_adar, REG_LNA_BIAS_ON,bias_on_voltage[4], BROADCAST_OFF);
Adar_Write(p_adar, REG_LNA_BIAS_OFF,bias_off_voltage[4], BROADCAST_OFF);
Adar_ResetBit(p_adar, 0x30, 7, BROADCAST_OFF);
Adar_SetBit(p_adar, 0x31, 2, BROADCAST_OFF);
Adar_SetBit(p_adar, 0x31, 4, BROADCAST_OFF);
Adar_SetBit(p_adar, 0x31, 7, BROADCAST_OFF);
return(ADAR_ERROR_NOERROR);
}
/**
* @brief Setup the ADAR to use settings that are transferred over SPI.
*
* @param p_adar[in] Adar pointer Which specifies the device and what function
* to use for SPI transfer.
* @param broadcast Send the message as a broadcast to all ADARs in the SPI chain
* if this set to BROADCAST_ON.
*
* @return Returns ADAR_ERR_NOERROR if the bias currents were set
*/
uint8_t Adar_SetRamBypass(const AdarDevice * p_adar, uint8_t broadcast)
{
uint8_t data;
data = (MEM_CTRL_BIAS_RAM_BYPASS | MEM_CTRL_BEAM_RAM_BYPASS);
Adar_Write(p_adar, REG_MEM_CTL, data, broadcast);
return(ADAR_ERROR_NOERROR);
}
/**
* @brief Set the VGA gain value of a Receive channel in dB.
*
* @param p_adar[in] Adar pointer Which specifies the device and what function
* to use for SPI transfer.
* @param channel Channel in which to set the gain (1-4).
* @param vga_gain_db Gain to be applied to the channel, ranging from 0 - 30 dB.
* (Intended operation >16 dB).
* @param broadcast Send the message as a broadcast to all ADARs in the SPI chain
* if this set to BROADCAST_ON.
*
* @return Returns ADAR_ERROR_NOERROR if the gain was successfully set.
* ADAR_ERROR_FAILED if an invalid channel was selected.
*
* @warning 0 dB or 15 dB step attenuator may also be turned on, which is why intended operation is >16 dB.
*/
uint8_t Adar_SetRxVgaGain(const AdarDevice * p_adar, uint8_t channel, uint8_t vga_gain_db, uint8_t broadcast)
{
uint8_t vga_gain_bits = (uint8_t)(255*vga_gain_db/16);
uint32_t mem_addr = 0;
if((channel == 0) || (channel > 4))
{
return(ADAR_ERROR_FAILED);
}
mem_addr = REG_CH1_RX_GAIN + (channel & 0x03);
// Set gain
Adar_Write(p_adar, mem_addr, vga_gain_bits, broadcast);
// Load the new setting
Adar_Write(p_adar, REG_LOAD_WORKING, 0x1, broadcast);
return(ADAR_ERROR_NOERROR);
}
/**
* @brief Set the phase of a given receive channel using the I/Q vector modulator.
*
* @pre According to the given @param phase, this sets the polarity (bit 5) and gain (bits 4-0)
* of the @param channel, and then loads them into the working register.
* A vector modulator I/Q look-up table has been provided at the beginning of this library.
*
* @param p_adar[in] Adar pointer Which specifies the device and what function
* to use for SPI transfer.
* @param channel Channel in which to set the gain (1-4).
* @param phase Byte that is used to set the polarity (bit 5) and gain (bits 4-0).
* @param broadcast Send the message as a broadcast to all ADARs in the SPI chain
* if this set to BROADCAST_ON.
*
* @return Returns ADAR_ERROR_NOERROR if the phase was successfully set.
* ADAR_ERROR_FAILED if an invalid channel was selected.
*
* @note To obtain your phase:
* phase = degrees * 128;
* phase /= 360;
*/
uint8_t Adar_SetRxPhase(const AdarDevice * p_adar, uint8_t channel, uint8_t phase, uint8_t broadcast)
{
uint8_t i_val = 0;
uint8_t q_val = 0;
uint32_t mem_addr_i, mem_addr_q;
if((channel == 0) || (channel > 4))
{
return(ADAR_ERROR_FAILED);
}
//phase = phase % 128;
i_val = VM_I[phase];
q_val = VM_Q[phase];
mem_addr_i = REG_CH1_RX_PHS_I + (channel & 0x03) * 2;
mem_addr_q = REG_CH1_RX_PHS_Q + (channel & 0x03) * 2;
Adar_Write(p_adar, mem_addr_i, i_val, broadcast);
Adar_Write(p_adar, mem_addr_q, q_val, broadcast);
Adar_Write(p_adar, REG_LOAD_WORKING, 0x1, broadcast);
return(ADAR_ERROR_NOERROR);
}
/**
* @brief Set the VGA gain value of a Tx channel in dB.
*
* @param p_adar[in] Adar pointer Which specifies the device and what function
* to use for SPI transfer.
* @param broadcast Send the message as a broadcast to all ADARs in the SPI chain
* if this set to BROADCAST_ON.
*
* @return Returns ADAR_ERROR_NOERROR if the bias was successfully set.
* ADAR_ERROR_FAILED if an invalid channel was selected.
*
* @warning 0 dB or 15 dB step attenuator may also be turned on, which is why intended operation is >16 dB.
*/
uint8_t Adar_SetTxBias(const AdarDevice * p_adar, uint8_t broadcast)
{
uint8_t vga_bias_bits;
uint8_t drv_bias_bits;
uint32_t mem_vga_bias;
uint32_t mem_drv_bias;
mem_vga_bias = REG_BIAS_CURRENT_TX;
mem_drv_bias = REG_BIAS_CURRENT_TX_DRV;
// Set bias to nom
vga_bias_bits = 0x2D;
drv_bias_bits = 0x06;
// Set bias
Adar_Write(p_adar, mem_vga_bias, vga_bias_bits, broadcast);
// Set bias
Adar_Write(p_adar, mem_drv_bias, drv_bias_bits, broadcast);
// Load the new setting
Adar_Write(p_adar, REG_LOAD_WORKING, 0x2, broadcast);
return(ADAR_ERROR_NOERROR);
}
/**
* @brief Set the VGA gain value of a Tx channel.
*
* @param p_adar[in] Adar pointer Which specifies the device and what function
* to use for SPI transfer.
* @param channel Tx channel in which to set the gain, ranging from 1 - 4.
* @param gain Gain to be applied to the channel, ranging from 0 - 127,
* plus the MSb 15dB attenuator (Intended operation >16 dB).
* @param broadcast Send the message as a broadcast to all ADARs in the SPI chain
* if this set to BROADCAST_ON.
*
* @return Returns ADAR_ERROR_NOERROR if the gain was successfully set.
* ADAR_ERROR_FAILED if an invalid channel was selected.
*
* @warning 0 dB or 15 dB step attenuator may also be turned on, which is why intended operation is >16 dB.
*/
uint8_t Adar_SetTxVgaGain(const AdarDevice * p_adar, uint8_t channel, uint8_t gain, uint8_t broadcast)
{
uint32_t mem_addr;
if((channel == 0) || (channel > 4))
{
return(ADAR_ERROR_FAILED);
}
mem_addr = REG_CH1_TX_GAIN + (channel & 0x03);
// Set gain
Adar_Write(p_adar, mem_addr, gain, broadcast);
// Load the new setting
Adar_Write(p_adar, REG_LOAD_WORKING, LD_WRK_REGS_LDTX_OVERRIDE, broadcast);
return(ADAR_ERROR_NOERROR);
}
/**
* @brief Set the phase of a given transmit channel using the I/Q vector modulator.
*
* @pre According to the given @param phase, this sets the polarity (bit 5) and gain (bits 4-0)
* of the @param channel, and then loads them into the working register.
* A vector modulator I/Q look-up table has been provided at the beginning of this library.
*
* @param p_adar[in] Adar pointer Which specifies the device and what function
* to use for SPI transfer.
* @param channel Channel in which to set the gain (1-4).
* @param phase Byte that is used to set the polarity (bit 5) and gain (bits 4-0).
* @param broadcast Send the message as a broadcast to all ADARs in the SPI chain
* if this set to BROADCAST_ON.
*
* @return Returns ADAR_ERROR_NOERROR if the phase was successfully set.
* ADAR_ERROR_FAILED if an invalid channel was selected.
*
* @note To obtain your phase:
* phase = degrees * 128;
* phase /= 360;
*/
uint8_t Adar_SetTxPhase(const AdarDevice * p_adar, uint8_t channel, uint8_t phase, uint8_t broadcast)
{
uint8_t i_val = 0;
uint8_t q_val = 0;
uint32_t mem_addr_i, mem_addr_q;
if((channel == 0) || (channel > 4))
{
return(ADAR_ERROR_FAILED);
}
//phase = phase % 128;
i_val = VM_I[phase];
q_val = VM_Q[phase];
mem_addr_i = REG_CH1_TX_PHS_I + (channel & 0x03) * 2;
mem_addr_q = REG_CH1_TX_PHS_Q + (channel & 0x03) * 2;
Adar_Write(p_adar, mem_addr_i, i_val, broadcast);
Adar_Write(p_adar, mem_addr_q, q_val, broadcast);
Adar_Write(p_adar, REG_LOAD_WORKING, 0x1, broadcast);
return(ADAR_ERROR_NOERROR);
}
/**
* @brief Reset the whole ADAR device.
*
* @param p_adar[in] ADAR pointer Which specifies the device and what function
* to use for SPI transfer.
*/
void Adar_SoftReset(const AdarDevice * p_adar)
{
uint8_t instruction[3];
instruction[0] = ((p_adar->dev_addr & 0x03) << 5);
instruction[1] = 0x00;
instruction[2] = 0x81;
p_adar->Transfer(instruction, NULL, sizeof(instruction));
}
/**
* @brief Reset ALL ADAR devices in the SPI chain.
*
* @param p_adar[in] Adar pointer Which specifies the device and what function
* to use for SPI transfer.
*/
void Adar_SoftResetAll(const AdarDevice * p_adar)
{
uint8_t instruction[3];
instruction[0] = 0x08;
instruction[1] = 0x00;
instruction[2] = 0x81;
p_adar->Transfer(instruction, NULL, sizeof(instruction));
}
/**
* @brief Write a byte of @param data to the register located at @param mem_addr.
*
* @param p_adar[in] Adar pointer Which specifies the device and what function
* to use for SPI transfer.
* @param mem_addr Memory address of the register you wish to read from.
* @param data Byte of data to be stored in the register.
* @param broadcast Send the message as a broadcast to all ADARs in the SPI chain
if this set to BROADCAST_ON.
*
* @warning If writing the same data to multiple registers, use ADAR_WriteBlock.
*/
void Adar_Write(const AdarDevice * p_adar, uint32_t mem_addr, uint8_t data, uint8_t broadcast)
{
uint8_t instruction[3];
if (broadcast)
{
instruction[0] = 0x08;
}
else
{
instruction[0] = ((p_adar->dev_addr & 0x03) << 5);
}
instruction[0] |= (0x1F00 & mem_addr) >> 8;
instruction[1] = (0xFF & mem_addr);
instruction[2] = data;
p_adar->Transfer(instruction, NULL, sizeof(instruction));
}
/**
* @brief Block memory write to an ADAR device.
*
* @pre ADDR_ASCN BITS IN REGISTER ZERO MUST BE SET!
*
* @param p_adar[in] Adar pointer Which specifies the device and what function
* to use for SPI transfer.
* @param mem_addr Memory address of the register you wish to read from.
* @param p_data[in] Pointer to block of data to transfer (must have two unused bytes
preceding the data for instruction).
* @param size Size of data in bytes, including the two additional leading bytes.
*
* @warning First two bytes of data will be corrupted if you do not provide two unused leading bytes!
*/
void Adar_WriteBlock(const AdarDevice * p_adar, uint16_t mem_addr, uint8_t * p_data, uint32_t size)
{
// Prepare command
p_data[0] = ((p_adar->dev_addr & 0x03) << 5);
p_data[0] |= ((mem_addr) >> 8) & 0x1F;
p_data[1] = (0xFF & mem_addr);
// Start the transfer
p_adar->Transfer(p_data, NULL, size);
// Return nothing since we assume this is non-blocking and won't wait around
}
/**
* @brief Set contents of the INTERFACE_CONFIG_A register.
*
* @param p_adar[in] Adar pointer Which specifies the device and what function
* to use for SPI transfer.
* @param flags #INTERFACE_CONFIG_A_SOFTRESET, #INTERFACE_CONFIG_A_LSB_FIRST,
* #INTERFACE_CONFIG_A_ADDR_ASCN, #INTERFACE_CONFIG_A_SDO_ACTIVE
* @param broadcast Send the message as a broadcast to all ADARs in the SPI chain
* if this set to BROADCAST_ON.
*/
void Adar_WriteConfigA(const AdarDevice * p_adar, uint8_t flags, uint8_t broadcast)
{
Adar_Write(p_adar, 0x00, flags, broadcast);
}
/**
* @brief Write a byte of @param data to the register located at @param mem_addr and
* then read from the device and verify that the register was correctly set.
*
* @param p_adar[in] Adar pointer Which specifies the device and what function
* to use for SPI transfer.
* @param mem_addr Memory address of the register you wish to read from.
* @param data Byte of data to be stored in the register.
*
* @return Returns the number of attempts that it took to successfully write to a register,
* starting from zero.
* @warning This function currently only supports writes to a single regiter in a single ADAR.
*/
uint8_t Adar_WriteVerify(const AdarDevice * p_adar, uint32_t mem_addr, uint8_t data)
{
uint8_t rx_data;
for (uint8_t ii = 0; ii < 3; ii++)
{
Adar_Write(p_adar, mem_addr, data, 0);
// Can't read back from an ADAR with HW address 0
if (!((p_adar->dev_addr) % 4))
{
return(ADAR_ERROR_INVALIDADDR);
}
rx_data = Adar_Read(p_adar, mem_addr);
if (rx_data == data)
{
return(ii);
}
}
return(ADAR_ERROR_FAILED);
}
void Adar_SetBit(const AdarDevice * p_adar, uint32_t mem_addr, uint8_t bit, uint8_t broadcast)
{
uint8_t temp = Adar_Read(p_adar, mem_addr);
uint8_t data = temp|(1<<bit);
Adar_Write(p_adar,mem_addr, data,broadcast);
}
void Adar_ResetBit(const AdarDevice * p_adar, uint32_t mem_addr, uint8_t bit, uint8_t broadcast)
{
uint8_t temp = Adar_Read(p_adar, mem_addr);
uint8_t data = temp&~(1<<bit);
Adar_Write(p_adar,mem_addr, data,broadcast);
}
@@ -0,0 +1,296 @@
/**
* MIT License
*
* Copyright (c) 2020 Jimmy Pentz
*
* Reach me at: github.com/jgpentz, jpentz1( at )gmail.com
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sells
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
/* ADAR1000 4-Channel, X Band and Ku Band Beamformer */
#ifndef LIB_ADAR1000_H_
#define LIB_ADAR1000_H_
extern SPI_HandleTypeDef hspi1;
#ifndef NULL
#define NULL (0)
#endif
// ----------------------------------------------------------------------------
// Includes
// ----------------------------------------------------------------------------
#include "main.h"
#include "hardware_config.h"
#include "stm32f7xx_hal.h"
#include "stm32f7xx_hal_spi.h"
#include "stm32f7xx_hal_gpio.h"
#include <stdbool.h>
#include <stdint.h>
#include <string.h>
#ifdef __cplusplus
extern "C" { // Prevent C++ name mangling
#endif
// ----------------------------------------------------------------------------
// Datatypes
// ----------------------------------------------------------------------------
extern const uint8_t VM_GAIN[128];
extern const uint8_t VM_I[128];
extern const uint8_t VM_Q[128];
/// A function pointer prototype for a SPI transfer, the 3 parameters would be
/// p_txData, p_rxData, and size (number of bytes to transfer), respectively.
typedef uint32_t (*Adar_SpiTransfer)( uint8_t *, uint8_t *, uint32_t);
typedef struct
{
uint8_t dev_addr; ///< 2-bit device hardware address, 0x00, 0x01, 0x10, 0x11
Adar_SpiTransfer Transfer; ///< Function pointer to the function used for SPI transfers
uint8_t * p_rx_buffer; ///< Data buffer to store received bytes into
}const AdarDevice;
/// Use this to store bias current values into, as seen in the datasheet
/// Table 6. SPI Settings for Different Power Modules
typedef struct
{
uint8_t rx_lna; ///< nominal: 8, low power: 5
uint8_t rx_vm; ///< nominal: 5, low power: 2
uint8_t rx_vga; ///< nominal: 10, low power: 3
uint8_t tx_vm; ///< nominal: 5, low power: 2
uint8_t tx_vga; ///< nominal: 5, low power: 5
uint8_t tx_drv; ///< nominal: 6, low power: 3
} AdarBiasCurrents;
/// Useful for queries regarding the device info
typedef struct
{
uint8_t norm_operating_mode : 2;
uint8_t cust_operating_mode : 2;
uint8_t dev_status : 4;
uint8_t chip_type;
uint16_t product_id;
uint8_t scratchpad;
uint8_t spi_rev;
uint16_t vendor_id;
uint8_t rev_id;
} AdarDeviceInfo;
/// Return types for functions in this library
typedef enum {
ADAR_ERROR_NOERROR = 0,
ADAR_ERROR_FAILED = 1,
ADAR_ERROR_INVALIDADDR = 2,
} AdarErrorCodes;
// ----------------------------------------------------------------------------
// Function Prototypes
// ----------------------------------------------------------------------------
void Adar_AdcInit(const AdarDevice * p_adar, uint8_t broadcast_bit);
uint8_t Adar_AdcRead(const AdarDevice * p_adar, uint8_t broadcast_bit);
uint8_t Adar_GetDeviceInfo(const AdarDevice * p_adar, AdarDeviceInfo * info);
uint8_t Adar_Read(const AdarDevice * p_adar, uint32_t mem_addr);
void Adar_ReadBlock(const AdarDevice * p_adar, uint16_t mem_addr, uint8_t * p_data, uint32_t size);
uint8_t Adar_SetBiasCurrents(const AdarDevice * p_adar, AdarBiasCurrents * p_bias, uint8_t broadcast_bit);
uint8_t Adar_SetBiasVoltages(const AdarDevice * p_adar, uint8_t bias_on_voltage[5], uint8_t bias_off_voltage[5]);
uint8_t Adar_SetRamBypass(const AdarDevice * p_adar, uint8_t broadcast_bit);
uint8_t Adar_SetRxVgaGain(const AdarDevice * p_adar, uint8_t channel, uint8_t vga_gain_db, uint8_t broadcast_bit);
uint8_t Adar_SetRxPhase(const AdarDevice * p_adar, uint8_t channel, uint8_t phase, uint8_t broadcast_bit);
uint8_t Adar_SetTxBias(const AdarDevice * p_adar, uint8_t broadcast_bit);
uint8_t Adar_SetTxVgaGain(const AdarDevice * p_adar, uint8_t channel, uint8_t vga_gain_db, uint8_t broadcast_bit);
uint8_t Adar_SetTxPhase(const AdarDevice * p_adar, uint8_t channel, uint8_t phase, uint8_t broadcast_bit);
void Adar_SoftReset(const AdarDevice * p_adar);
void Adar_SoftResetAll(const AdarDevice * p_adar);
void Adar_Write(const AdarDevice * p_adar, uint32_t mem_addr, uint8_t data, uint8_t broadcast_bit);
void Adar_WriteBlock(const AdarDevice * p_adar, uint16_t mem_addr, uint8_t * p_data, uint32_t size);
void Adar_WriteConfigA(const AdarDevice * p_adar, uint8_t flags, uint8_t broadcast);
uint8_t Adar_WriteVerify(const AdarDevice * p_adar, uint32_t mem_addr, uint8_t data);
void Adar_SetBit(const AdarDevice * p_adar, uint32_t mem_addr, uint8_t bit, uint8_t broadcast);
void Adar_ResetBit(const AdarDevice * p_adar, uint32_t mem_addr, uint8_t bit, uint8_t broadcast);
// ----------------------------------------------------------------------------
// Preprocessor Definitions and Constants
// ----------------------------------------------------------------------------
// Using BROADCAST_ON will send a command to all ADARs that share a bus
#define BROADCAST_OFF 0
#define BROADCAST_ON 1
// The minimum size of a read from the ADARs consists of 3 bytes
#define ADAR1000_RD_SIZE 3
// Address at which the TX RAM starts
#define ADAR_TX_RAM_START_ADDR 0x1800
// ADC Defines
#define ADAR1000_ADC_2MHZ_CLK 0x00
#define ADAR1000_ADC_EN 0x60
#define ADAR1000_ADC_ST_CONV 0x70
/* REGISTER DEFINITIONS */
#define REG_INTERFACE_CONFIG_A 0x000
#define REG_INTERFACE_CONFIG_B 0x001
#define REG_DEV_CONFIG 0x002
#define REG_SCRATCHPAD 0x00A
#define REG_TRANSFER 0x00F
#define REG_CH1_RX_GAIN 0x010
#define REG_CH2_RX_GAIN 0x011
#define REG_CH3_RX_GAIN 0x012
#define REG_CH4_RX_GAIN 0x013
#define REG_CH1_RX_PHS_I 0x014
#define REG_CH1_RX_PHS_Q 0x015
#define REG_CH2_RX_PHS_I 0x016
#define REG_CH2_RX_PHS_Q 0x017
#define REG_CH3_RX_PHS_I 0x018
#define REG_CH3_RX_PHS_Q 0x019
#define REG_CH4_RX_PHS_I 0x01A
#define REG_CH4_RX_PHS_Q 0x01B
#define REG_CH1_TX_GAIN 0x01C
#define REG_CH2_TX_GAIN 0x01D
#define REG_CH3_TX_GAIN 0x01E
#define REG_CH4_TX_GAIN 0x01F
#define REG_CH1_TX_PHS_I 0x020
#define REG_CH1_TX_PHS_Q 0x021
#define REG_CH2_TX_PHS_I 0x022
#define REG_CH2_TX_PHS_Q 0x023
#define REG_CH3_TX_PHS_I 0x024
#define REG_CH3_TX_PHS_Q 0x025
#define REG_CH4_TX_PHS_I 0x026
#define REG_CH4_TX_PHS_Q 0x027
#define REG_LOAD_WORKING 0x028
#define REG_PA_CH1_BIAS_ON 0x029
#define REG_PA_CH2_BIAS_ON 0x02A
#define REG_PA_CH3_BIAS_ON 0x02B
#define REG_PA_CH4_BIAS_ON 0x02C
#define REG_LNA_BIAS_ON 0x02D
#define REG_RX_ENABLES 0x02E
#define REG_TX_ENABLES 0x02F
#define REG_MISC_ENABLES 0x030
#define REG_SW_CONTROL 0x031
#define REG_ADC_CONTROL 0x032
#define REG_ADC_CONTROL_TEMP_EN 0xf0
#define REG_ADC_OUT 0x033
#define REG_BIAS_CURRENT_RX_LNA 0x034
#define REG_BIAS_CURRENT_RX 0x035
#define REG_BIAS_CURRENT_TX 0x036
#define REG_BIAS_CURRENT_TX_DRV 0x037
#define REG_MEM_CTL 0x038
#define REG_RX_CHX_MEM 0x039
#define REG_TX_CHX_MEM 0x03A
#define REG_RX_CH1_MEM 0x03D
#define REG_RX_CH2_MEM 0x03E
#define REG_RX_CH3_MEM 0x03F
#define REG_RX_CH4_MEM 0x040
#define REG_TX_CH1_MEM 0x041
#define REG_TX_CH2_MEM 0x042
#define REG_TX_CH3_MEM 0x043
#define REG_TX_CH4_MEM 0x044
#define REG_PA_CH1_BIAS_OFF 0x046
#define REG_PA_CH2_BIAS_OFF 0x047
#define REG_PA_CH3_BIAS_OFF 0x048
#define REG_PA_CH4_BIAS_OFF 0x049
#define REG_LNA_BIAS_OFF 0x04A
#define REG_TX_BEAM_STEP_START 0x04D
#define REG_TX_BEAM_STEP_STOP 0x04E
#define REG_RX_BEAM_STEP_START 0x04F
#define REG_RX_BEAM_STEP_STOP 0x050
// REGISTER CONSTANTS
#define INTERFACE_CONFIG_A_SOFTRESET ((1 << 7) | (1 << 0))
#define INTERFACE_CONFIG_A_LSB_FIRST ((1 << 6) | (1 << 1))
#define INTERFACE_CONFIG_A_ADDR_ASCN ((1 << 5) | (1 << 2))
#define INTERFACE_CONFIG_A_SDO_ACTIVE ((1 << 4) | (1 << 3))
#define LD_WRK_REGS_LDRX_OVERRIDE (1 << 0)
#define LD_WRK_REGS_LDTX_OVERRIDE (1 << 1)
#define RX_ENABLES_TX_VGA_EN (1 << 0)
#define RX_ENABLES_TX_VM_EN (1 << 1)
#define RX_ENABLES_TX_DRV_EN (1 << 2)
#define RX_ENABLES_CH3_TX_EN (1 << 3)
#define RX_ENABLES_CH2_TX_EN (1 << 4)
#define RX_ENABLES_CH1_TX_EN (1 << 5)
#define RX_ENABLES_CH0_TX_EN (1 << 6)
#define TX_ENABLES_TX_VGA_EN (1 << 0)
#define TX_ENABLES_TX_VM_EN (1 << 1)
#define TX_ENABLES_TX_DRV_EN (1 << 2)
#define TX_ENABLES_CH3_TX_EN (1 << 3)
#define TX_ENABLES_CH2_TX_EN (1 << 4)
#define TX_ENABLES_CH1_TX_EN (1 << 5)
#define TX_ENABLES_CH0_TX_EN (1 << 6)
#define MISC_ENABLES_CH4_DET_EN (1 << 0)
#define MISC_ENABLES_CH3_DET_EN (1 << 1)
#define MISC_ENABLES_CH2_DET_EN (1 << 2)
#define MISC_ENABLES_CH1_DET_EN (1 << 3)
#define MISC_ENABLES_LNA_BIAS_OUT_EN (1 << 4)
#define MISC_ENABLES_BIAS_EN (1 << 5)
#define MISC_ENABLES_BIAS_CTRL (1 << 6)
#define MISC_ENABLES_SW_DRV_TR_MODE_SEL (1 << 7)
#define SW_CTRL_POL (1 << 0)
#define SW_CTRL_TR_SPI (1 << 1)
#define SW_CTRL_TR_SOURCE (1 << 2)
#define SW_CTRL_SW_DRV_EN_POL (1 << 3)
#define SW_CTRL_SW_DRV_EN_TR (1 << 4)
#define SW_CTRL_RX_EN (1 << 5)
#define SW_CTRL_TX_EN (1 << 6)
#define SW_CTRL_SW_DRV_TR_STATE (1 << 7)
#define MEM_CTRL_RX_CHX_RAM_BYPASS (1 << 0)
#define MEM_CTRL_TX_CHX_RAM_BYPASS (1 << 1)
#define MEM_CTRL_RX_BEAM_STEP_EN (1 << 2)
#define MEM_CTRL_TX_BEAM_STEP_EN (1 << 3)
#define MEM_CTRL_BIAS_RAM_BYPASS (1 << 5)
#define MEM_CTRL_BEAM_RAM_BYPASS (1 << 6)
#define MEM_CTRL_SCAN_MODE_EN (1 << 7)
#ifdef __cplusplus
} // End extern "C"
#endif
#endif /* LIB_ADAR1000_H_ */
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,803 @@
/***************************************************************************//**
* @file adf4382.h
* @brief Implementation of adf4382 Driver.
* @authors Ciprian Hegbeli (ciprian.hegbeli@analog.com)
* Jude Osemene (jude.osemene@analog.com)
********************************************************************************
* Copyright 2024(c) Analog Devices, Inc.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* 3. Neither the name of Analog Devices, Inc. nor the names of its
* contributors may be used to endorse or promote products derived from this
* software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY ANALOG DEVICES, INC. “AS IS” AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
* EVENT SHALL ANALOG DEVICES, INC. BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
* OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
* EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*******************************************************************************/
#ifdef __cplusplus
extern "C" {
#endif
#include <stdint.h>
#include <string.h>
#include "no_os_units.h"
#include "no_os_util.h"
#include "no_os_spi.h"
/* ADF4382 REG0000 Map */
#define ADF4382_SOFT_RESET_R_MSK NO_OS_BIT(7)
#define ADF4382_LSB_FIRST_R_MSK NO_OS_BIT(6)
#define ADF4382_ADDRESS_ASC_R_MSK NO_OS_BIT(5)
#define ADF4382_SDO_ACTIVE_R_MSK NO_OS_BIT(4)
#define ADF4382_SDO_ACTIVE_MSK NO_OS_BIT(3)
#define ADF4382_ADDRESS_ASC_MSK NO_OS_BIT(2)
#define ADF4382_LSB_FIRST_MSK NO_OS_BIT(1)
#define ADF4382_SOFT_RESET_MSK NO_OS_BIT(0)
#define ADF4382_RESET_CMD 0x81
/* ADF4382 REG0000 NO_OS_BIT Definition */
#define ADF4382_SDO_ACTIVE_SPI_3W 0x0
#define ADF4382_SDO_ACTIVE_SPI_4W 0x1
#define ADF4382_ADDR_ASC_AUTO_DECR 0x0
#define ADF4382_ADDR_ASC_AUTO_INCR 0x1
#define ADF4382_LSB_FIRST_MSB 0x0
#define ADF4382_LSB_FIRST_LSB 0x1
#define ADF4382_SOFT_RESET_N_OP 0x0
#define ADF4382_SOFT_RESET_EN 0x1
/* ADF4382 REG0001 Map */
#define ADF4382_SINGLE_INSTR_MSK NO_OS_BIT(7)
#define ADF4382_MASTER_RB_CTRL_MSK NO_OS_BIT(5)
/* ADF4382 REG0001 NO_OS_BIT Definition */
#define ADF4382_SPI_STREAM_EN 0x0
#define ADF4382_SPI_STREAM_DIS 0x1
#define ADF4382_RB_SLAVE_REG 0x0
#define ADF4382_RB_MASTER_REG 0x1
/* ADF4382 REG0003 NO_OS_BIT Definition */
#define ADF4382_CHIP_TYPE 0x06
/* ADF4382 REG0004 NO_OS_BIT Definition */
#define ADF4382_PRODUCT_ID_LSB 0x0005
/* ADF4382 REG0005 NO_OS_BIT Definition */
#define ADF4382_PRODUCT_ID_MSB 0x0005
/* ADF4382 REG000A Map */
#define ADF4382_SCRATCHPAD_MSK NO_OS_GENMASK(7, 0)
/* ADF4382 REG000C NO_OS_BIT Definition */
#define ADF4382_VENDOR_ID_LSB 0x56
/* ADF4382 REG000D NO_OS_BIT Definition */
#define ADF4382_VENDOR_ID_MSB 0x04
/* ADF4382 REG000F NO_OS_BIT Definition */
#define ADF4382_M_S_TRANSF_NO_OS_BIT_MSK NO_OS_BIT(0)
/* ADF4382 REG0010 Map*/
#define ADF4382_N_INT_LSB_MSK NO_OS_GENMASK(7, 0)
/* ADF4382 REG0011 Map*/
#define ADF4382_CLKOUT_DIV_MSK NO_OS_GENMASK(7, 5)
#define ADF4382_INV_CLK_OUT_MSK NO_OS_BIT(4)
#define ADF4382_N_INT_MSB_MSK NO_OS_GENMASK(3, 0)
/* ADF4382 REG0012 Map */
#define ADF4382_FRAC1WORD_LSB_MSK NO_OS_GENMASK(7, 0)
/* ADF4382 REG0013 Map */
#define ADF4382_FRAC1WORD_MID_MSK NO_OS_GENMASK(7, 0)
/* ADF4382 REG0014 Map */
#define ADF4382_FRAC1WORD_MSB_MSK NO_OS_GENMASK(7, 0)
/* ADF4382 REG0015 Map */
#define ADF4382_M_VCO_BAND_LSB_MSK NO_OS_BIT(7)
#define ADF4382_M_VCO_CORE_MSK NO_OS_BIT(6)
#define ADF4382_BIAS_DEC_MODE_MSK NO_OS_GENMASK(5, 3)
#define ADF4382_INT_MODE_MSK NO_OS_BIT(2)
#define ADF4382_PFD_POL_MSK NO_OS_BIT(1)
#define ADF4382_FRAC1WORD_MSB NO_OS_BIT(0)
/* ADF4382 REG0016 Map */
#define ADF4382_M_VCO_BAND_MSB_MSK NO_OS_GENMASK(7, 0)
/* ADF4382 REG0017 Map */
#define ADF4382_FRAC2WORD_LSB_MSK NO_OS_GENMASK(7, 0)
/* ADF4382 REG0018 Map */
#define ADF4382_FRAC2WORD_MID_MSK NO_OS_GENMASK(7, 0)
/* ADF4382 REG0019 Map */
#define ADF4382_FRAC2WORD_MSB_MSK NO_OS_GENMASK(7, 0)
/* ADF4382 REG001A Map */
#define ADF4382_MOD2WORD_LSB_MSK NO_OS_GENMASK(7, 0)
/* ADF4382 REG001B Map */
#define ADF4382_MOD2WORD_MID_MSK NO_OS_GENMASK(7, 0)
/* ADF4382 REG001C Map */
#define ADF4382_MOD2WORD_MSB_MSK NO_OS_GENMASK(7, 0)
/* ADF4382 REG001D Map */
#define ADF4382_FINE_BLEED_LSB_MSK NO_OS_GENMASK(7, 0)
/* ADF4382 REG001E Map */
#define ADF4382_EN_PHASE_RESYNC_MSK NO_OS_BIT(7)
#define ADF4382_EN_REF_RST_MSK NO_OS_BIT(6)
#define ADF4382_TIMED_SYNC_MSK NO_OS_BIT(5)
#define ADF4382_COARSE_BLEED_MSK NO_OS_GENMASK(4, 1)
#define ADF4382_FINE_BLEED_MSB_MSK NO_OS_BIT(0)
/* ADF4382 REG001F Map */
#define ADF4382_SW_SYNC_MSK NO_OS_BIT(7)
#define ADF4382_SPARE_1F_MSK NO_OS_BIT(6)
#define ADF4382_BLEED_POL_MSK NO_OS_BIT(5)
#define ADF4382_EN_BLEED_MSK NO_OS_BIT(4)
#define ADF4382_CP_I_MSK NO_OS_GENMASK(3, 0)
/* ADF4382 REG0020 Map */
#define ADF4382_EN_AUTOCAL_MSK NO_OS_BIT(7)
#define ADF4382_EN_RDBLR_MSK NO_OS_BIT(6)
#define ADF4382_R_DIV_MSK NO_OS_GENMASK(5, 0)
/* ADF4382 REG0021 Map */
#define ADF4382_PHASE_WORD_LSB_MSK NO_OS_GENMASK(7, 0)
/* ADF4382 REG0022 Map */
#define ADF4382_PHASE_WORD_MID_MSK NO_OS_GENMASK(7, 0)
/* ADF4382 REG0023 Map */
#define ADF4382_PHASE_WORD_MSB_MSK NO_OS_GENMASK(7, 0)
/* ADF4382 REG0024 Map */
#define ADF4382_SPARE_24_MSK NO_OS_GENMASK(7, 5)
#define ADF4382_DCLK_DIV_SEL_MSK NO_OS_BIT(4)
#define ADF4382_DNCLK_DIV1_MSK NO_OS_GENMASK(3, 2)
#define ADF4382_DCLK_DIV1_MSK NO_OS_GENMASK(1, 0)
/* ADF4382 REG0025 Map */
#define ADF4382_RESYNC_WAIT_LSB_MSK NO_OS_GENMASK(7, 0)
/* ADF4382 REG0026 Map */
#define ADF4382_RESYNC_WAIT_MSB_MSK NO_OS_GENMASK(7, 0)
/* ADF4382 REG0027 Map */
#define ADF4382_CAL_BLEED_FINE_MIN_MSK NO_OS_GENMASK(7, 4)
#define ADF4382_BLEED_ADJ_SCALE_MSK NO_OS_GENMASK(3, 0)
/* ADF4382 REG0028 Map */
#define ADF4382_PH_RESYNC_RB_SEL_MSK NO_OS_BIT(7)
#define ADF4382_LSB_P1_MSK NO_OS_BIT(6)
#define ADF4382_VAR_MOD_EN_MSK NO_OS_BIT(5)
#define ADF4382_DITHER1_SCALE_MSK NO_OS_GENMASK(4, 2)
#define ADF4382_EN_DITHER2_MSK NO_OS_BIT(1)
#define ADF4382_EN_DITHER1_MSK NO_OS_BIT(0)
/* ADF4382 REG0029 Map */
#define ADF4382_CLK2_OPWR_MSK NO_OS_GENMASK(7, 4)
#define ADF4382_CLK1_OPWR_MSK NO_OS_GENMASK(3, 0)
/* ADF4382 REG002A Map */
#define ADF4382_FN_DBL_MSK NO_OS_BIT(7)
#define ADF4382_PD_NDIV_TL_MSK NO_OS_BIT(6)
#define ADF4382_CLKOUT_BST_MSK NO_OS_BIT(5)
#define ADF4382_PD_SYNC_MSK NO_OS_BIT(4)
#define ADF4382_PD_CLK_MSK NO_OS_BIT(3)
#define ADF4382_PD_RDET_MSK NO_OS_BIT(2)
#define ADF4382_PD_ADC_MSK NO_OS_BIT(1)
#define ADF4382_PD_CALGEN_MSK NO_OS_BIT(0)
/* ADF4382 REG002B Map */
#define ADF4382_PD_ALL_MSK NO_OS_BIT(7)
#define ADF4382_PD_RDIV_TL_MSK NO_OS_BIT(6)
#define ADF4382_PD_NDIV_MSK NO_OS_BIT(5)
#define ADF4382_PD_VCO_MSK NO_OS_BIT(4)
#define ADF4382_PD_LD_MSK NO_OS_BIT(3)
#define ADF4382_PD_PFDCP_MSK NO_OS_BIT(2)
#define ADF4382_PD_CLKOUT1_MSK NO_OS_BIT(1)
#define ADF4382_PD_CLKOUT2_MSK NO_OS_BIT(0)
/* ADF4382 REG002C Map */
#define ADF4382_LDWIN_PW_MSK NO_OS_GENMASK(7, 5)
#define ADF4382_LD_COUNT_OPWR_MSK NO_OS_GENMASK(4, 0)
/* ADF4382 REG002D Map */
#define ADF4382_EN_DNCLK_MSK NO_OS_BIT(7)
#define ADF4382_EN_DRCLK_MSK NO_OS_BIT(6)
#define ADF4382_EN_LOL_MSK NO_OS_BIT(5)
#define ADF4382_EN_LDWIN_MSK NO_OS_BIT(4)
#define ADF4382_PDET_POL_MSK NO_OS_BIT(3)
#define ADF4382_RST_LD_MSK NO_OS_BIT(2)
#define ADF4382_LD_O_CTRL_MSK NO_OS_GENMASK(1, 0)
/* ADF4382 REG002E Map */
#define ADF4382_MUXOUT_MSK NO_OS_GENMASK(7, 4)
#define ADF4382_ABPW_WD_MSK NO_OS_BIT(3)
#define ADF4382_EN_CPTEST_MSK NO_OS_BIT(2)
#define ADF4382_CP_DOWN_MSK NO_OS_BIT(1)
#define ADF4382_CP_UP_MSK NO_OS_BIT(0)
/* ADF4382 REG002F Map*/
#define ADF4382_BST_REF_MSK NO_OS_BIT(7)
#define ADF4382_FILT_REF_MSK NO_OS_BIT(6)
#define ADF4382_RDBLR_DC_MSK NO_OS_GENMASK(5, 0)
/* ADF4382 REG0030 Map */
#define ADF4382_MUTE_NCLK_MSK NO_OS_BIT(7)
#define ADF4382_MUTE_RCLK_MSK NO_OS_BIT(6)
#define ADF4382_REF_SEL_MSK NO_OS_BIT(5)
#define ADF4382_INV_RDBLR_MSK NO_OS_BIT(4)
#define ADF4382_RDBLR_DEL_SEL_MSK NO_OS_GENMASK(3, 0)
/* ADF4382 REG0031 Map */
#define ADF4382_SYNC_DEL_MSK NO_OS_GENMASK(7, 5)
#define ADF4382_RST_SYS_MSK NO_OS_BIT(4)
#define ADF4382_EN_ADC_CLK_MSK NO_OS_BIT(3)
#define ADF4382_EN_VCAL_MSK NO_OS_BIT(2)
#define ADF4382_CAL_CT_SEL_MSK NO_OS_BIT(1)
#define ADF4382_DCLK_MODE_MSK NO_OS_BIT(0)
/* ADF4382 REG0032 Map */
#define ADF4382_SPARE_32_MSK NO_OS_BIT(7)
#define ADF4382_BLEED_ADJ_CAL_MSK NO_OS_BIT(6)
#define ADF4382_DEL_MODE_MSK NO_OS_BIT(5)
#define ADF4382_EN_AUTO_ALIGN_MSK NO_OS_BIT(4)
#define ADF4382_PHASE_ADJ_POL_MSK NO_OS_BIT(3)
#define ADF4382_EFM3_MODE_MSK NO_OS_GENMASK(2, 0)
/* ADF4382 REG0033 Map */
#define ADF4382_PHASE_ADJUST_MSK NO_OS_GENMASK(7, 0)
/* ADF4382 REG0034 Map */
#define ADF4382_PHASE_ADJ_MSK NO_OS_BIT(7)
#define ADF4382_DRCLK_DEL_MSK NO_OS_GENMASK(6, 4)
#define ADF4382_DNCLK_DEL_MSK NO_OS_GENMASK(3, 1)
#define ADF4382_RST_CNTR_MSK NO_OS_BIT(0)
/* ADF4382 REG0035 Map */
#define ADF4382_SPARE_35_MSK NO_OS_GENMASK(7, 6)
#define ADF4382_M_VCO_BIAS_MSK NO_OS_GENMASK(5, 0)
/* ADF4382 REG0036 Map */
#define ADF4382_CLKODIV_DB_MSK NO_OS_BIT(7)
#define ADF4382_DCLK_DIV_DB_MSK NO_OS_BIT(6)
#define ADF4382_SPARE_36_MSK NO_OS_GENMASK(5, 2)
#define ADF4382_EN_LUT_GEN_MSK NO_OS_BIT(1)
#define ADF4382_EN_LUT_CAL_MSK NO_OS_BIT(0)
/* ADF4382 REG0037 Map */
#define ADF4382_CAL_COUNT_TO_MSK NO_OS_GENMASK(7, 0)
/* ADF4382 REG0038 Map */
#define ADF4382_CAL_VTUNE_TO_LSB_MSK NO_OS_GENMASK(7, 0)
/* ADF4382 REG0039 Map */
#define ADF4382_O_VCO_DB_MSK NO_OS_BIT(7)
#define ADF4382_CAL_VTUNE_TO_MSB_MSK NO_OS_GENMASK(6, 0)
/* ADF4382 REG003A Map */
#define ADF4382_CAL_VCO_TO_LSB_MSK NO_OS_GENMASK(7, 0)
/* ADF4382 REG003B Map */
#define ADF4382_DEL_CTRL_DB_MSK NO_OS_BIT(7)
#define ADF4382_CAL_VCO_TO_MSB_MSK NO_OS_GENMASK(6, 0)
/* ADF4382 REG003C Map */
#define ADF4382_CNTR_DIV_WORD_MSK NO_OS_GENMASK(7, 0)
/* ADF4382 REG003D Map */
#define ADF4382_SPARE_3D_MSK NO_OS_BIT(7)
#define ADF4382_SYNC_SP_DB_MSK NO_OS_BIT(6)
#define ADF4382_CMOS_OV_MSK NO_OS_BIT(5)
#define ADF4382_READ_MODE_MSK NO_OS_BIT(4)
#define ADF4382_CNTR_DIV_WORD_MSB_MSK NO_OS_GENMASK(3, 0)
/* ADF4382 REG003E Map */
#define ADF4382_ADC_CLK_DIV_MSK NO_OS_GENMASK(7, 0)
/* ADF4382 REG003F Map */
#define ADF4382_EN_ADC_CNV_MSK NO_OS_BIT(7)
#define ADF4382_EN_ADC_VTEST_MSK NO_OS_BIT(6)
#define ADF4382_ADC_VTEST_SEL_MSK NO_OS_BIT(5)
#define ADF4382_ADC_MUX_SEL_MSK NO_OS_BIT(4)
#define ADF4382_ADC_F_CONV_MSK NO_OS_BIT(3)
#define ADF4382_ADC_C_CONV_MSK NO_OS_BIT(2)
#define ADF4382_EN_ADC_MSK NO_OS_BIT(1)
#define ADF4382_SPARE_3F_MSK NO_OS_BIT(0)
/* ADF4382 REG0040 Map */
#define ADF4382_EXT_DIV_DEC_SEL_MSK NO_OS_BIT(7)
#define ADF4382_ADC_CLK_TEST_SEL_MSK NO_OS_BIT(6)
#define ADF4382_MUTE_CLKOUT2_MSK NO_OS_GENMASK(5, 3)
#define ADF4382_MUTE_CLKOUT1_MSK NO_OS_GENMASK(2, 0)
/* ADF4382 REG0041 Map */
#define ADF4382_EXT_DIV_MSK NO_OS_GENMASK(7, 5)
#define ADF4382_EN_VCO_CAP_TEST_MSK NO_OS_BIT(4)
#define ADF4382_EN_CALGEN_CAP_TEST_MSK NO_OS_BIT(3)
#define ADF4382_EN_CP_CAP_TEST_MSK NO_OS_BIT(2)
#define ADF4382_CAP_TEST_STATE_MSK NO_OS_BIT(1)
#define ADF4382_TRANS_LOOP_SEL_MSK NO_OS_BIT(0)
/* ADF4382 REG0042 Map */
#define ADF4382_NDIV_PWRUP_TIMEOUT_MSK NO_OS_GENMASK(7, 0)
/* ADF4382 REG0043 Map */
#define ADF4382_CAL_BLEED_FINE_MAX_MSK NO_OS_GENMASK(7, 0)
/* ADF4382 REG0044 Map */
#define ADF4382_VCAL_ZERO_MSK NO_OS_BIT(7)
#define ADF4382_VPTAT_CALGEN_MSK NO_OS_GENMASK(6, 0)
/* ADF4382 REG0045 Map */
#define ADF4382_SPARE_45_MSK NO_OS_BIT(7)
#define ADF4382_VCTAT_CALGEN_MSK NO_OS_GENMASK(6, 0)
/* ADF4382 REG0046 Map */
#define ADF4382_NVMDIN_MSK NO_OS_GENMASK(7, 0)
/* ADF4382 REG0047 Map */
#define ADF4382_SPARE_47_MSK NO_OS_BIT(7)
#define ADF4382_NVMADDR_MSK NO_OS_GENMASK(6, 3)
#define ADF4382_NVMNO_OS_BIT_SEL NO_OS_GENMASK(2, 0)
/* ADF4382 REG0048 Map */
#define ADF4382_TRIM_LATCH_MSK NO_OS_BIT(7)
#define ADF4382_NVMTEST_MSK NO_OS_BIT(6)
#define ADF4382_NVMPROG_MSK NO_OS_BIT(5)
#define ADF4382_NVMRD_MSK NO_OS_BIT(4)
#define ADF4382_NVMSTART_MSK NO_OS_BIT(3)
#define ADF4382_NVMON_MSK NO_OS_BIT(2)
#define ADF4382_MARGIN_MSK NO_OS_GENMASK(1, 0)
/* ADF4382 REG0049 Map */
#define ADF4382_NVMDOUT_MSK NO_OS_GENMASK(7, 0)
/* ADF4382 REG004A Map */
#define ADF4382_SCAN_MODE_CODE_MSK NO_OS_GENMASK(7, 0)
/* ADF4382 REG004B Map */
#define ADF4382_TEMP_OFFSET_MSK NO_OS_GENMASK(7, 0)
/* ADF4382 REG004C Map */
#define ADF4382_SPARE_4C_MSK NO_OS_GENMASK(7, 6)
#define ADF4382_TEMP_SLOPE_MSK NO_OS_GENMASK(5, 0)
/* ADF4382 REG004D Map */
#define ADF4382_VCO_FSM_TEST_MUX_MSK NO_OS_GENMASK(7, 5)
#define ADF4382_SPARE_4D_MSK NO_OS_GENMASK(4, 3)
#define ADF4382_O_VCO_BIAS_MSK NO_OS_BIT(2)
#define ADF4382_O_VCO_BAND_MSK NO_OS_BIT(1)
#define ADF4382_O_VCO_CORE_MSK NO_OS_BIT(0)
/* ADF4382 REG004E Map */
#define ADF4382_SPARE_4E_MSK NO_OS_GENMASK(7, 5)
#define ADF4382_EN_TWO_PASS_CAL_MSK NO_OS_BIT(4)
#define ADF4382_TWO_PASS_BAND_START_MSK NO_OS_GENMASK(3, 0)
/* ADF4382 REG004F Map */
#define ADF4382_LUT_SCALE_MSK NO_OS_GENMASK(7, 0)
/* ADF4382 REG0050 Map */
#define ADF4382_SPARE0_MSK NO_OS_GENMASK(7, 0)
/* ADF4382 REG0051 Map */
#define ADF4382_SPARE1_MSK NO_OS_GENMASK(7, 0)
/* ADF4382 REG0052 Map */
#define ADF4382_SYNC_REF_SPARE_MSK NO_OS_GENMASK(7, 4)
#define ADF4382_SYNC_MON_DEL_MSK NO_OS_GENMASK(3, 0)
/* ADF4382 REG0053 Map */
#define ADF4382_SPARE_53_MSK NO_OS_BIT(7)
#define ADF4382_PD_SYNC_MON_MSK NO_OS_BIT(6)
#define ADF4382_SYNC_SEL_MSK NO_OS_BIT(5)
#define ADF4382_RST_SYNC_MON_MSK NO_OS_BIT(4)
#define ADF4382_SYNC_SH_DEL_MSK NO_OS_GENMASK(3, 0)
/* ADF4382 REG0054 Map */
#define ADF4382_ADC_ST_CNV_MSK NO_OS_BIT(0)
/* ADF4382 REG0058 Map */
#define ADF4382_FSM_BUSY_MSK NO_OS_BIT(1)
#define ADF4382_LOCKED_MSK NO_OS_BIT(0)
/* ADF4382 REG005E Map */
#define ADF4382_VCO_BAND_LSB_MSK NO_OS_GENMASK(7, 0)
/* ADF4382 REG005F Map */
#define ADF4382_VCO_CORE_MSK NO_OS_BIT(1)
#define ADF4382_VCO_BAND_MSB_MSK NO_OS_BIT(0)
/* ADF4382 REG0200 Map */
#define ADF4382_LUT_WR_ADDR_MSK NO_OS_GENMASK(5, 1)
#define ADF4382_O_VCO_LUT_MSK NO_OS_BIT(0)
/* ADF4382 REG0201 Map */
#define ADF4382_M_LUT_BAND_LSB_MSK NO_OS_GENMASK(7, 0)
/* ADF4382 REG0202 Map */
#define ADF4382_M_LUT_N_LSB_MSK NO_OS_GENMASK(7, 2)
#define ADF4382_M_LUT_CORE_MSK NO_OS_BIT(1)
#define ADF4382_M_LUT_BAND_MSB_MSK NO_OS_BIT(0)
/* ADF4382 REG0203 Map */
#define ADF4382_M_LUT_N_MSB_MSK NO_OS_GENMASK(5, 0)
#define ADF4382_SPI_3W_CFG(x) (no_os_field_prep(ADF4382_SDO_ACTIVE_MSK, x) | \
no_os_field_prep(ADF4382_SDO_ACTIVE_R_MSK, x))
#define ADF4382_BLEED_MSB_MSK (ADF4382_COARSE_BLEED_MSK | \
ADF4382_FINE_BLEED_MSB_MSK)
#define ADF4382_SPI_SCRATCHPAD_TEST 0x5A
/* Specifications */
#define ADF4382_SPI_WRITE_CMD 0x0
#define ADF4382_SPI_READ_CMD 0x8000
#define ADF4382_SPI_DUMMY_DATA 0x00
#define ADF4382_BUFF_SIZE_BYTES 3
#define ADF4382_VCO_FREQ_MIN 11000000000U // 11GHz
#define ADF4382_VCO_FREQ_MAX 22000000000U // 22GHz
#define ADF4383_VCO_FREQ_MIN 10000000000U // 10GHz
#define ADF4383_VCO_FREQ_MAX 20000000000U // 20GHz
#define ADF4382A_VCO_FREQ_MIN 11500000000U // 11.5GHz
#define ADF4382A_VCO_FREQ_MAX 21000000000U // 21GHz
#define ADF4382_MOD1WORD 0x2000000U // 2^25
#define ADF4382_MOD2WORD_MAX 0xFFFFFFU // 2^24 - 1
#define ADF4382_PHASE_RESYNC_MOD2WORD_MAX 0x1FFFFU // 2^17 - 1
#define ADF4382_CHANNEL_SPACING_MAX 78125U
#define ADF4382_PFD_FREQ_MAX 625000000U // 625MHz
#define ADF4382_PFD_FREQ_FRAC_MAX 250000000U // 250MHz
#define ADF4382_PFD_FREQ_MIN 5400000U // 5.4MHz
#define ADF4382_DCLK_DIV1_0_MAX 160000000U // 160MHz
#define ADF4382_DCLK_DIV1_1_MAX 320000000U // 320MHz
#define ADF4382_CLKOUT_DIV_REG_VAL_MAX 4
#define ADF4382A_CLKOUT_DIV_REG_VAL_MAX 2
#define ADF4383_RFOUT_MAX 20000000000U
#define ADF4383_RFOUT_MIN 625000000U
#define ADF4382_RFOUT_MAX 22000000000U
#define ADF4382_RFOUT_MIN 687500000U
#define ADF4382A_RFOUT_MAX 21000000000U
#define ADF4382A_RFOUT_MIN 2875000000U
#define ADF4382_REF_CLK_MAX 5000000000U
#define ADF4382_REF_CLK_MIN 10000000
#define ADF4382_REF_DIV_MAX 63
#define ADF4382_OUT_PWR_MAX 15
#define ADF4382_CPI_VAL_MAX 15
#define ADF4382_BLEED_WORD_MAX 8191
#define ADF4382_VPTAT_CALGEN 46
#define ADF4382_VCTAT_CALGEN 82
#define ADF4382_FASTCAL_VPTAT_CALGEN 30
#define ADF4382_FASTCAL_VCTAT_CALGEN 70
#define ADF4382_PHASE_BLEED_CNST 2044000
#define ADF4382_VCO_CAL_CNT 183
#define ADF4382_VCO_CAL_VTUNE 640
#define ADF4382_VCO_CAL_ALC 123
#define ADF4382_POR_DELAY_US 200
#define ADF4382_LKD_DELAY_US 500
#define ADF4382_COARSE_BLEED_CONST 180U // 180 microseconds
#define ADF4382_FINE_BLEED_CONST_1 512U // 512 microseconds
#define ADF4382_FINE_BLEED_CONST_2 250U // 250 microseconds
#define MHZ MEGA
#define S_TO_NS NANO
#define PS_TO_S PICO
#define NS_TO_PS KHZ_PER_MHZ
/**
* @brief Supported device ids.
*/
enum adf4382_dev_id {
ID_ADF4382,
ID_ADF4382A,
ID_ADF4383,
};
/**
* @struct adf4382_init_param
* @brief ADF4382 Initialization Parameters structure.
*/
struct adf4382_init_param {
/** SPI Initialization parameters */
struct no_os_spi_init_param *spi_init;
bool spi_3wire_en;
bool cmos_3v3;
uint64_t ref_freq_hz;
uint64_t freq;
bool ref_doubler_en;
uint8_t ref_div;
uint8_t cp_i;
uint16_t bleed_word;
uint8_t ld_count;
uint8_t en_lut_gen;
uint8_t en_lut_cal;
enum adf4382_dev_id id;
};
/**
* @struct adf4382_dev
* @brief ADF4382 Device Descriptor.
*/
struct adf4382_dev {
/** SPI Descriptor */
struct no_os_spi_desc *spi_desc;
bool spi_3wire_en;
bool cmos_3v3;
uint64_t ref_freq_hz;
uint64_t freq;
bool ref_doubler_en;
uint8_t ref_div;
uint8_t cp_i;
uint16_t bleed_word;
uint8_t ld_count;
uint32_t phase_adj;
uint8_t en_lut_gen;
uint8_t en_lut_cal;
uint64_t vco_max;
uint64_t vco_min;
uint64_t freq_max;
uint64_t freq_min;
uint8_t clkout_div_reg_val_max;
// N_INT variable to trigger auto calibration
uint16_t n_int;
};
/**
* @struct reg_sequence
* @brief ADF4382 register format structure for default values
*/
struct reg_sequence {
uint16_t reg;
uint8_t val;
};
/**
* @struct adf4382_reg_defaults
* @brief ADF4382 register initialization
*/
static const struct reg_sequence adf4382_reg_defaults[] = {
{ 0x000, 0x18 },
{ 0x00a, 0xA5 },
{ 0x200, 0x00 },
{ 0x201, 0x00 },
{ 0x202, 0x00 },
{ 0x203, 0x00 },
{ 0x203, 0x00 },
{ 0x203, 0x00 },
{ 0x100, 0x25 },
{ 0x101, 0x3F },
{ 0x102, 0x3F },
{ 0x103, 0x3F },
{ 0x104, 0x3F },
{ 0x105, 0x3F },
{ 0x106, 0x3F },
{ 0x107, 0x3F },
{ 0x108, 0x3F },
{ 0x109, 0x25 },
{ 0x10A, 0x25 },
{ 0x10B, 0x3F },
{ 0x10C, 0x3F },
{ 0x10D, 0x3F },
{ 0x10E, 0x3F },
{ 0x10F, 0x3F },
{ 0x110, 0x3F },
{ 0x111, 0x3F },
{ 0x054, 0x00 },
{ 0x053, 0x45 },
{ 0x052, 0x00 },
{ 0x051, 0x00 },
{ 0x050, 0x00 },
{ 0x04f, 0x08 },
{ 0x04e, 0x06 },
{ 0x04d, 0x00 },
{ 0x04c, 0x2B },
{ 0x04b, 0x5D },
{ 0x04a, 0x00 },
{ 0x048, 0x00 },
{ 0x047, 0x00 },
{ 0x046, 0x00 },
{ 0x045, 0x52 },
{ 0x044, 0x2E },
{ 0x043, 0xB8 },
{ 0x042, 0x01 },
{ 0x041, 0x00 },
{ 0x040, 0x00 },
{ 0x03f, 0x82 },
{ 0x03e, 0x4E },
{ 0x03c, 0x00 },
{ 0x03b, 0x00 },
{ 0x03a, 0xFA },
{ 0x039, 0x80 },
{ 0x038, 0x71 },
{ 0x037, 0x82 },
{ 0x036, 0xC0 },
{ 0x035, 0x00 },
{ 0x034, 0x36 },
{ 0x033, 0x00 },
{ 0x032, 0x40 },
{ 0x031, 0x63 },
{ 0x030, 0x0F },
{ 0x02f, 0x3F },
{ 0x02e, 0x00 },
{ 0x02d, 0xF1 },
{ 0x02c, 0x0E },
{ 0x02b, 0x01 },
{ 0x02a, 0x30 },
{ 0x029, 0x09 },
{ 0x028, 0x00 },
{ 0x027, 0xF0 },
{ 0x026, 0x00 },
{ 0x025, 0x01 },
{ 0x024, 0x01 },
{ 0x023, 0x00 },
{ 0x022, 0x00 },
{ 0x021, 0x00 },
{ 0x020, 0xC1 },
{ 0x01f, 0x0F },
{ 0x01e, 0x20 },
{ 0x01d, 0x00 },
{ 0x01c, 0x00 },
{ 0x01b, 0x00 },
{ 0x01a, 0x00 },
{ 0x019, 0x00 },
{ 0x018, 0x00 },
{ 0x017, 0x00 },
{ 0x016, 0x00 },
{ 0x015, 0x06 },
{ 0x014, 0x00 },
{ 0x013, 0x00 },
{ 0x012, 0x00 },
{ 0x011, 0x00 },
{ 0x010, 0x50 },
};
/** ADF4382 SPI write */
int adf4382_spi_write(struct adf4382_dev *dev, uint16_t reg_addr, uint8_t data);
/** ADF4382 SPI Read */
int adf4382_spi_read(struct adf4382_dev *dev, uint16_t reg_addr, uint8_t *data);
/** ADF4382 updates a bit in the register space over SPI */
int adf4382_spi_update_bits(struct adf4382_dev *dev, uint16_t reg_addr,
uint8_t mask, uint8_t data);
/** ADF4382 Register dump */
int adf4382_reg_dump(struct adf4382_dev *dev);
/** ADF4382 Set reference frequency attribute */
int adf4382_set_ref_clk(struct adf4382_dev *dev, uint64_t val);
/** ADF4382 Get reference frequency attribute */
int adf4382_get_ref_clk(struct adf4382_dev *dev, uint64_t *val);
/** ADF4382 Set reference doubler attribute */
int adf4382_set_en_ref_doubler(struct adf4382_dev *dev, bool en);
/** ADF4382 Get reference doubler attribute */
int adf4382_get_en_ref_doubler(struct adf4382_dev *dev, bool *en);
/** ADF4382 Set reference divider attribute */
int adf4382_set_ref_div(struct adf4382_dev *dev, int32_t div);
/** ADF4382 Get reference divider attribute */
int adf4382_get_ref_div(struct adf4382_dev *dev, int32_t *div);
/** ADF4382 Set charge pump current attribute */
int adf4382_set_cp_i(struct adf4382_dev *dev, int32_t reg_val);
/** ADF4382 Get charge pump current attribute */
int adf4382_get_cp_i(struct adf4382_dev *dev, int32_t *reg_val);
/** ADF4382 Set bleed current attribute */
int adf4382_set_bleed_word(struct adf4382_dev *dev, int32_t word);
/** ADF4382 Get bleed current attribute */
int adf4382_get_bleed_word(struct adf4382_dev *dev, int32_t *word);
/** ADF4382 Set output frequency attribute */
int adf4382_set_rfout(struct adf4382_dev *dev, uint64_t val);
/** ADF4382 Get output frequency attribute */
int adf4382_get_rfout(struct adf4382_dev *dev, uint64_t *val);
/** ADF4382 Set output power attributes */
int adf4382_set_out_power(struct adf4382_dev *dev, uint8_t ch, int32_t pwr);
/** ADF4382 Get output power attributes */
int adf4382_get_out_power(struct adf4382_dev *dev, uint8_t ch, int32_t *pwr);
/** ADF4382 Set channel enable attributes */
int adf4382_set_en_chan(struct adf4382_dev *dev, uint8_t ch, bool en);
/** ADF4382 Get channel enable attributes */
int adf4382_get_en_chan(struct adf4382_dev *dev, uint8_t ch, bool *en);
/** ADF4382 Sets frequency */
int adf4382_set_freq(struct adf4382_dev *dev);
/** ADF4382 Set fast calibration attributes */
int adf4382_set_en_fast_calibration(struct adf4382_dev *dev, bool en_fast_cal);
/** ADF4382 Set fast calibration LUT calibration attributes */
int adf4382_set_en_lut_calibration(struct adf4382_dev *dev, bool en_lut_cal);
/** ADF4382 Get Fast Calibration LUT Calibration attributes */
int adf4382_get_en_lut_calibration(struct adf4382_dev *dev, bool *en);
/** ADF4382 Set Output Frequency without writing the Ndiv Register */
int adf4382_set_change_freq(struct adf4382_dev *dev);
/** ADF4382 Get Change Output Frequency attribute value */
int adf4382_get_change_rfout(struct adf4382_dev *dev, uint64_t *val);
/** ADF4382 Set Change Output Frequency attribute value */
int adf4382_set_change_rfout(struct adf4382_dev *dev, uint64_t val);
/** ADF4382 Set the NDIV register attribute value */
int adf4382_set_start_calibration(struct adf4382_dev *dev);
/** ADF4382 Get the NDIV register attribute value as 0 */
int adf4382_get_start_calibration(struct adf4382_dev *dev, bool *start_cal);
/** ADF4382 Sets Phase adjustment */
int adf4382_set_phase_adjust(struct adf4382_dev *dev, uint32_t phase_ps);
/** ADF4382 Sets Phase adjustment polarity*/
int adf4382_set_phase_pol(struct adf4382_dev *dev, bool polarity);
/** ADF4382 Gets Phase adjustment polarity*/
int adf4382_get_phase_pol(struct adf4382_dev *dev, bool *polarity);
/** ADF4382 Set EZSYNC feature attributes */
int adf4382_set_ezsync_setup(struct adf4382_dev *dev, bool sync);
/** ADF4382 Set Timed SYNC feature attributes */
int adf4382_set_timed_sync_setup(struct adf4382_dev *dev, bool sync);
/** ADF4382 Get EZSYNC and Timed SYNC feature attributes */
int adf4382_get_phase_sync_setup(struct adf4382_dev *dev, bool *en);
/** ADF4382 Set sw_sync attribute */
int adf4382_set_sw_sync(struct adf4382_dev *dev, bool sw_sync);
/** ADF4382 Get sw_sync attribute */
int adf4382_get_sw_sync(struct adf4382_dev *dev, bool *sw_sync);
/** ADF4382 Initialization */
int adf4382_init(struct adf4382_dev **device,
struct adf4382_init_param *init_param);
/** ADF4382 Remove */
int adf4382_remove(struct adf4382_dev *dev);
#ifdef __cplusplus
}
#endif
@@ -0,0 +1,43 @@
#ifndef HARDWARE_CONFIG_H
#define HARDWARE_CONFIG_H
#include "stm32f7xx_hal.h"
#define GPIO_VR GPIOB
#define EN_32 GPIO_PIN_14 //Active High
#define EN_42 GPIO_PIN_15 //Active High
#define GPIO_si5351 GPIOB
#define SI5351_CLK_EN GPIO_PIN_4 //Active Low
#define SI5351_SS_EN GPIO_PIN_5 //Active High (Spread Spectrum)
#define GPIO_ADF GPIOD
#define ADF_CS GPIO_PIN_0 //Active Low
#define ADF_CE GPIO_PIN_1 //Active High (Chip Enable)
#define ADF_DELSTR GPIO_PIN_2 //Delay Strobe/ 1=adjustment needed/ adjustment is made after GPIO_PIN_ssing from 1 to 0
#define ADF_DELADJ GPIO_PIN_3 // Delay Adjustment/ 0=ensures that delay of RF is reduced when ADF_DELSTR is asserted/ 0!=1
#define GPIO_LED GPIOD
#define LED_1 GPIO_PIN_10
#define LED_2 GPIO_PIN_11
#define LED_3 GPIO_PIN_12
#define LED_4 GPIO_PIN_13
#define GPIO_ADAR GPIOA
#define CS_ADAR_1 GPIO_PIN_8
#define CS_ADAR_2 GPIO_PIN_9
#define CS_ADAR_3 GPIO_PIN_10
#define CS_ADAR_4 GPIO_PIN_11
#define GPIO_DIG GPIOC
#define DIG_0 GPIO_PIN_0 // 0 = RX mode, 1 = TX mode
#define DIG_1 GPIO_PIN_1 // Send RX ADC start frame of (83x83) to FT2232HQ_FPGA
#define DIG_2 GPIO_PIN_2 // Enable = 1 / Disable = 0 RX mixer
#define DIG_3 GPIO_PIN_3 // Enable = 1 / Disable = 0 RX mixer
#define DIG_4 GPIO_PIN_4 //
#define DIG_5 GPIO_PIN_5
#define DIG_6 GPIO_PIN_6
#define DIG_7 GPIO_PIN_7
#endif // HARDWARE_CONFIG_H
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,143 @@
/***************************************************************************//**
* @file iio.h
* @brief Header file of iio
* @author Cristian Pop (cristian.pop@analog.com)
* @author Mihail Chindris (mihail.chindris@analog.com)
********************************************************************************
* Copyright 2013(c) Analog Devices, Inc.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* 3. Neither the name of Analog Devices, Inc. nor the names of its
* contributors may be used to endorse or promote products derived from this
* software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY ANALOG DEVICES, INC. “AS IS” AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
* EVENT SHALL ANALOG DEVICES, INC. BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
* OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
* EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*******************************************************************************/
#ifndef IIO_H_
#define IIO_H_
#include "iio_types.h"
#include "no_os_uart.h"
#if defined(NO_OS_NETWORKING) || defined(NO_OS_LWIP_NETWORKING)
#include "tcp_socket.h"
#endif
enum physical_link_type {
USE_UART,
USE_LOCAL_BACKEND,
USE_NETWORK
};
struct iio_desc;
struct iio_device_init {
char *name;
void *dev;
struct iio_device *dev_descriptor;
/*
* IIO buffer implementation can use a user provided buffer in raw_buf.
* If raw_buf is NULL and iio_device has buffer callback function set,
* it will allocate memory for it when needed.
*/
int8_t *raw_buf;
/* Length of raw_buf */
uint32_t raw_buf_len;
/* If set, trigger will be linked to this device */
char *trigger_id;
};
struct iio_trigger_init {
char *name;
void *trig;
struct iio_trigger *descriptor;
};
/**
* @struct iio_ctx_attr
* @brief Structure holding the context attribute members
*/
struct iio_ctx_attr {
/** Attribute name */
const char *name;
/** Attribute value */
const char *value;
};
/**
* @struct iio_local_backend
* @brief Structure holding the local backend init parameters
*/
struct iio_local_backend {
int(*local_backend_event_read)(void *conn, uint8_t *buf, uint32_t len);
int(*local_backend_event_write)(void *conn, uint8_t *buf, uint32_t len);
char *local_backend_buff;
uint32_t local_backend_buff_len;
};
struct iio_init_param {
enum physical_link_type phy_type;
union {
struct no_os_uart_desc *uart_desc;
#if defined(NO_OS_NETWORKING) || defined(NO_OS_LWIP_NETWORKING)
struct tcp_socket_init_param *tcp_socket_init_param;
#endif
};
struct iio_local_backend *local_backend;
struct iio_ctx_attr *ctx_attrs;
uint32_t nb_ctx_attr;
struct iio_device_init *devs;
uint32_t nb_devs;
struct iio_trigger_init *trigs;
uint32_t nb_trigs;
};
/* Set communication ops and read/write ops. */
int iio_init(struct iio_desc **desc, struct iio_init_param *init_param);
/* Free the resources allocated by iio_init(). */
int iio_remove(struct iio_desc *desc);
/* Execut an iio step. */
int iio_step(struct iio_desc *desc);
/* Signal iio that a trigger has been triggered.
* This will be called in interrupt context. An application callback will be
called in interrupt context if trigger is synchronous with the interrupt
(is_synchronous = true) or will be called from iio_step if trigger is
asynchronous (is_synchronous = false) */
int iio_process_trigger_type(struct iio_desc *desc, char *trigger_name);
int32_t iio_parse_value(char *buf, enum iio_val fmt,
int32_t *val, int32_t *val2);
int iio_format_value(char *buf, uint32_t len, enum iio_val fmt,
int32_t size, int32_t *vals);
/* DMA buffer functions. */
/* Get buffer addr where to write iio_buffer.size bytes */
int iio_buffer_get_block(struct iio_buffer *buffer, void **addr);
/* To be called to mark last iio_buffer_read as done */
int iio_buffer_block_done(struct iio_buffer *buffer);
/* Trigger buffer functions. */
/* Write to buffer iio_buffer.bytes_per_scan bytes from data */
int iio_buffer_push_scan(struct iio_buffer *buffer, void *data);
/* Read from buffer iio_buffer.bytes_per_scan bytes into data */
int iio_buffer_pop_scan(struct iio_buffer *buffer, void *data);
#endif /* IIO_H_ */
@@ -0,0 +1,733 @@
/***************************************************************************//**
* @file iio_adf4382.c
* @brief Implementation of IIO ADF4382 Driver.
* @authors CHegbeli (ciprian.hegbeli@analog.com)
* Jude Osemene (jude.osemene@analog.com)
********************************************************************************
* Copyright 2024(c) Analog Devices, Inc.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* 3. Neither the name of Analog Devices, Inc. nor the names of its
* contributors may be used to endorse or promote products derived from this
* software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY ANALOG DEVICES, INC. “AS IS” AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
* EVENT SHALL ANALOG DEVICES, INC. BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
* OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
* EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*******************************************************************************/
#include <stdlib.h>
#include <stdio.h>
#include <inttypes.h>
#include "no_os_error.h"
#include "no_os_util.h"
#include "iio_adf4382.h"
#include "adf4382.h"
#include "no_os_alloc.h"
/**
* @brief Supported charge pump currents
*/
static const int ci_table[16][2] = {
{0, 700000},
{0, 900000},
{1, 100000},
{1, 300000},
{1, 500000},
{1, 900000},
{2, 300000},
{2, 700000},
{3, 100000},
{3, 900000},
{4, 700000},
{5, 500000},
{6, 300000},
{7, 900000},
{9, 500000},
{11, 100000}
};
/**
* @brief Helper function to read a pair of values in a table with 2 elements.
* @param tb - Input table.
* @param size - Size of the table.
* @param val1 - The first value to be found.
* @param val2 - The second value to be found.
* @return i - The index of the pair if found or an error if there is no
* pair of values in the table.
*/
static int adf4382_iio_find_2d_row(const int (*tbl)[2], const int size,
const int val1, const int val2)
{
int i;
for (i = 0; i < size; i++) {
if (tbl[i][0] == val1 && tbl[i][1] == val2)
return i;
}
return -EINVAL;
}
/**
* @brief Wrapper for reading adf4382 register.
* @param dev - The iio device structure.
* @param reg - Address of the register to be read from.
* @param readval - Read data.
* @return - Result of the reading procedure.
*/
static int adf4382_iio_read_reg(struct adf4382_iio_dev *dev, uint32_t reg,
uint32_t *readval)
{
uint8_t tmp;
int ret;
ret = adf4382_spi_read(dev->adf4382_dev, (uint16_t)reg, &tmp);
if (ret)
return ret;
*readval = tmp;
return 0;
}
/**
* @brief Wrapper for writing adf4382 register.
* @param dev - The iio device structure.
* @param reg - Address of the register to be written to.
* @param writeval - Data to be written.
* @return - Result of the writing procedure.
*/
static int adf4382_iio_write_reg(struct adf4382_iio_dev *dev, uint32_t reg,
uint32_t writeval)
{
return adf4382_spi_write(dev->adf4382_dev, (uint16_t)reg,
(uint8_t)writeval);
}
/**
* @brief Handles the read request for the device attributes.
* @param dev - The iio device structure.
* @param buf - Command buffer to be filled with requested data.
* @param len - Length of the received command buffer in bytes.
* @param channel - Command channel info.
* @param priv - Command attribute id.
* @return - The size of the read data in case of success, error code
* otherwise.
*/
static int adf4382_iio_read_dev_attr(void *dev, char *buf, uint32_t len,
const struct iio_ch_info *channel,
intptr_t priv)
{
struct adf4382_iio_dev *iio_adf4382 = (struct adf4382_iio_dev *)dev;
struct adf4382_dev *adf4382;
int32_t val = -EINVAL;
uint64_t val_64 = 0;
int32_t val_b[2];
char buffer[5];
int32_t cp_i;
uint8_t i;
bool en;
int ret;
if (!iio_adf4382)
return -EINVAL;
adf4382 = iio_adf4382->adf4382_dev;
if (!adf4382)
return -EINVAL;
switch (priv) {
case ADF4382_IIO_DEV_ATTR_REF_FREQ:
ret = adf4382_get_ref_clk(adf4382, &val_64);
if (ret)
return ret;
ret = snprintf(buf, len, "%"PRIu64, val_64);
break;
case ADF4382_IIO_DEV_ATTR_BLEED_CURRENT:
ret = adf4382_get_bleed_word(adf4382, &val);
if (ret)
return ret;
ret = iio_format_value(buf, len, IIO_VAL_INT, 1, &val);
break;
case ADF4382_IIO_DEV_ATTR_CHARGE_PUMP_CURRENT:
ret = adf4382_get_cp_i(adf4382, &cp_i);
if (ret)
return ret;
val_b[0] = ci_table[cp_i][0];
val_b[1] = ci_table[cp_i][1];
ret = iio_format_value(buf, len, IIO_VAL_INT_PLUS_MICRO, 2, val_b);
break;
case ADF4382_IIO_DEV_ATTR_CHARGE_PUMP_AVAILABLE:
strcpy(buf, "");
for (i = 0; i < NO_OS_ARRAY_SIZE(ci_table); i++) {
val_b[0] = ci_table[i][0];
val_b[1] = ci_table[i][1];
iio_format_value(buffer, len, IIO_VAL_INT_PLUS_MICRO, 2,
val_b);
strcat(buf, buffer);
if (i < NO_OS_ARRAY_SIZE(ci_table) - 1)
strcat(buf, " ");
}
ret = strlen(buf);
break;
case ADF4382_IIO_DEV_ATTR_REF_DIVIDER:
ret = adf4382_get_ref_div(adf4382, &val);
if (ret)
return ret;
ret = iio_format_value(buf, len, IIO_VAL_INT, 1, &val);
break;
case ADF4382_IIO_DEV_ATTR_REF_DOUBLER_EN:
ret = adf4382_get_en_ref_doubler(adf4382, &en);
if (ret)
return ret;
val = en;
ret = iio_format_value(buf, len, IIO_VAL_INT, 1, &val);
break;
case ADF4382_IIO_DEV_ATTR_FASTCAL_EN:
ret = adf4382_get_en_lut_calibration(adf4382, &en);
if (ret)
return ret;
val = en;
ret = iio_format_value(buf, len, IIO_VAL_INT, 1, &val);
break;
case ADF4382_IIO_DEV_ATTR_FASTCAL_LUT_EN:
ret = adf4382_get_en_lut_calibration(adf4382, &en);
if (ret)
return ret;
val = en;
ret = iio_format_value(buf, len, IIO_VAL_INT, 1, &val);
break;
case ADF4382_IIO_DEV_ATTR_FASTCAL_CHANGE_FREQ:
ret = adf4382_get_change_rfout(adf4382, &val_64);
if (ret)
return ret;
ret = snprintf(buf, len, "%"PRIu64, val_64);
break;
case ADF4382_IIO_DEV_ATTR_FASTCAL_START_CALIBRATION:
ret = adf4382_get_start_calibration(adf4382, &en);
if (ret)
return ret;
val = en;
ret = iio_format_value(buf, len, IIO_VAL_INT, 1, &val);
break;
case ADF4382_IIO_DEV_ATTR_SW_SYNC:
ret = adf4382_get_sw_sync(adf4382, &en);
if (ret)
return ret;
val = en;
ret = iio_format_value(buf, len, IIO_VAL_INT, 1, &val);
break;
case ADF4382_IIO_DEV_ATTR_EZ_SYNC:
ret = adf4382_get_phase_sync_setup(adf4382, &en);
if (ret)
return ret;
val = en;
ret = iio_format_value(buf, len, IIO_VAL_INT, 1, &val);
break;
case ADF4382_IIO_DEV_ATTR_TIMED_SYNC:
ret = adf4382_get_phase_sync_setup(adf4382, &en);
if (ret)
return ret;
val = en;
ret = iio_format_value(buf, len, IIO_VAL_INT, 1, &val);
break;
default:
return -EINVAL;
};
return ret;
};
/**
* @brief Handles the write request for the device attributes.
* @param dev - The iio device structure.
* @param buf - Command buffer to be filled with requested data.
* @param len - Length of the received command buffer in bytes.
* @param channel - Command channel info.
* @param priv - Command attribute id.
* @return - The size of the read data in case of success, error code
* otherwise.
*/
static int adf4382_iio_write_dev_attr(void *dev, char *buf, uint32_t len,
const struct iio_ch_info *channel,
intptr_t priv)
{
struct adf4382_iio_dev *iio_adf4382 = (struct adf4382_iio_dev *)dev;
struct adf4382_dev *adf4382;
int32_t val = -EINVAL;
uint64_t val_64 = 0;
int32_t val_b[2];
bool en;
int8_t index;
int ret;
if (!iio_adf4382)
return -EINVAL;
adf4382 = iio_adf4382->adf4382_dev;
if (!adf4382)
return -EINVAL;
switch (priv) {
case ADF4382_IIO_DEV_ATTR_REF_FREQ:
sscanf(buf, "%"PRIu64, &val_64);
ret = adf4382_set_ref_clk(adf4382, val_64);
break;
case ADF4382_IIO_DEV_ATTR_BLEED_CURRENT:
iio_parse_value(buf, IIO_VAL_INT, &val, NULL);
ret = adf4382_set_bleed_word(adf4382, val);
break;
case ADF4382_IIO_DEV_ATTR_CHARGE_PUMP_CURRENT:
iio_parse_value(buf, IIO_VAL_INT_PLUS_MICRO, &val_b[0], &val_b[1]);
index = adf4382_iio_find_2d_row(ci_table, NO_OS_ARRAY_SIZE(ci_table),
val_b[0], val_b[1]);
if (index < 0)
return index;
ret = adf4382_set_cp_i(adf4382, index);
break;
case ADF4382_IIO_DEV_ATTR_REF_DIVIDER:
iio_parse_value(buf, IIO_VAL_INT, &val, NULL);
ret = adf4382_set_ref_div(adf4382, val);
break;
case ADF4382_IIO_DEV_ATTR_REF_DOUBLER_EN:
iio_parse_value(buf, IIO_VAL_INT, &val, NULL);
en = val;
ret = adf4382_set_en_ref_doubler(adf4382, val);
break;
case ADF4382_IIO_DEV_ATTR_FASTCAL_EN:
iio_parse_value(buf, IIO_VAL_INT, &val, NULL);
en = val;
ret = adf4382_set_en_fast_calibration(adf4382, en);
break;
case ADF4382_IIO_DEV_ATTR_FASTCAL_LUT_EN:
iio_parse_value(buf, IIO_VAL_INT, &val, NULL);
en = val;
ret = adf4382_set_en_lut_calibration(adf4382, en);
break;
case ADF4382_IIO_DEV_ATTR_FASTCAL_CHANGE_FREQ:
sscanf(buf, "%"PRIu64, &val_64);
ret = adf4382_set_change_rfout(adf4382, val_64);
break;
case ADF4382_IIO_DEV_ATTR_FASTCAL_START_CALIBRATION:
iio_parse_value(buf, IIO_VAL_INT, &val, NULL);
if (!val)
return 0;
ret = adf4382_set_start_calibration(adf4382);
break;
case ADF4382_IIO_DEV_ATTR_SW_SYNC:
iio_parse_value(buf, IIO_VAL_INT, &val, NULL);
en = val;
ret = adf4382_set_sw_sync(adf4382, en);
break;
case ADF4382_IIO_DEV_ATTR_EZ_SYNC:
iio_parse_value(buf, IIO_VAL_INT, &val, NULL);
en = val;
ret = adf4382_set_ezsync_setup(adf4382, en);
break;
case ADF4382_IIO_DEV_ATTR_TIMED_SYNC:
iio_parse_value(buf, IIO_VAL_INT, &val, NULL);
en = val;
ret = adf4382_set_timed_sync_setup(adf4382, en);
break;
default:
return -EINVAL;
}
return ret;
}
/**
* @brief Handles the read request for the channel attributes.
* @param dev - The iio device structure.
* @param buf - Command buffer to be filled with requested data.
* @param len - Length of the received command buffer in bytes.
* @param channel - Command channel info.
* @param priv - Command attribute id.
* @return - The size of the read data in case of success, error code
* otherwise.
*/
static int adf4382_iio_read_chan_attr(void *dev, char *buf, uint32_t len,
const struct iio_ch_info *channel,
intptr_t priv)
{
struct adf4382_iio_dev *iio_adf4382 = (struct adf4382_iio_dev *)dev;
struct adf4382_dev *adf4382;
int32_t val = -EINVAL;
uint64_t val_64 = 0;
bool en, pol;
int ret;
if (!iio_adf4382)
return -EINVAL;
adf4382 = iio_adf4382->adf4382_dev;
if (!adf4382)
return -EINVAL;
switch (priv) {
case ADF4382_IIO_CH_ATTR_EN:
ret = adf4382_get_en_chan(adf4382, channel->ch_num, &en);
if (ret)
return ret;
val = en;
ret = iio_format_value(buf, len, IIO_VAL_INT, 1, &val);
break;
case ADF4382_IIO_CH_ATTR_FREQ:
ret = adf4382_get_rfout(adf4382, &val_64);
if (ret)
return ret;
ret = snprintf(buf, len, "%"PRIu64, val_64);
break;
case ADF4382_IIO_CH_ATTR_OPWR:
ret = adf4382_get_out_power(adf4382, channel->ch_num, &val);
if (ret)
return ret;
ret = iio_format_value(buf, len, IIO_VAL_INT, 1, &val);
break;
case ADF4382_IIO_CH_ATTR_PHASE_ADJ:
val = adf4382->phase_adj;
ret = adf4382_get_phase_pol(adf4382, &pol);
if (ret)
return ret;
if (pol)
val *= -1;
ret = iio_format_value(buf, len, IIO_VAL_INT, 1, &val);
break;
default:
return -EINVAL;
}
return ret;
}
/**
* @brief Handles the write request for the channel attributes.
* @param dev - The iio device structure.
* @param buf - Command buffer to be filled with requested data.
* @param len - Length of the received command buffer in bytes.
* @param channel - Command channel info.
* @param priv - Command attribute id.
* @return - The size of the read data in case of success, error code
* otherwise.
*/
static int adf4382_iio_write_chan_attr(void *dev, char *buf, uint32_t len,
const struct iio_ch_info *channel,
intptr_t priv)
{
struct adf4382_iio_dev *iio_adf4382 = (struct adf4382_iio_dev *)dev;
struct adf4382_dev *adf4382;
int32_t val = -EINVAL;
uint64_t val_64 = 0;
bool en;
int ret;
if (!iio_adf4382)
return -EINVAL;
adf4382 = iio_adf4382->adf4382_dev;
if (!adf4382)
return -EINVAL;
switch (priv) {
case ADF4382_IIO_CH_ATTR_EN:
iio_parse_value(buf, IIO_VAL_INT, &val, NULL);
en = val;
ret = adf4382_set_en_chan(adf4382, channel->ch_num, en);
break;
case ADF4382_IIO_CH_ATTR_FREQ:
sscanf(buf, "%"PRIu64, &val_64);
ret = adf4382_set_rfout(adf4382, val_64);
break;
case ADF4382_IIO_CH_ATTR_PHASE_ADJ:
iio_parse_value(buf, IIO_VAL_INT, &val, NULL);
if (val < 0)
ret = adf4382_set_phase_pol(adf4382, 1);
else
ret = adf4382_set_phase_pol(adf4382, 0);
if (ret)
return ret;
val = abs(val);
ret = adf4382_set_phase_adjust(adf4382, val);
break;
default:
return -EINVAL;
}
return ret;
}
static struct iio_attribute adf4382_iio_attrs[] = {
{
.name = "reference_frequency",
.shared = IIO_SHARED_BY_ALL,
.priv = ADF4382_IIO_DEV_ATTR_REF_FREQ,
.show = adf4382_iio_read_dev_attr,
.store = adf4382_iio_write_dev_attr,
},
{
.name = "charge_pump_current",
.shared = IIO_SHARED_BY_ALL,
.priv = ADF4382_IIO_DEV_ATTR_CHARGE_PUMP_CURRENT,
.show = adf4382_iio_read_dev_attr,
.store = adf4382_iio_write_dev_attr,
},
{
.name = "charge_pump_current_available",
.shared = IIO_SHARED_BY_ALL,
.priv = ADF4382_IIO_DEV_ATTR_CHARGE_PUMP_AVAILABLE,
.show = adf4382_iio_read_dev_attr,
},
{
.name = "bleed_current",
.shared = IIO_SHARED_BY_ALL,
.priv = ADF4382_IIO_DEV_ATTR_BLEED_CURRENT,
.show = adf4382_iio_read_dev_attr,
.store = adf4382_iio_write_dev_attr,
},
{
.name = "reference_doubler_en",
.shared = IIO_SHARED_BY_ALL,
.priv = ADF4382_IIO_DEV_ATTR_REF_DOUBLER_EN,
.show = adf4382_iio_read_dev_attr,
.store = adf4382_iio_write_dev_attr,
},
{
.name = "reference_divider",
.shared = IIO_SHARED_BY_ALL,
.priv = ADF4382_IIO_DEV_ATTR_REF_DIVIDER,
.show = adf4382_iio_read_dev_attr,
.store = adf4382_iio_write_dev_attr,
},
{
.name = "sw_sync_en",
.shared = IIO_SHARED_BY_ALL,
.priv = ADF4382_IIO_DEV_ATTR_SW_SYNC,
.show = adf4382_iio_read_dev_attr,
.store = adf4382_iio_write_dev_attr,
},
{
.name = "ezsync_setup",
.shared = IIO_SHARED_BY_ALL,
.priv = ADF4382_IIO_DEV_ATTR_EZ_SYNC,
.show = adf4382_iio_read_dev_attr,
.store = adf4382_iio_write_dev_attr,
},
{
.name = "timed_sync_setup",
.shared = IIO_SHARED_BY_ALL,
.priv = ADF4382_IIO_DEV_ATTR_TIMED_SYNC,
.show = adf4382_iio_read_dev_attr,
.store = adf4382_iio_write_dev_attr,
},
{
.name = "fastcal_en",
.shared = IIO_SHARED_BY_ALL,
.priv = ADF4382_IIO_DEV_ATTR_FASTCAL_EN,
.show = adf4382_iio_read_dev_attr,
.store = adf4382_iio_write_dev_attr,
},
{
.name = "fastcal_lut_en",
.shared = IIO_SHARED_BY_ALL,
.priv = ADF4382_IIO_DEV_ATTR_FASTCAL_LUT_EN,
.show = adf4382_iio_read_dev_attr,
.store = adf4382_iio_write_dev_attr,
},
{
.name = "change_frequency",
.shared = IIO_SHARED_BY_ALL,
.priv = ADF4382_IIO_DEV_ATTR_FASTCAL_CHANGE_FREQ,
.show = adf4382_iio_read_dev_attr,
.store = adf4382_iio_write_dev_attr,
},
{
.name = "start_calibration",
.shared = IIO_SHARED_BY_ALL,
.priv = ADF4382_IIO_DEV_ATTR_FASTCAL_START_CALIBRATION,
.show = adf4382_iio_read_dev_attr,
.store = adf4382_iio_write_dev_attr,
},
END_ATTRIBUTES_ARRAY
};
static struct iio_attribute adf4382_iio_ch_attrs[] = {
{
.name = "en",
.shared = IIO_SEPARATE,
.priv = ADF4382_IIO_CH_ATTR_EN,
.show = adf4382_iio_read_chan_attr,
.store = adf4382_iio_write_chan_attr,
},
{
.name = "frequency",
.shared = IIO_SHARED_BY_TYPE,
.priv = ADF4382_IIO_CH_ATTR_FREQ,
.show = adf4382_iio_read_chan_attr,
.store = adf4382_iio_write_chan_attr,
},
{
.name = "output_power",
.shared = IIO_SEPARATE,
.priv = ADF4382_IIO_CH_ATTR_OPWR,
.show = adf4382_iio_read_chan_attr,
.store = adf4382_iio_write_chan_attr,
},
{
.name = "phase",
.shared = IIO_SHARED_BY_TYPE,
.priv = ADF4382_IIO_CH_ATTR_PHASE_ADJ,
.show = adf4382_iio_read_chan_attr,
.store = adf4382_iio_write_chan_attr,
},
END_ATTRIBUTES_ARRAY
};
static struct iio_channel adf4382_channels[] = {
{
.ch_type = IIO_ALTVOLTAGE,
.channel = 0,
.ch_out = true,
.indexed = true,
.attributes = adf4382_iio_ch_attrs,
.scan_type = NULL,
},
{
.ch_type = IIO_ALTVOLTAGE,
.channel = 1,
.ch_out = true,
.indexed = true,
.attributes = adf4382_iio_ch_attrs,
.scan_type = NULL,
},
};
static struct iio_device adf4382_iio_dev = {
.num_ch = NO_OS_ARRAY_SIZE(adf4382_channels),
.channels = adf4382_channels,
.attributes = adf4382_iio_attrs,
.debug_reg_read = (int32_t (*)())adf4382_iio_read_reg,
.debug_reg_write = (int32_t (*)())adf4382_iio_write_reg
};
/**
* @brief Initializes the ADF4382 IIO driver
* @param iio_dev - The iio device structure.
* @param init_param - The structure that contains the device initial parameters.
* @return ret - Result of the initialization procedure.
*/
int adf4382_iio_init(struct adf4382_iio_dev **iio_dev,
struct adf4382_iio_dev_init_param *init_param)
{
struct adf4382_iio_dev *dev;
int ret;
dev = (struct adf4382_iio_dev *)no_os_calloc(1, sizeof(*dev));
if (!dev)
return -ENOMEM;
dev->iio_dev = &adf4382_iio_dev;
ret = adf4382_init(&dev->adf4382_dev, init_param->adf4382_dev_init);
if (ret)
goto error;
*iio_dev = dev;
return ret;
error:
no_os_free(dev);
return ret;
}
/**
* @brief Free the resources allocated by adf4382_iio_init().
* @param dev - The IIO device structure.
* @return ret - Result of the remove procedure.
*/
int adf4382_iio_remove(struct adf4382_iio_dev *dev)
{
int ret;
ret = adf4382_remove(dev->adf4382_dev);
if (ret)
return ret;
no_os_free(dev);
return 0;
}
@@ -0,0 +1,76 @@
/***************************************************************************//**
* @file iio_adf4382.h
* @brief Implementation of IIO ADF4382 Driver.
* @authors Ciprian Hegbeli (ciprian.hegbeli@analog.com)
* Jude Osemene (jude.osemene@analog.com)
********************************************************************************
* Copyright 2024(c) Analog Devices, Inc.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* 3. Neither the name of Analog Devices, Inc. nor the names of its
* contributors may be used to endorse or promote products derived from this
* software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY ANALOG DEVICES, INC. “AS IS” AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
* EVENT SHALL ANALOG DEVICES, INC. BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
* OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
* EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*******************************************************************************/
#ifndef IIO_ADF4382_H
#define IIO_ADF4382_H
#include "iio.h"
struct adf4382_iio_dev {
struct adf4382_dev *adf4382_dev;
struct iio_device *iio_dev;
};
struct adf4382_iio_dev_init_param {
struct adf4382_init_param *adf4382_dev_init;
};
enum adf4382_iio_ch_attr_id {
ADF4382_IIO_CH_ATTR_EN,
ADF4382_IIO_CH_ATTR_FREQ,
ADF4382_IIO_CH_ATTR_OPWR,
ADF4382_IIO_CH_ATTR_PHASE_ADJ,
};
enum adf4382_iio_dev_attr_id {
ADF4382_IIO_DEV_ATTR_REF_FREQ,
ADF4382_IIO_DEV_ATTR_BLEED_CURRENT,
ADF4382_IIO_DEV_ATTR_CHARGE_PUMP_CURRENT,
ADF4382_IIO_DEV_ATTR_CHARGE_PUMP_AVAILABLE,
ADF4382_IIO_DEV_ATTR_REF_DIVIDER,
ADF4382_IIO_DEV_ATTR_REF_DOUBLER_EN,
ADF4382_IIO_DEV_ATTR_SW_SYNC,
ADF4382_IIO_DEV_ATTR_EZ_SYNC,
ADF4382_IIO_DEV_ATTR_TIMED_SYNC,
ADF4382_IIO_DEV_ATTR_FASTCAL_EN,
ADF4382_IIO_DEV_ATTR_FASTCAL_LUT_EN,
ADF4382_IIO_DEV_ATTR_FASTCAL_CHANGE_FREQ,
ADF4382_IIO_DEV_ATTR_FASTCAL_START_CALIBRATION,
};
int adf4382_iio_init(struct adf4382_iio_dev **iio_dev,
struct adf4382_iio_dev_init_param *init_param);
int adf4382_iio_remove(struct adf4382_iio_dev *desc);
#endif
@@ -0,0 +1,475 @@
/***************************************************************************//**
* @file iio_app.c
* @brief C file of iio_app
* @author Mihail Chindris (mihail.chindris@analog.com)
********************************************************************************
* Copyright 2020(c) Analog Devices, Inc.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* 3. Neither the name of Analog Devices, Inc. nor the names of its
* contributors may be used to endorse or promote products derived from this
* software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY ANALOG DEVICES, INC. “AS IS” AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
* EVENT SHALL ANALOG DEVICES, INC. BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
* OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
* EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*******************************************************************************/
#ifdef IIO_SUPPORT
#include <stdlib.h>
#include <stdio.h>
#include "iio_app.h"
#include "parameters.h"
#include "no_os_alloc.h"
#if defined(ADUCM_PLATFORM)
#include "aducm3029_uart.h"
#include "aducm3029_irq.h"
#endif
#if defined(XILINX_PLATFORM)
#include "xilinx_uart.h"
#include "xilinx_irq.h"
#endif
#if defined(STM32_PLATFORM)
#include <errno.h>
#include "stm32_uart.h"
#include "stm32_irq.h"
#endif
#if defined(MAXIM_PLATFORM)
#include "maxim_irq.h"
#include "maxim_uart.h"
#endif
#ifdef NO_OS_NETWORKING
/* Fix: Use static buffers instead of calloc for new connections */
#warning "iio may not work with WIFI on aducm3029."
#ifdef ADUCM_PLATFORM
#include "wifi.h"
#endif
#include "tcp_socket.h"
#endif
#ifdef LINUX_PLATFORM
#include "linux_socket.h"
#include "tcp_socket.h"
#endif
#ifdef NO_OS_LWIP_NETWORKING
#include "lwip_socket.h"
#endif
// The default baudrate iio_app will use to print messages to console.
#define UART_BAUDRATE_DEFAULT 115200
#define UART_STOPBITS_DEFAULT NO_OS_UART_STOP_1_BIT
static inline uint32_t _calc_uart_xfer_time(uint32_t len, uint32_t baudrate)
{
uint32_t ms = 1000ul * len * 8 / UART_BAUDRATE_DEFAULT;
ms += ms / 10; // overhead
return ms;
}
#if !defined(LINUX_PLATFORM) && !defined(NO_OS_NETWORKING) && !defined(NO_OS_USB_UART)
static int32_t iio_print_uart_info_message(struct no_os_uart_desc **uart_desc,
struct no_os_uart_init_param *user_uart_params,
char *message, int32_t msglen)
{
int32_t status;
uint32_t delay_ms;
status = no_os_uart_write(*uart_desc, (uint8_t *)message, msglen);
if (status < 0)
return status;
delay_ms = _calc_uart_xfer_time(msglen, UART_BAUDRATE_DEFAULT);
no_os_mdelay(delay_ms);
/** Reinitialize UART with parameters required by the IIO application */
no_os_uart_remove(*uart_desc);
return no_os_uart_init(uart_desc, user_uart_params);
}
#endif
static int32_t print_uart_hello_message(struct no_os_uart_desc **uart_desc,
struct no_os_uart_init_param *user_uart_params)
{
#if defined(LINUX_PLATFORM) || defined(NO_OS_NETWORKING) || defined(NO_OS_LWIP_NETWORKING) || defined(NO_OS_USB_UART)
return 0;
#else
const char *uart_data_size[] = { "5", "6", "7", "8", "9" };
const char *uart_parity[] = { "none", "mark", "space", "odd", "even" };
const char *uart_stop[] = { "1", "2" };
char message[512];
uint32_t msglen = sprintf(message,
"Running IIOD server...\n"
"If successful, you may connect an IIO client application by:\n"
"1. Disconnecting the serial terminal you use to view this message.\n"
"2. Connecting the IIO client application using the serial backend configured as shown:\n"
"\tBaudrate: %lu\n"
"\tData size: %s bits\n"
"\tParity: %s\n"
"\tStop bits: %s\n"
"\tFlow control: none\n",
user_uart_params->baud_rate,
uart_data_size[user_uart_params->size],
uart_parity[user_uart_params->parity],
uart_stop[user_uart_params->stop]);
return iio_print_uart_info_message(uart_desc, user_uart_params,
message, msglen);
#endif
}
static int32_t print_uart_error_message(struct no_os_uart_desc **uart_desc,
struct no_os_uart_init_param *user_uart_params,
int32_t status)
{
char message[512];
uint32_t msglen = sprintf(message,
"IIOD server failed with code %d.\n",
(int)status);
#if defined(LINUX_PLATFORM) || defined(NO_OS_NETWORKING) || defined(NO_OS_LWIP_NETWORKING) || defined(NO_OS_USB_UART)
(void)msglen;
printf("%s", message);
return 0;
#else
return iio_print_uart_info_message(uart_desc, user_uart_params,
message, msglen);
#endif
}
#if defined(NO_OS_LWIP_NETWORKING)
static int32_t lwip_network_setup(struct iio_app_desc *app,
struct iio_app_init_param param,
struct iio_init_param *iio_init_param)
{
static struct tcp_socket_init_param socket_param;
static struct lwip_network_desc lwip_desc;
static bool is_initialized = false;
int ret;
if (NO_OS_LWIP_INIT_ONETIME && is_initialized) {
socket_param.net = &lwip_desc.no_os_net;
} else {
ret = no_os_lwip_init(&app->lwip_desc, &param.lwip_param);
if (ret)
return ret;
socket_param.net = &app->lwip_desc->no_os_net;
memcpy(&lwip_desc, app->lwip_desc, sizeof(lwip_desc));
}
is_initialized = true;
socket_param.max_buff_size = 0;
iio_init_param->phy_type = USE_NETWORK;
iio_init_param->tcp_socket_init_param = &socket_param;
return 0;
}
#endif
#if defined(NO_OS_NETWORKING) || defined(LINUX_PLATFORM)
static int32_t network_setup(struct iio_init_param *iio_init_param,
struct no_os_uart_desc *uart_desc,
void *irq_desc)
{
static struct tcp_socket_init_param socket_param;
#ifdef LINUX_PLATFORM
socket_param.net = &linux_net;
#endif
#ifdef ADUCM_PLATFORM
int32_t status;
static struct wifi_desc *wifi;
struct wifi_init_param wifi_param = {
.irq_desc = irq_desc,
.uart_desc = uart_desc,
.uart_irq_conf = uart_desc,
.uart_irq_id = UART_IRQ_ID,
.sw_reset_en = true
};
status = wifi_init(&wifi, &wifi_param);
if (status < 0)
return status;
status = wifi_connect(wifi, WIFI_SSID, WIFI_PWD);
if (status < 0)
return status;
char buff[100];
wifi_get_ip(wifi, buff, 100);
printf("iiod ip is: %s\n", buff);
wifi_get_network_interface(wifi, &socket_param.net);
#endif
socket_param.max_buff_size = 0;
iio_init_param->phy_type = USE_NETWORK;
iio_init_param->tcp_socket_init_param = &socket_param;
return 0;
}
#endif
static int32_t uart_setup(struct no_os_uart_desc **uart_desc,
struct no_os_uart_init_param *uart_init_par)
{
#if defined(LINUX_PLATFORM) || defined(NO_OS_LWIP_NETWORKING)
*uart_desc = NULL;
return 0;
#endif
struct no_os_uart_init_param luart_par = {
.device_id = uart_init_par->device_id,
/* TODO: remove this ifdef when asynchrounous rx is implemented on every platform. */
#if defined(STM32_PLATFORM) || defined(MAXIM_PLATFORM) || defined(ADUCM_PLATFORM) || defined(PICO_PLATFORM)
.irq_id = uart_init_par->irq_id,
.asynchronous_rx = true,
#endif
.baud_rate = UART_BAUDRATE_DEFAULT,
.size = NO_OS_UART_CS_8,
.parity = NO_OS_UART_PAR_NO,
.stop = NO_OS_UART_STOP_1_BIT,
.platform_ops = uart_init_par->platform_ops,
#ifndef ADUCM_PLATFORM
.extra = uart_init_par->extra
#endif
};
return no_os_uart_init(uart_desc, &luart_par);
}
#if defined(ADUCM_PLATFORM) || (defined(STM32_PLATFORM)) || defined(MAXIM_PLATFORM)
static int32_t irq_setup(struct no_os_irq_ctrl_desc **irq_desc)
{
int32_t status;
#if defined(ADUCM_PLATFORM)
void *platform_irq_init_par = NULL;
const struct no_os_irq_platform_ops *platform_irq_ops = &aducm_irq_ops;
#elif defined(STM32_PLATFORM)
void *platform_irq_init_par = NULL;
const struct no_os_irq_platform_ops *platform_irq_ops = &stm32_irq_ops;
#elif defined(MAXIM_PLATFORM)
void *platform_irq_init_par = NULL;
const struct no_os_irq_platform_ops *platform_irq_ops = &max_irq_ops;
#endif
struct no_os_irq_init_param irq_init_param = {
.irq_ctrl_id = INTC_DEVICE_ID,
.platform_ops = platform_irq_ops,
.extra = platform_irq_init_par
};
status = no_os_irq_ctrl_init(irq_desc, &irq_init_param);
if (status < 0)
return status;
return no_os_irq_global_enable(*irq_desc);
}
#endif
/**
* @brief Register devices for an iio application
*
* Configuration for communication is done in parameters.h
* @param app - the iio application descriptor
* @param app_init_param - the iio application initialization parameters
* @return 0 on success, negative value otherwise
*/
int iio_app_init(struct iio_app_desc **app,
struct iio_app_init_param app_init_param)
{
struct iio_device_init *iio_init_devs = NULL;
struct iio_init_param iio_init_param;
struct no_os_uart_desc *uart_desc;
struct iio_app_desc *application;
struct iio_data_buffer *buff;
unsigned int i;
int status;
void *irq_desc = app_init_param.irq_desc;
application = (struct iio_app_desc *)no_os_calloc(1, sizeof(*application));
if (!application)
return -ENOMEM;
application->post_step_callback = app_init_param.post_step_callback;
application->arg = app_init_param.arg;
#if defined(ADUCM_PLATFORM) || defined(STM32_PLATFORM)
/* Only one irq controller can exist and be initialized in
* any of the iio_devices. */
for (i = 0; i < app_init_param.nb_devices; i++) {
if (app_init_param.devices[i].dev_descriptor->irq_desc) {
irq_desc = (struct no_os_irq_ctrl_desc *)
app_init_param.devices[i].dev_descriptor->irq_desc;
break;
}
}
if (!irq_desc) {
status = irq_setup((struct no_os_irq_ctrl_desc **)&irq_desc);
if (status < 0)
return status;
}
#endif
status = uart_setup(&uart_desc, &app_init_param.uart_init_params);
if (status < 0)
goto error_uart;
status = print_uart_hello_message(&uart_desc,
&app_init_param.uart_init_params);
if (status < 0)
goto error;
application->uart_desc = uart_desc;
#if defined(NO_OS_LWIP_NETWORKING)
status = lwip_network_setup(application, app_init_param, &iio_init_param);
if (status)
goto error;
#elif defined(NO_OS_NETWORKING) || defined(LINUX_PLATFORM)
status = network_setup(&iio_init_param, uart_desc, application->irq_desc);
if (status < 0)
goto error;
#else
iio_init_param.phy_type = USE_UART;
iio_init_param.uart_desc = uart_desc;
#endif
iio_init_devs = no_os_calloc(app_init_param.nb_devices, sizeof(*iio_init_devs));
if (!iio_init_devs) {
status = -ENOMEM;
goto error;
}
for (i = 0; i < app_init_param.nb_devices; ++i) {
/*
* iio_app_device is from iio_app.h and we don't want to include
* this in iio.h.
* At the moment iio_device_init has the same parameters but
* it will change.
* When changes are done in iio. iio_app_device may be removed
*iio_init_param and use iio_device_init instead.
* This way faster changes can be done without changing all
* project for each change.
*/
iio_init_devs[i].name = app_init_param.devices[i].name;
iio_init_devs[i].dev = app_init_param.devices[i].dev;
iio_init_devs[i].dev_descriptor = app_init_param.devices[i].dev_descriptor;
iio_init_devs[i].trigger_id = app_init_param.devices[i].default_trigger_id;
buff = app_init_param.devices[i].read_buff ?
app_init_param.devices[i].read_buff :
app_init_param.devices[i].write_buff;
if (buff) {
iio_init_devs[i].raw_buf = buff->buff;
iio_init_devs[i].raw_buf_len = buff->size;
} else {
iio_init_devs[i].raw_buf = NULL;
iio_init_devs[i].raw_buf_len = 0;
}
}
iio_init_param.devs = iio_init_devs;
iio_init_param.nb_devs = app_init_param.nb_devices;
iio_init_param.trigs = app_init_param.trigs;
iio_init_param.nb_trigs = app_init_param.nb_trigs;
iio_init_param.ctx_attrs = app_init_param.ctx_attrs;
iio_init_param.nb_ctx_attr = app_init_param.nb_ctx_attr;
status = iio_init(&application->iio_desc, &iio_init_param);
if (status < 0)
goto error;
no_os_free(iio_init_devs);
*app = application;
return 0;
error_uart:
/** We might have to reinit UART, settings might have changed for IIO */
uart_setup(&uart_desc, &app_init_param.uart_init_params);
error:
no_os_free(iio_init_devs);
no_os_free(application);
print_uart_error_message(&uart_desc, &app_init_param.uart_init_params, status);
no_os_uart_remove(uart_desc);
return status;
}
/**
* @brief Start an IIO application
*
* Configuration for communication is done through iio_app_init_param
* @param app - the iio application parameters
* @return 0 on success, negative value otherwise
*/
int iio_app_run(struct iio_app_desc *app)
{
int status;
do {
status = iio_step(app->iio_desc);
if (status && status != -EAGAIN && status != -ENOTCONN
&& status != -NO_OS_EOVERRUN)
return status;
if (app->post_step_callback) {
status = app->post_step_callback(app->arg);
if (status)
return status;
}
} while (true);
}
/**
* @brief Remove resources allocated by the IIO application
*
* Configuration for communication is done through iio_app_init_param
* @param app - the iio application parameters
* @return 0 on success, negative value otherwise
*/
int iio_app_remove(struct iio_app_desc *app)
{
int ret;
#if defined(ADUCM_PLATFORM) || (defined(XILINX_PLATFORM) && !defined(PLATFORM_MB)) || defined(STM32_PLATFORM)
ret = no_os_irq_ctrl_remove(app->irq_desc);
if (ret)
return ret;
#endif
if (app->uart_desc) {
ret = no_os_uart_remove(app->uart_desc);
if (ret)
return ret;
}
ret = iio_remove(app->iio_desc);
if (ret)
return ret;
no_os_free(app);
return 0;
}
#endif
@@ -0,0 +1,138 @@
/***************************************************************************//**
* @file iio_app.h
* @brief Header file of iio_app
* @author Mihail Chindris (mihail.chindris@analog.com)
********************************************************************************
* Copyright 2013(c) Analog Devices, Inc.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* 3. Neither the name of Analog Devices, Inc. nor the names of its
* contributors may be used to endorse or promote products derived from this
* software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY ANALOG DEVICES, INC. “AS IS” AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
* EVENT SHALL ANALOG DEVICES, INC. BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
* OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
* EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*******************************************************************************/
#ifndef IIO_APP
#define IIO_APP
#include "iio.h"
#include "no_os_irq.h"
#include "no_os_uart.h"
#include "no_os_error.h"
#include "no_os_delay.h"
#if defined(NO_OS_LWIP_NETWORKING)
#include "lwip_socket.h"
#endif
#define IIO_APP_DEVICE(_name, _dev, _dev_descriptor, _read_buff, _write_buff, _default_trigger_id) {\
.name = _name,\
.dev = _dev,\
.dev_descriptor = _dev_descriptor,\
.read_buff = _read_buff,\
.write_buff = _write_buff,\
.default_trigger_id = _default_trigger_id\
}
#define IIO_APP_TRIGGER(_name, _trig, _trig_descriptor) {\
.name = _name,\
.trig = _trig,\
.descriptor = _trig_descriptor,\
}
struct iio_data_buffer {
uint32_t size;
void *buff;
};
struct iio_app_device {
char *name;
void *dev;
struct iio_device *dev_descriptor;
struct iio_data_buffer *read_buff;
struct iio_data_buffer *write_buff;
char *default_trigger_id;
};
/**
* @struct iio_app_desc
* @brief IIO application descriptor.
*/
struct iio_app_desc {
/** UART descriptor to be used */
struct no_os_uart_desc *uart_desc;
/** IRQ descriptor to be used */
void *irq_desc;
/** IIO descriptor to be returned */
struct iio_desc *iio_desc;
/** Function to be called each step */
int (*post_step_callback)(void *arg);
/** Function parameteres */
void *arg;
#ifdef NO_OS_LWIP_NETWORKING
struct lwip_network_desc *lwip_desc;
#endif
};
/**
* @struct iio_app_init_param
* @brief IIO application descriptor initialization parameters.
*/
struct iio_app_init_param {
/** Array of context attribute name/value pairs */
struct iio_ctx_attr *ctx_attrs;
/** Number of context attributes in the array above */
uint32_t nb_ctx_attr;
/** Array of IIO devices */
struct iio_app_device *devices;
/** Number of devices */
uint32_t nb_devices;
/** IIO triggers to be used */
struct iio_trigger_init *trigs;
/** Number of triggers to be used */
int32_t nb_trigs;
/** UART init params */
struct no_os_uart_init_param uart_init_params;
/** IRQ descriptor to be used */
void *irq_desc;
/** Function to be called each step */
int (*post_step_callback)(void *arg);
/** Function parameteres */
void *arg;
#ifdef NO_OS_LWIP_NETWORKING
struct lwip_network_param lwip_param;
#endif
};
/** Register devices for an IIO application */
int iio_app_init(struct iio_app_desc **app,
struct iio_app_init_param app_init_param);
/** Start an IIO application */
int iio_app_run(struct iio_app_desc *app);
/** Remove resources allocated by the IIO application */
int iio_app_remove(struct iio_app_desc *app);
#endif
@@ -0,0 +1,227 @@
/***************************************************************************//**
* @file iio_trigger.c
* @brief Implementation of generic iio trigger.
* @author RBolboac (ramona.bolboaca@analog.com)
********************************************************************************
* Copyright 2022(c) Analog Devices, Inc.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* 3. Neither the name of Analog Devices, Inc. nor the names of its
* contributors may be used to endorse or promote products derived from this
* software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY ANALOG DEVICES, INC. “AS IS” AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
* EVENT SHALL ANALOG DEVICES, INC. BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
* OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
* EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include <stdlib.h>
#include <string.h>
#include "no_os_error.h"
#include "no_os_alloc.h"
#include "iio.h"
#include "iio_trigger.h"
#ifndef LINUX_PLATFORM
/**
* @brief Initialize hardware trigger.
*
* @param iio_trig - The iio trigger structure.
* @param init_param - The structure that contains the trigger initial params.
*
* @return ret - Result of the initialization procedure.
*/
int iio_hw_trig_init(struct iio_hw_trig **iio_trig,
struct iio_hw_trig_init_param *init_param)
{
struct iio_hw_trig *trig_desc;
int ret;
if (!init_param->name)
return -EINVAL;
trig_desc = (struct iio_hw_trig*)no_os_calloc(1, sizeof(*trig_desc));
if (!trig_desc)
return -ENOMEM;
trig_desc->iio_desc = init_param->iio_desc;
strncpy(trig_desc->name, init_param->name, TRIG_MAX_NAME_SIZE);
trig_desc->irq_ctrl = init_param->irq_ctrl;
trig_desc->irq_id = init_param->irq_id;
trig_desc->irq_trig_lvl = init_param->irq_trig_lvl;
struct no_os_callback_desc irq_cb = {
.callback = iio_hw_trig_handler,
.ctx = trig_desc,
.event = init_param->cb_info.event,
.handle = init_param->cb_info.handle,
.peripheral = init_param->cb_info.peripheral
};
ret = no_os_irq_register_callback(trig_desc->irq_ctrl,
trig_desc->irq_id, &irq_cb);
if (ret)
goto error;
if (init_param->cb_info.event == NO_OS_EVT_GPIO) {
ret = no_os_irq_trigger_level_set(trig_desc->irq_ctrl,
trig_desc->irq_id, trig_desc->irq_trig_lvl);
if (ret)
goto error;
}
*iio_trig = trig_desc;
return 0;
error:
no_os_free(trig_desc);
return ret;
}
/**
* @brief Enable system interrupt which is linked to the given trigger.
*
* @param trig - Trigger structure.
*
* @return ret - Result of the enable procedure.
*/
int iio_trig_enable(void *trig)
{
if (!trig)
return -EINVAL;
struct iio_hw_trig *desc = trig;
return no_os_irq_enable(desc->irq_ctrl, desc->irq_id);
}
/**
* @brief Disable system interrupt which is linked to the given trigger.
*
* @param trig - Trigger structure.
*
* @return ret - Result of the disable procedure.
*/
int iio_trig_disable(void *trig)
{
if (!trig)
return -EINVAL;
struct iio_hw_trig *desc = trig;
return no_os_irq_disable(desc->irq_ctrl, desc->irq_id);
}
/**
* @brief Trigger interrupt handler. This function will be called when a system
* interrupt is asserted for the configured trigger.
*
* @param trig - Trigger structure which is linked to this handler.
*/
void iio_hw_trig_handler(void *trig)
{
if (!trig)
return;
struct iio_hw_trig *desc = trig;
iio_process_trigger_type(desc->iio_desc, desc->name);
}
/**
* @brief Free the resources allocated by iio_hw_trig_init().
*
* @param trig - The trigger structure.
*
* @return ret - Result of the remove procedure.
*/
int iio_hw_trig_remove(struct iio_hw_trig *trig)
{
if (trig)
no_os_free(trig);
return 0;
}
#endif
/**
* @brief Initialize software trigger.
*
* @param iio_trig - The iio trigger structure.
* @param init_param - The structure that contains the sw trigger initial params.
*
* @return ret - Result of the initialization procedure.
*/
int iio_sw_trig_init(struct iio_sw_trig **iio_trig,
struct iio_sw_trig_init_param *init_param)
{
struct iio_sw_trig *trig_desc;
if (!init_param->iio_desc || !init_param->name)
return -EINVAL;
trig_desc = (struct iio_sw_trig*)no_os_calloc(1, sizeof(*trig_desc));
if (!trig_desc)
return -ENOMEM;
trig_desc->iio_desc = init_param->iio_desc;
strncpy(trig_desc->name, init_param->name, TRIG_MAX_NAME_SIZE);
*iio_trig = trig_desc;
return 0;
}
/**
* @brief Handles the write request for trigger_now attribute.
*
* @param trig - The iio trigger structure.
* @param buf - Command buffer to be filled with the data to be written.
* @param len - Length of the received command buffer in bytes.
* @param channel - Command channel info (is NULL).
* @param priv - Command attribute id.
*
* @return ret - Result of the sw trigger handler procedure.
*/
int iio_sw_trig_handler(void *trig, char *buf, uint32_t len,
const struct iio_ch_info *channel,
intptr_t priv)
{
if (!trig)
return -EINVAL;
struct iio_sw_trig *desc = trig;
return iio_process_trigger_type(desc->iio_desc, desc->name);
}
/**
* @brief Free the resources allocated by iio_sw_trig_init().
*
* @param trig - The trigger structure.
*
* @return ret - Result of the remove procedure.
*/
int iio_sw_trig_remove(struct iio_sw_trig *trig)
{
if (trig)
no_os_free(trig);
return 0;
}
@@ -0,0 +1,138 @@
/***************************************************************************//**
* @file iio_trigger.h
* @brief Header file for iio_trigger.
* @author RBolboac(ramona.bolboaca@analog.com)
********************************************************************************
* Copyright 2022(c) Analog Devices, Inc.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* 3. Neither the name of Analog Devices, Inc. nor the names of its
* contributors may be used to endorse or promote products derived from this
* software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY ANALOG DEVICES, INC. “AS IS” AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
* EVENT SHALL ANALOG DEVICES, INC. BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
* OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
* EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*******************************************************************************/
#ifndef IIO_TRIGGER_H_
#define IIO_TRIGGER_H_
#include "iio.h"
#include "iio_types.h"
#include "no_os_irq.h"
#define TRIG_MAX_NAME_SIZE 20
/**
* @struct iio_hw_trig
* @brief IIO hardware trigger structure
*/
struct iio_hw_trig {
/** IIO descriptor */
struct iio_desc *iio_desc;
/** Interrupt descriptor to be linked with the trigger */
struct no_os_irq_ctrl_desc *irq_ctrl;
/** Interrupt id to be linked with the trigger */
uint32_t irq_id;
/** Interrupt trigger level */
enum no_os_irq_trig_level irq_trig_lvl;
/** Device trigger name */
char name[TRIG_MAX_NAME_SIZE + 1];
};
/**
* @struct iio_hw_trig_cb_info
* @brief Hardware trigger callback extra information structure
*/
struct iio_hw_trig_cb_info {
/** Platform specific event that triggers the calling of the callback. */
enum no_os_irq_event event;
/** Interrupt source peripheral specifier. */
enum no_os_irq_peripheral peripheral;
/** This will be used to store HAL specific descriptors */
void *handle;
};
/**
* @struct iio_hw_trig_init_param
* @brief IIO hardware trigger initialization structure
*/
struct iio_hw_trig_init_param {
/** IIO descriptor */
struct iio_desc *iio_desc;
/** Interrupt descriptor to be linked with the trigger */
struct no_os_irq_ctrl_desc *irq_ctrl;
/** Interrupt id to be linked with the trigger */
uint32_t irq_id;
/** Interrupt trigger level */
enum no_os_irq_trig_level irq_trig_lvl;
/** Additional interrupt callback information */
struct iio_hw_trig_cb_info cb_info;
/** Device trigger name */
const char *name;
};
/**
* @struct iio_sw_trig
* @brief IIO software trigger structure
*/
struct iio_sw_trig {
/** IIO descriptor */
struct iio_desc *iio_desc;
/** Device trigger name */
char name[TRIG_MAX_NAME_SIZE + 1];
};
/**
* @struct iio_sw_trig_init_param
* @brief IIO software trigger initialization structure
*/
struct iio_sw_trig_init_param {
/** IIO descriptor */
struct iio_desc *iio_desc;
/** Device trigger name */
const char *name;
};
#ifndef LINUX_PLATFORM
/** API to initialize a hardware trigger */
int iio_hw_trig_init(struct iio_hw_trig **iio_trig,
struct iio_hw_trig_init_param *init_param);
/** API to enable a hardware trigger */
int iio_trig_enable(void *trig);
/** API to disable a hardware trigger */
int iio_trig_disable(void *trig);
/** API for hardware trigger handler */
void iio_hw_trig_handler(void *trig);
/** API to remove a hardware trigger */
int iio_hw_trig_remove(struct iio_hw_trig *trig);
#endif
/** API to initialize a software trigger */
int iio_sw_trig_init(struct iio_sw_trig **iio_trig,
struct iio_sw_trig_init_param *init_param);
/** API for software trigger handler */
int iio_sw_trig_handler(void *trig, char *buf, uint32_t len,
const struct iio_ch_info *channel,
intptr_t priv);
/** API to remove a software trigger */
int iio_trig_remove(struct iio_sw_trig *trig);
#endif /* IIO_TRIGGER_H_ */
@@ -0,0 +1,280 @@
/***************************************************************************//**
* @file iio_types.h
* @brief Header file for iio_types
* @author Cristian Pop (cristian.pop@analog.com)
********************************************************************************
* Copyright 2013(c) Analog Devices, Inc.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* 3. Neither the name of Analog Devices, Inc. nor the names of its
* contributors may be used to endorse or promote products derived from this
* software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY ANALOG DEVICES, INC. “AS IS” AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
* EVENT SHALL ANALOG DEVICES, INC. BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
* OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
* EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*******************************************************************************/
#ifndef IIO_TYPES_H_
#define IIO_TYPES_H_
#include <stdbool.h>
#include <stdint.h>
#include "no_os_circular_buffer.h"
enum iio_val {
IIO_VAL_INT = 1,
IIO_VAL_INT_PLUS_MICRO,
IIO_VAL_INT_PLUS_NANO,
IIO_VAL_INT_PLUS_MICRO_DB,
IIO_VAL_INT_MULTIPLE,
IIO_VAL_FRACTIONAL = 10,
IIO_VAL_FRACTIONAL_LOG2,
IIO_VAL_CHAR
};
/**
* @struct iio_chan_type
* @brief IIO channel types
*/
enum iio_chan_type {
IIO_VOLTAGE,
IIO_CURRENT,
IIO_ALTVOLTAGE,
IIO_ANGL_VEL,
IIO_TEMP,
IIO_CAPACITANCE,
IIO_ACCEL,
IIO_RESISTANCE,
IIO_MAGN,
IIO_INCLI,
IIO_VELOCITY,
IIO_ANGL,
IIO_ROT,
IIO_COUNT,
IIO_DELTA_ANGL,
IIO_DELTA_VELOCITY,
IIO_WEIGHT,
};
/**
* @struct iio_modifier
* @brief IIO channel modifier
*/
enum iio_modifier {
IIO_NO_MOD,
IIO_MOD_X,
IIO_MOD_Y,
IIO_MOD_Z,
IIO_MOD_TEMP_AMBIENT,
IIO_MOD_PITCH,
IIO_MOD_YAW,
IIO_MOD_ROLL,
};
/**
* @struct iio_ch_info
* @brief Structure holding channel attributess.
*/
struct iio_ch_info {
/** Channel number. TODO: refactor out the ch_ prefix. */
int16_t ch_num;
/** Channel direction: input/output. TODO: refactor out the ch_ prefix. */
bool ch_out;
/** Channel type */
enum iio_chan_type type;
/** Differential channel indicator */
bool differential;
/** Driver specific identifier. */
uint32_t address;
};
#define END_ATTRIBUTES_ARRAY {.name = NULL}
enum iio_attribute_shared {
IIO_SEPARATE,
IIO_SHARED_BY_TYPE,
IIO_SHARED_BY_DIR,
IIO_SHARED_BY_ALL,
};
/**
* @struct iio_attribute
* @brief Structure holding pointers to show and store functions.
*/
struct iio_attribute {
/** Attribute name */
const char *name;
/** Attribute id */
intptr_t priv;
/** Whether this attribute is shared by all channels of the same type, or direction
* or simply by all channels. If left uninitialized, the sharedness defaults to
* separate.
*/
enum iio_attribute_shared shared;
/** Show function pointer */
int (*show)(void *device, char *buf, uint32_t len,
const struct iio_ch_info *channel, intptr_t priv);
/** Store function pointer */
int (*store)(void *device, char *buf, uint32_t len,
const struct iio_ch_info *channel, intptr_t priv);
};
/**
* @struct iio_channel
* @brief Struct describing the scan type
*/
struct scan_type {
/** 's' or 'u' to specify signed or unsigned */
char sign;
/** Number of valid bits of data */
uint8_t realbits;
/** Realbits + padding */
uint8_t storagebits;
/** Shift right by this before masking out realbits. */
uint8_t shift;
/** True if big endian, false if little endian */
bool is_big_endian;
};
/**
* @struct iio_channel
* @brief Structure holding attributes of a channel.
*/
struct iio_channel {
/** Channel name */
const char *name;
/** Chanel type */
enum iio_chan_type ch_type;
/** Channel number when the same channel type */
int channel;
/** If modified is set, this provides the modifier. E.g. IIO_MOD_X
* for angular rate when applied to channel2 will make make the
* IIO_ANGL_VEL have anglvel_x which corresponds to the x-axis. */
int channel2;
/** Driver specific identifier. */
unsigned long address;
/** Index to give ordering in scans when read from a buffer. */
int scan_index;
/** */
struct scan_type *scan_type;
/** Array of attributes. Last one should have its name set to NULL */
struct iio_attribute *attributes;
/** if true, the channel is an output channel */
bool ch_out;
/** Set if channel has a modifier. Use channel2 property to
* select the modifier to use.*/
bool modified;
/** Specify if channel has a numerical index. If not set, channel
* number will be suppressed. */
bool indexed;
/* Set if the channel is differential. */
bool diferential;
};
enum iio_buffer_direction {
IIO_DIRECTION_INPUT,
IIO_DIRECTION_OUTPUT
};
struct iio_cyclic_buffer_info {
bool is_cyclic;
uint32_t buff_index;
};
struct iio_buffer {
/* Mask with active channels */
uint32_t active_mask;
/* Size in bytes */
uint32_t size;
/* Number of bytes per sample * number of active channels */
uint32_t bytes_per_scan;
/* Number of requested samples */
uint32_t samples;
/* Buffer direction */
enum iio_buffer_direction dir;
/* Buffer where data is stored */
struct no_os_circular_buffer *buf;
/* Stores cyclic buffer specific information */
struct iio_cyclic_buffer_info cyclic_info;
};
struct iio_device_data {
void *dev;
struct iio_buffer *buffer;
};
struct iio_trigger {
/** If true the trigger handler will be called in interrupt context
* If false the handler will be called from iio_step */
bool is_synchronous;
/** Array of attributes. Last one should have its name set to NULL */
struct iio_attribute *attributes;
/** Called when needs to be enabled */
int (*enable)(void *trig);
/** Called when needs to be disabled */
int (*disable)(void *trig);
};
/**
* @struct iio_device
* @brief Structure holding channels and attributes of a device.
*/
struct iio_device {
/** Structure for existing initialized irq controllers. Has to be
* set to NULL if there isn't any irq controller initialized. */
struct no_os_irq_ctrl_desc *irq_desc;
/** Device number of channels */
uint16_t num_ch;
/** List of channels */
struct iio_channel *channels;
/** Array of attributes. Last one should have its name set to NULL */
struct iio_attribute *attributes;
/** Array of attributes. Last one should have its name set to NULL */
struct iio_attribute *debug_attributes;
/** Array of attributes. Last one should have its name set to NULL */
struct iio_attribute *buffer_attributes;
/* Numbers of bytes will be:
* samples * (storage_size_of_first_active_ch / 8) * nb_active_channels
* DEPRECATED.
*/
int32_t (*read_dev)(void *dev, void *buff, uint32_t nb_samples);
/* Numbers of bytes will be:
* samples * (storage_size_of_first_active_ch / 8) * nb_active_channels
* DEPRECATED.
*/
int32_t (*write_dev)(void *dev, void *buff, uint32_t nb_samples);
/* Bufer callbacks */
/** Called before enabling buffer */
int32_t (*pre_enable)(void *dev, uint32_t mask);
/** Called after disabling buffer */
int32_t (*post_disable)(void *dev);
/** Called when buffer ready to transfer. Write/read to/from dev */
int32_t (*submit)(struct iio_device_data *dev);
/** Called after a trigger signal has been received by iio */
int32_t (*trigger_handler)(struct iio_device_data *dev);
/* Read device register */
int32_t (*debug_reg_read)(void *dev, uint32_t reg, uint32_t *readval);
/* Write device register */
int32_t (*debug_reg_write)(void *dev, uint32_t reg, uint32_t writeval);
};
#endif /* IIO_TYPES_H_ */
@@ -0,0 +1,927 @@
/***************************************************************************//**
* @file iiod.c
* @brief Nonblocking implementation of iiod.
* @author Mihail Chindris (mihail.chindris@analog.com)
********************************************************************************
* Copyright 2022(c) Analog Devices, Inc.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* 3. Neither the name of Analog Devices, Inc. nor the names of its
* contributors may be used to endorse or promote products derived from this
* software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY ANALOG DEVICES, INC. “AS IS” AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
* EVENT SHALL ANALOG DEVICES, INC. BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
* OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
* EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*******************************************************************************/
#include <inttypes.h>
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
#include <assert.h>
#include "iiod.h"
#include "iiod_private.h"
#include "no_os_error.h"
#include "no_os_util.h"
#define SET_DUMMY_IF_NULL(func, dummy) ((func) ? (func) : (dummy))
static char delim[] = " \r\n";
static const char *attr_types_strs[] = {
[IIO_ATTR_TYPE_DEBUG] = "DEBUG",
[IIO_ATTR_TYPE_BUFFER] = "BUFFER",
[IIO_ATTR_TYPE_CH_OUT] = "OUTPUT",
[IIO_ATTR_TYPE_CH_IN] = "INPUT"
};
static struct iiod_str cmds[] = {
[IIOD_CMD_HELP] = IIOD_STR("HELP"),
[IIOD_CMD_EXIT] = IIOD_STR("EXIT"),
[IIOD_CMD_PRINT] = IIOD_STR("PRINT"),
[IIOD_CMD_VERSION] = IIOD_STR("VERSION"),
[IIOD_CMD_TIMEOUT] = IIOD_STR("TIMEOUT"),
[IIOD_CMD_OPEN] = IIOD_STR("OPEN"),
[IIOD_CMD_CLOSE] = IIOD_STR("CLOSE"),
[IIOD_CMD_READ] = IIOD_STR("READ"),
[IIOD_CMD_WRITE] = IIOD_STR("WRITE"),
[IIOD_CMD_READBUF] = IIOD_STR("READBUF"),
[IIOD_CMD_WRITEBUF] = IIOD_STR("WRITEBUF"),
[IIOD_CMD_GETTRIG] = IIOD_STR("GETTRIG"),
[IIOD_CMD_SETTRIG] = IIOD_STR("SETTRIG"),
[IIOD_CMD_SET] = IIOD_STR("SET")
};
static const uint32_t priority_array[] = {
/* Order not tested, just personal expectation. Function can
* be improved, this improvement is chosen for simplicity */
IIOD_CMD_READBUF,
IIOD_CMD_WRITEBUF,
IIOD_CMD_READ,
IIOD_CMD_WRITE,
IIOD_CMD_OPEN,
IIOD_CMD_CLOSE,
IIOD_CMD_PRINT,
IIOD_CMD_EXIT,
IIOD_CMD_TIMEOUT,
IIOD_CMD_VERSION,
IIOD_CMD_GETTRIG,
IIOD_CMD_SETTRIG,
IIOD_CMD_HELP,
IIOD_CMD_SET
};
static_assert(NO_OS_ARRAY_SIZE(cmds) == NO_OS_ARRAY_SIZE(priority_array),
"Arrays must have the same size");
/* Set res->cmd to corresponding cmd and return the processed length of buf */
static int32_t parse_cmd(const char *token, struct comand_desc *res)
{
uint32_t i;
struct iiod_str *cmd;
if (!token)
return -EINVAL;
for (i = 0; i < NO_OS_ARRAY_SIZE(cmds); ++i) {
cmd = &cmds[priority_array[i]];
if (strcmp(token, cmd->str) == 0) {
res->cmd = priority_array[i];
return 0;
}
}
return -EINVAL;
}
static int32_t parse_num(const char *token, uint32_t *res, uint32_t base)
{
char *end_ptr;
*res = strtoul(token, &end_ptr, base);
if (*res == 0 && *end_ptr != '\0')
return -EINVAL;
return 0;
}
static int32_t iiod_parse_open(const char *token, struct comand_desc *res,
char **ctx)
{
int32_t ret;
if (!token)
return -EINVAL;
ret = parse_num(token, &res->sample_count, 10);
if (NO_OS_IS_ERR_VALUE(ret))
return ret;
token = strtok_r(NULL, delim, ctx);
if (!token)
return -EINVAL;
ret = parse_num(token, &res->mask, 16);
if (NO_OS_IS_ERR_VALUE(ret))
return ret;
res->cyclic = 0;
token = strtok_r(NULL, delim, ctx);
if (token) {
if (strcmp(token, "CYCLIC") == 0)
res->cyclic = 1;
else
return -EINVAL;
}
return 0;
}
static int32_t iiod_parse_set(const char *token, struct comand_desc *res,
char **ctx)
{
if (!token)
return -EINVAL;
if (strcmp(token, "BUFFERS_COUNT"))
return -EINVAL;
token = strtok_r(NULL, delim, ctx);
if (!token)
return -EINVAL;
return parse_num(token, &res->count, 10);
}
static int32_t iiod_parse_rw_attr(const char *token, struct comand_desc *res,
char **ctx)
{
int32_t i;
res->type = IIO_ATTR_TYPE_DEVICE;
if (token) {
for (i = 0; i < IIO_ATTR_TYPE_DEVICE; ++i) {
if (strcmp(token, attr_types_strs[i]) == 0) {
token = strtok_r(NULL, delim, ctx);
res->type = i;
break;
}
}
}
if (res->type == IIO_ATTR_TYPE_CH_IN ||
res->type == IIO_ATTR_TYPE_CH_OUT) {
if (!token)
return -EINVAL;
strncpy(res->channel, token, sizeof(res->channel));
token = strtok_r(NULL, delim, ctx);
}
if (res->cmd == IIOD_CMD_WRITE) {
if (!token)
return -EINVAL;
if (*token >= '0' && *token <= '9') {
memset(res->attr, 0, sizeof(res->attr));
return parse_num(token, &res->bytes_count, 10);
}
strncpy(res->attr, token, sizeof(res->attr));
token = strtok_r(NULL, delim, ctx);
if (!token)
return -EINVAL;
return parse_num(token, &res->bytes_count, 10);
}
if (token)
strncpy(res->attr, token, sizeof(res->attr));
else
memset(res->attr, 0, sizeof(res->attr));
return 0;
}
int32_t iiod_parse_line(char *buf, struct comand_desc *res, char **ctx)
{
int32_t ret;
char *token;
token = strtok_r(buf, delim, ctx);
ret = parse_cmd(token, res);
if (NO_OS_IS_ERR_VALUE(ret))
return ret;
token = strtok_r(NULL, delim, ctx);
/* Commands without device */
switch (res->cmd) {
case IIOD_CMD_HELP:
case IIOD_CMD_EXIT:
case IIOD_CMD_PRINT:
case IIOD_CMD_VERSION:
return 0;
case IIOD_CMD_TIMEOUT:
return parse_num(token, &res->timeout, 10);
default:
break;
}
strncpy(res->device, token, sizeof(res->device));
token = strtok_r(NULL, delim, ctx);
switch (res->cmd) {
case IIOD_CMD_CLOSE:
case IIOD_CMD_GETTRIG:
return 0;
case IIOD_CMD_OPEN:
return iiod_parse_open(token, res, ctx);
case IIOD_CMD_READ:
case IIOD_CMD_WRITE:
return iiod_parse_rw_attr(token, res, ctx);
case IIOD_CMD_READBUF:
case IIOD_CMD_WRITEBUF:
return parse_num(token, &res->bytes_count, 10);
case IIOD_CMD_SETTRIG:
if (token)
strncpy(res->trigger, token, sizeof(res->trigger));
else
memset(res->trigger, 0, sizeof(res->trigger));
return 0;
case IIOD_CMD_SET:
return iiod_parse_set(token, res, ctx);
default:
break;
}
return -EINVAL;
}
static int dummy_open(struct iiod_ctx *ctx, const char *device,
uint32_t samples, uint32_t mask, bool cyclic)
{
return -EINVAL;
}
static int dummy_close(struct iiod_ctx *ctx, const char *device)
{
return -EINVAL;
}
static int dummy_rw_attr(struct iiod_ctx *ctx, const char *device,
struct iiod_attr *attr, char *buf, uint32_t len)
{
return -EINVAL;
}
static int dummy_rd_data(struct iiod_ctx *ctx, const char *device, char *buf,
uint32_t bytes)
{
return -EINVAL;
}
static int dummy_wr_data(struct iiod_ctx *ctx, const char *device,
const char *trig, uint32_t bytes)
{
return -EINVAL;
}
static int dummy_set_timeout(struct iiod_ctx *ctx, uint32_t timeout)
{
return -EINVAL;
}
static int dummy_set_buffers_count(struct iiod_ctx *ctx, const char *device,
uint32_t buffers_count)
{
return -EINVAL;
}
int32_t iiod_copy_ops(struct iiod_ops *ops, struct iiod_ops *new_ops)
{
if (!new_ops->recv || !new_ops->send)
return -EINVAL;
ops->recv = new_ops->recv;
ops->send = new_ops->send;
ops->open = SET_DUMMY_IF_NULL(new_ops->open, dummy_open);
ops->close = SET_DUMMY_IF_NULL(new_ops->close, dummy_close);
ops->read_buffer = SET_DUMMY_IF_NULL(new_ops->read_buffer, dummy_rd_data);
ops->write_buffer = SET_DUMMY_IF_NULL(new_ops->write_buffer, dummy_wr_data);
ops->read_attr = SET_DUMMY_IF_NULL(new_ops->read_attr, dummy_rw_attr);
ops->write_attr = SET_DUMMY_IF_NULL(new_ops->write_attr, dummy_rw_attr);
ops->get_trigger = SET_DUMMY_IF_NULL(new_ops->get_trigger, dummy_rd_data);
ops->set_trigger = SET_DUMMY_IF_NULL(new_ops->set_trigger, dummy_wr_data);
ops->set_timeout = SET_DUMMY_IF_NULL(new_ops->set_timeout, dummy_set_timeout);
ops->set_buffers_count = SET_DUMMY_IF_NULL(new_ops->set_buffers_count,
dummy_set_buffers_count);
ops->refill_buffer = SET_DUMMY_IF_NULL(new_ops->refill_buffer,
dummy_close);
ops->push_buffer = SET_DUMMY_IF_NULL(new_ops->push_buffer,
dummy_close);
return 0;
}
int32_t iiod_init(struct iiod_desc **desc, struct iiod_init_param *param)
{
struct iiod_desc *ldesc;
int32_t ret;
if (!desc || !param || !param->ops)
return -EINVAL;
ldesc = (struct iiod_desc *)calloc(1, sizeof(*ldesc));
if (!ldesc)
return -ENOMEM;
ret = iiod_copy_ops(&ldesc->ops, param->ops);
if (NO_OS_IS_ERR_VALUE(ret)) {
free(ldesc);
return ret;
}
ldesc->xml = param->xml;
ldesc->xml_len = param->xml_len;
ldesc->app_instance = param->instance;
ldesc->phy_type = param->phy_type;
*desc = ldesc;
return 0;
}
void iiod_remove(struct iiod_desc *desc)
{
free(desc);
}
static void conn_clean_state(struct iiod_conn_priv *conn)
{
memset(&conn->cmd_data, 0, sizeof(conn->cmd_data));
memset(&conn->res, 0, sizeof(conn->res));
memset(&conn->nb_buf, 0, sizeof(conn->nb_buf));
conn->res.buf.buf = NULL;
conn->res.buf.idx = 0;
conn->parser_idx = 0;
conn->state = IIOD_READING_LINE;
}
int32_t iiod_conn_add(struct iiod_desc *desc, struct iiod_conn_data *data,
uint32_t *new_conn_id)
{
uint32_t i;
struct iiod_conn_priv *conn;
if (!desc || !new_conn_id)
return -EINVAL;
for (i = 0; i < IIOD_MAX_CONNECTIONS; ++i)
if (!desc->conns[i].used) {
conn = &desc->conns[i];
memset(conn, 0, sizeof(*conn));
conn->used = 1;
conn->conn = data->conn;
/*
* TODO in future:
* think of using other buffer (e.g. ciruclar_buffer)
* to somehow implement zero copy
*/
conn->payload_buf = data->buf;
conn->payload_buf_len = data->len;
*new_conn_id = i;
return 0;
}
return -EBUSY;
}
int32_t iiod_conn_remove(struct iiod_desc *desc, uint32_t conn_id,
struct iiod_conn_data *data)
{
if (!desc || conn_id > IIOD_MAX_CONNECTIONS ||
!desc->conns[conn_id].used)
return -EINVAL;
struct iiod_conn_priv *conn;
conn = &desc->conns[conn_id];
data->conn = conn->conn;
data->len = conn->payload_buf_len;
data->buf = conn->payload_buf;
conn->used = 0;
return 0;
}
static int32_t call_op(struct iiod_ops *ops, struct comand_desc *data,
struct iiod_ctx *ctx)
{
switch (data->cmd) {
case IIOD_CMD_HELP:
return -EINVAL;
case IIOD_CMD_TIMEOUT:
return ops->set_timeout(ctx, data->timeout);
case IIOD_CMD_OPEN:
return ops->open(ctx, data->device, data->sample_count,
data->mask, data->cyclic);
case IIOD_CMD_CLOSE:
return ops->close(ctx, data->device);
case IIOD_CMD_SETTRIG:
return ops->set_trigger(ctx, data->device, data->trigger,
strlen(data->trigger));
case IIOD_CMD_SET:
return ops->set_buffers_count(ctx, data->device, data->count);
default:
break;
}
return -EINVAL;
}
/*
* Unload data from buf without blocking.
* When done will return 0, if there is still data to be sent it will return
* -EAGIAN. On error, an negative error code is returned
*/
static int32_t rw_iiod_buff(struct iiod_desc *desc, struct iiod_conn_priv *conn,
struct iiod_buff *buf, uint8_t flags)
{
struct iiod_ctx ctx = IIOD_CTX(desc, conn);
uint8_t *tmp_buf;
int32_t ret;
int32_t len;
len = buf->len - buf->idx;
if (len) {
tmp_buf = (uint8_t *)buf->buf + buf->idx;
if (flags & IIOD_WR)
ret = desc->ops.send(&ctx, tmp_buf, len);
else
ret = desc->ops.recv(&ctx, tmp_buf, len);
if (NO_OS_IS_ERR_VALUE(ret))
return ret;
buf->idx += ret;
if (ret < len)
return -EAGAIN;
}
if (flags & IIOD_ENDL) {
ret = desc->ops.send(&ctx, (uint8_t *)"\n", 1);
if (NO_OS_IS_ERR_VALUE(ret))
return ret;
if (ret != 1)
return -EAGAIN;
}
return 0;
}
static int32_t do_read_buff_delayed(struct iiod_desc *desc,
struct iiod_conn_priv *conn)
{
struct iiod_ctx ctx = IIOD_CTX(desc, conn);
uint32_t max_to_read;
int32_t ret, len;
conn->nb_buf.buf = conn->payload_buf;
len = no_os_min(conn->payload_buf_len, conn->cmd_data.bytes_count);
max_to_read = len - conn->nb_buf.len;
ret = desc->ops.read_buffer(&ctx, conn->cmd_data.device,
conn->nb_buf.buf + conn->nb_buf.len, max_to_read);
if (ret < 0)
return ret;
conn->nb_buf.len += ret;
if (conn->nb_buf.len < conn->cmd_data.bytes_count)
return -EAGAIN;
ret = rw_iiod_buff(desc, conn, &conn->nb_buf, IIOD_WR);
if (ret < 0)
return ret;
conn->nb_buf.len = 0;
conn->nb_buf.idx = 0;
return 0;
}
static int32_t do_read_buff(struct iiod_desc *desc, struct iiod_conn_priv *conn)
{
struct iiod_ctx ctx;
int32_t ret, len;
/*
* When using the network backend wait for a whole buffer to be filled
* before sending in order to reduce the ammount of network traffic.
*/
if (desc->phy_type == USE_NETWORK)
return do_read_buff_delayed(desc, conn);
ctx = (struct iiod_ctx)IIOD_CTX(desc, conn);
if (conn->nb_buf.len == 0) {
conn->nb_buf.buf = conn->payload_buf;
len = no_os_min(conn->payload_buf_len,
conn->cmd_data.bytes_count);
/* Read from dev */
ret = desc->ops.read_buffer(&ctx, conn->cmd_data.device,
conn->nb_buf.buf, len);
if (NO_OS_IS_ERR_VALUE(ret))
return ret;
len = ret;
conn->nb_buf.len = len;
conn->nb_buf.idx = 0;
}
if (conn->nb_buf.idx < conn->nb_buf.len) {
/* Write on conn */
ret = rw_iiod_buff(desc, conn, &conn->nb_buf, IIOD_WR);
if (NO_OS_IS_ERR_VALUE(ret))
return ret;
conn->cmd_data.bytes_count -= conn->nb_buf.len;
conn->nb_buf.len = 0;
if (conn->cmd_data.bytes_count)
return -EAGAIN;
}
return 0;
}
static int32_t do_write_buff(struct iiod_desc *desc,
struct iiod_conn_priv *conn)
{
struct iiod_ctx ctx = IIOD_CTX(desc, conn);
int32_t ret, len;
if (conn->nb_buf.len == 0) {
conn->nb_buf.buf = conn->payload_buf;
len = no_os_min(conn->payload_buf_len,
conn->cmd_data.bytes_count);
conn->nb_buf.len = len;
conn->nb_buf.idx = 0;
}
if (conn->nb_buf.idx < conn->nb_buf.len) {
/* Read from conn */
ret = rw_iiod_buff(desc, conn, &conn->nb_buf, IIOD_RD);
if (NO_OS_IS_ERR_VALUE(ret))
return ret;
}
/* Write to dev */
ret = desc->ops.write_buffer(&ctx, conn->cmd_data.device,
conn->nb_buf.buf, conn->nb_buf.len);
if (NO_OS_IS_ERR_VALUE(ret))
return ret;
conn->cmd_data.bytes_count -= conn->nb_buf.len;
conn->nb_buf.len = 0;
if (conn->cmd_data.bytes_count)
return -EAGAIN;
return 0;
}
static int32_t iiod_run_cmd(struct iiod_desc *desc,
struct iiod_conn_priv *conn)
{
struct iiod_ctx ctx = IIOD_CTX(desc, conn);
struct comand_desc *data = &conn->cmd_data;
struct iiod_attr attr = {
.type = data->type,
.name = data->attr,
.channel = data->channel
};
int32_t ret;
switch (data->cmd) {
case IIOD_CMD_HELP:
case IIOD_CMD_TIMEOUT:
case IIOD_CMD_OPEN:
case IIOD_CMD_CLOSE:
case IIOD_CMD_SETTRIG:
case IIOD_CMD_SET:
if (data->cmd == IIOD_CMD_OPEN) {
conn->mask = data->mask;
if (data->cyclic)
conn->is_cyclic_buffer = true;
}
if (data->cmd == IIOD_CMD_CLOSE)
/* Set is_cyclic_buffer to false every time the device is closed */
conn->is_cyclic_buffer = false;
conn->res.val = call_op(&desc->ops, data, &ctx);
conn->res.write_val = 1;
break;
case IIOD_CMD_EXIT:
conn->res.val = 0;
conn->res.write_val = 1;
return -ENOTCONN;
case IIOD_CMD_PRINT:
conn->res.val = desc->xml_len;
conn->res.write_val = 1;
conn->res.buf.buf = desc->xml;
conn->res.buf.len = desc->xml_len;
break;
case IIOD_CMD_VERSION:
conn->res.buf.buf = IIOD_VERSION;
conn->res.buf.len = IIOD_VERSION_LEN;
break;
case IIOD_CMD_READ:
case IIOD_CMD_GETTRIG:
if (data->cmd == IIOD_CMD_READ)
ret = desc->ops.read_attr(&ctx, data->device, &attr,
conn->payload_buf,
conn->payload_buf_len);
else
ret = desc->ops.get_trigger(&ctx, data->device,
conn->payload_buf,
conn->payload_buf_len);
conn->res.val = ret;
conn->res.write_val = 1;
if (!NO_OS_IS_ERR_VALUE(ret)) {
conn->res.buf.buf = conn->payload_buf;
conn->res.buf.len = ret;
}
break;
case IIOD_CMD_WRITE:
conn->payload_buf[data->bytes_count] = '\0';
ret = desc->ops.write_attr(&ctx, data->device, &attr,
conn->payload_buf,
data->bytes_count);
conn->nb_buf.len = 0;
conn->res.val = ret;
conn->res.write_val = 1;
break;
case IIOD_CMD_READBUF:
conn->res.write_val = 1;
ret = desc->ops.refill_buffer(&ctx, data->device);
if (NO_OS_IS_ERR_VALUE(ret)) {
conn->res.val = ret;
break;
}
conn->res.val = data->bytes_count;
ret = snprintf(conn->buf_mask, 10, "%08"PRIx32, conn->mask);
conn->res.buf.buf = conn->buf_mask;
conn->res.buf.len = ret;
break;
case IIOD_CMD_WRITEBUF:
conn->res.val = data->bytes_count;
conn->res.write_val = 1;
break;
default:
return -EINVAL;
}
return 0;
}
static int32_t iiod_read_line(struct iiod_desc *desc,
struct iiod_conn_priv *conn)
{
struct iiod_ctx ctx = {
.instance = desc->app_instance,
.conn = conn->conn
};
int32_t ret;
char *ch;
while (conn->parser_idx < IIOD_PARSER_MAX_BUF_SIZE - 1) {
ch = conn->parser_buf + conn->parser_idx;
ret = desc->ops.recv(&ctx, (uint8_t *)ch, 1);
if (ret == -EAGAIN || ret == 0)
return -EAGAIN;
if (NO_OS_IS_ERR_VALUE(ret))
goto end;
if (conn->parser_idx == 0 && (*ch == '\n' || *ch == '\r'))
continue ;
++conn->parser_idx;
if (*ch == '\n') {
conn->parser_buf[conn->parser_idx] = '\0';
ret = 0;
goto end;
}
}
ret = -EIO;
end:
conn->parser_idx = 0;
return ret;
}
/*
* Function will return SUCCESS when a state was processed.
* If a state is still in processing state, it will return -EAGAIN.
* If other error occur. E.g. Connection errors, they are returned and
* the connection must be cleaned up.
*/
static int32_t iiod_run_state(struct iiod_desc *desc,
struct iiod_conn_priv *conn)
{
struct iiod_ctx ctx = {
.instance = desc->app_instance,
.conn = conn->conn
};
int32_t ret;
switch (conn->state) {
case IIOD_READING_LINE:
/* Read input data until \n. I/O Calls */
ret = iiod_read_line(desc, conn);
if (NO_OS_IS_ERR_VALUE(ret))
return ret;
/* Fill struct comand_desc with data from line. No I/O */
ret = iiod_parse_line(conn->parser_buf, &conn->cmd_data,
&conn->strtok_ctx);
if (NO_OS_IS_ERR_VALUE(ret)) {
/* Parsing line failed */
conn->res.write_val = 1;
conn->res.val = ret;
conn->state = IIOD_WRITING_CMD_RESULT;
} else if (conn->cmd_data.cmd == IIOD_CMD_WRITE) {
/* Special case. Attribute needs to be read */
conn->nb_buf.buf = conn->payload_buf;
conn->nb_buf.len = conn->cmd_data.bytes_count;
conn->nb_buf.idx = 0;
conn->state = IIOD_READING_WRITE_DATA;
} else {
conn->state = IIOD_RUNNING_CMD;
}
return 0;
case IIOD_RUNNING_CMD:
/* Execute or call necessary ops depending on cmd. No I/O */
ret = iiod_run_cmd(desc, conn);
if (NO_OS_IS_ERR_VALUE(ret))
return ret;
conn->state = IIOD_WRITING_CMD_RESULT;
return 0;
case IIOD_WRITING_CMD_RESULT:
/* Write result or the length of data to be sent*/
if (conn->res.write_val) {
if (conn->nb_buf.len == 0) {
conn->nb_buf.buf = conn->parser_buf;
ret = sprintf(conn->nb_buf.buf, "%"PRIi32,
conn->res.val);
conn->nb_buf.len = ret;
conn->nb_buf.idx = 0;
}
/* Non-blocking. Will enter here until val is sent */
if (conn->nb_buf.idx < conn->nb_buf.len) {
ret = rw_iiod_buff(desc, conn, &conn->nb_buf,
IIOD_WR | IIOD_ENDL);
if (NO_OS_IS_ERR_VALUE(ret))
return ret;
}
}
/* Send buf from result. Non blocking */
if (conn->res.buf.buf &&
conn->res.buf.idx < conn->res.buf.len) {
ret = rw_iiod_buff(desc, conn, &conn->res.buf,
IIOD_WR | IIOD_ENDL);
if (NO_OS_IS_ERR_VALUE(ret))
return ret;
}
if (conn->cmd_data.cmd != IIOD_CMD_READBUF &&
conn->cmd_data.cmd != IIOD_CMD_WRITEBUF) {
if (conn->is_cyclic_buffer && conn->cmd_data.cmd != IIOD_CMD_OPEN)
conn->state = IIOD_PUSH_CYCLIC_BUFFER;
else
conn->state = IIOD_LINE_DONE;
} else {
/* Preapre for IIOD_RW_BUF state */
memset(&conn->nb_buf, 0, sizeof(conn->nb_buf));
conn->state = IIOD_RW_BUF;
}
return 0;
case IIOD_RW_BUF:
/* IIOD_CMD_READBUF and IIOD_CMD_WRITEBUF special case */
/* Non blocking read/write until all data is processed */
if (conn->cmd_data.cmd == IIOD_CMD_READBUF)
ret = do_read_buff(desc, conn);
else {
ret = do_write_buff(desc, conn);
if (ret == 0) {
conn->res.write_val = 1;
ret = desc->ops.push_buffer(&ctx,
conn->cmd_data.device);
if (NO_OS_IS_ERR_VALUE(ret)) {
conn->res.val = ret;
conn->state = IIOD_LINE_DONE;
return 0;
}
memset(&conn->res.buf, 0, sizeof(conn->res.buf));
conn->res.val = conn->cmd_data.bytes_count;
conn->cmd_data.cmd = IIOD_CMD_PRINT;
conn->state = IIOD_WRITING_CMD_RESULT;
return 0;
}
}
if (NO_OS_IS_ERR_VALUE(ret))
return ret;
conn->state = IIOD_LINE_DONE;
return 0;
case IIOD_READING_WRITE_DATA:
/* Read attribute */
ret = rw_iiod_buff(desc, conn, &conn->nb_buf, IIOD_RD);
if (NO_OS_IS_ERR_VALUE(ret))
return ret;
conn->state = IIOD_RUNNING_CMD;
return 0;
case IIOD_PUSH_CYCLIC_BUFFER:
/* Push puffer to IIO application */
ret = desc->ops.push_buffer(&ctx,
conn->cmd_data.device);
/* If an error was encountered, close connection */
if (NO_OS_IS_ERR_VALUE(ret)) {
conn->res.val = ret;
desc->ops.close(&ctx, conn->cmd_data.device);
conn->state = IIOD_LINE_DONE;
conn->is_cyclic_buffer = false;
return 0;
}
/* Read data from the client to verify whether a close command has been sent */
ret = iiod_read_line(desc, conn);
if (NO_OS_IS_ERR_VALUE(ret))
return 0;
/* Fill struct comand_desc with data from line */
ret = iiod_parse_line(conn->parser_buf, &conn->cmd_data,
&conn->strtok_ctx);
if (!NO_OS_IS_ERR_VALUE(ret) && conn->cmd_data.cmd == IIOD_CMD_CLOSE) {
/* Exit this state only if a close command is received
All other commands will be ignored.
*/
conn->nb_buf.len = 0;
conn->state = IIOD_RUNNING_CMD;
conn->is_cyclic_buffer = false;
}
return 0;
default:
/* Should never get here */
return -EINVAL;
}
}
int32_t iiod_conn_step(struct iiod_desc *desc, uint32_t conn_id)
{
struct iiod_conn_priv *conn;
int32_t ret;
if (!desc || conn_id > IIOD_MAX_CONNECTIONS ||
!desc->conns[conn_id].used)
return -EINVAL;
conn = &desc->conns[conn_id];
do {
ret = iiod_run_state(desc, conn);
if (ret == -EAGAIN)
return ret;
if (NO_OS_IS_ERR_VALUE(ret) || conn->state == IIOD_LINE_DONE)
break;
//The loop will continue because the state was changed.
} while (true);
conn_clean_state(conn);
return ret;
}
@@ -0,0 +1,192 @@
/***************************************************************************//**
* @file iiod.h
* @brief Header file of iiod
* @author Mihail Chindris (mihail.chindris@analog.com)
********************************************************************************
* Copyright 2022(c) Analog Devices, Inc.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* 3. Neither the name of Analog Devices, Inc. nor the names of its
* contributors may be used to endorse or promote products derived from this
* software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY ANALOG DEVICES, INC. “AS IS” AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
* EVENT SHALL ANALOG DEVICES, INC. BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
* OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
* EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*******************************************************************************/
#ifndef IIOD_H
#define IIOD_H
#include <stdint.h>
#include <stdbool.h>
#include "iio.h"
/* Maximum nomber of iiod connections to allocate simultaneously */
#define IIOD_MAX_CONNECTIONS 10
#define IIOD_VERSION "1.1.0000000"
#define IIOD_VERSION_LEN (sizeof(IIOD_VERSION) - 1)
#define MAX_DEV_ID 64
#define MAX_TRIG_ID 64
#define MAX_CHN_ID 64
#define MAX_ATTR_NAME 256
enum iio_attr_type {
IIO_ATTR_TYPE_DEBUG,
IIO_ATTR_TYPE_BUFFER,
IIO_ATTR_TYPE_CH_OUT,
IIO_ATTR_TYPE_CH_IN,
IIO_ATTR_TYPE_DEVICE,
};
struct iiod_attr {
enum iio_attr_type type;
/*
* Attribute name.
* If empty (""), all attributes of the specified iio_attr_type must
* be read/wrote
*/
const char *name;
const char *channel;
};
struct iiod_ctx {
/* Value specified in iiod_init_param.instance in iiod_init */
void *instance;
/* Value specified in iiod_conn_data.conn in iiod_conn_add */
void *conn;
};
struct iiod_conn_data {
/* Value to be used in iiod_ctx */
void *conn;
/* Buffer to store attributes or buffer data for a connection. */
char *buf;
/* Size of the provided buffer. It must fit the max attribute size */
uint32_t len;
};
/* Functions should return a negative error code on failure */
struct iiod_ops {
/*
* I/O operations
* Send and recv are used to send or receive data to/from a connection.
* They should send/receive the at maximum len bytes.
* They must return the number of bytes sent/received.
* They can return 0 or -EAGAIN when no data was processed.
* They can do not block. They will be called again if there is still
* data to be sent/recevied
*/
int (*send)(struct iiod_ctx *ctx, uint8_t *buf, uint32_t len);
int (*recv)(struct iiod_ctx *ctx, uint8_t *buf, uint32_t len);
/*
* This is the equivalent of libiio iio_device_create_buffer.
* Called in order to create a buffer to read or write data.
* read_buffer or write_buffer will follow with a maximum of samples
* (depending on the internal buffer).
* All calls with the same ctx will refer to this buffer until close is
* called.
*/
int (*open)(struct iiod_ctx *ctx, const char *device, uint32_t samples,
uint32_t mask, bool cyclic);
/* Equivalent of iio_buffer_destroy */
int (*close)(struct iiod_ctx *ctx, const char *device);
/* Read data from opened buffer */
int (*read_buffer)(struct iiod_ctx *ctx, const char *device, char *buf,
uint32_t bytes);
/* Called to notify that buffer must be refiiled */
int (*refill_buffer)(struct iiod_ctx *ctx, const char *device);
/* Write data to opened buffer */
int (*write_buffer)(struct iiod_ctx *ctx, const char *device,
const char *buf, uint32_t bytes);
/* Called to notify that buffer must be pushed to hardware */
int (*push_buffer)(struct iiod_ctx *ctx, const char *device);
/*
* Attribute has to be read in buf and return the number of bytes
* written.
*/
int (*read_attr)(struct iiod_ctx *ctx, const char *device,
struct iiod_attr *attr, char *buf, uint32_t len);
/* Attribute buf is filled with the attribute value. */
int (*write_attr)(struct iiod_ctx *ctx, const char *device,
struct iiod_attr *attr, char *buf, uint32_t len);
/* Simular with read_attr but trigger must be filled */
int (*get_trigger)(struct iiod_ctx *ctx, const char *device,
char *trigger, uint32_t len);
/*
* Simular with write_attr but trigger name is in trigger.
* If trigger is equals to "". Trigger must be removed.
*/
int (*set_trigger)(struct iiod_ctx *ctx, const char *device,
const char *trigger, uint32_t len);
/* I don't know what this should be used for :) */
int (*set_timeout)(struct iiod_ctx *ctx, uint32_t timeout);
/* I don't know what this should be used for :) */
int (*set_buffers_count)(struct iiod_ctx *ctx, const char *device,
uint32_t buffers_count);
};
/*
* Internal structure.
* It is created in iiod_init and must be passed to all fucntions
*/
struct iiod_desc;
/* Parameter to initialize iiod_desc */
struct iiod_init_param {
struct iiod_ops *ops;
/* Value to be send in each iiod_ctx from iiod_ops functions */
void *instance;
/*
* Xml description of the context and devices. It should exist until
* iiod_remove is called
*/
char *xml;
/* Size of xml in bytes */
uint32_t xml_len;
/* Backend used by IIOD */
enum physical_link_type phy_type;
};
/* Initialize desc. */
int32_t iiod_init(struct iiod_desc **desc, struct iiod_init_param *param);
/* Remove desc resources */
void iiod_remove(struct iiod_desc *desc);
/*
* Notify iiod about a new connection in order to store context for it.
* new_conn_id is set in order to reference the connection in iiod_conn_step
*/
int32_t iiod_conn_add(struct iiod_desc *desc, struct iiod_conn_data *data,
uint32_t *new_conn_id);
/* Remove conn_id from iiod. Provided data is returned in data */
int32_t iiod_conn_remove(struct iiod_desc *desc, uint32_t conn_id,
struct iiod_conn_data *data);
/* Advance in the state machine of a connection. Will not block */
int32_t iiod_conn_step(struct iiod_desc *desc, uint32_t conn_id);
#endif //IIOD_H
@@ -0,0 +1,178 @@
/***************************************************************************//**
* @file iiod_private.h
* @brief Private header file of iiod
* @author Mihail Chindris (mihail.chindris@analog.com)
********************************************************************************
* Copyright 2022(c) Analog Devices, Inc.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* 3. Neither the name of Analog Devices, Inc. nor the names of its
* contributors may be used to endorse or promote products derived from this
* software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY ANALOG DEVICES, INC. “AS IS” AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
* EVENT SHALL ANALOG DEVICES, INC. BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
* OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
* EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*******************************************************************************/
#ifndef IIOD_PRIVATE_H
#define IIOD_PRIVATE_H
#include "iio.h"
#define IIOD_WR 0x1
#define IIOD_ENDL 0x2
#define IIOD_RD 0x4
#define IIOD_PARSER_MAX_BUF_SIZE 128
#define IIOD_STR(cmd) {(cmd), sizeof(cmd) - 1}
#define IIOD_CTX(desc, conn) {.instance = (desc)->app_instance,\
.conn = (conn)->conn}
/* Used to store a string and its size */
struct iiod_str {
char *str;
uint32_t len;
};
/*
* Commads are the ones documented int the link:
* https://wiki.analog.com/resources/tools-software/linux-software/libiio_internals#the_network_backend_and_iio_daemon
*/
enum iiod_cmd {
IIOD_CMD_HELP,
IIOD_CMD_EXIT,
IIOD_CMD_PRINT,
IIOD_CMD_VERSION,
IIOD_CMD_TIMEOUT,
IIOD_CMD_OPEN,
IIOD_CMD_CLOSE,
IIOD_CMD_READ,
IIOD_CMD_WRITE,
IIOD_CMD_READBUF,
IIOD_CMD_WRITEBUF,
IIOD_CMD_GETTRIG,
IIOD_CMD_SETTRIG,
IIOD_CMD_SET
};
/*
* Structure to be filled after a command is parsed.
* Depending of cmd some fields are set or not
*/
struct comand_desc {
enum iiod_cmd cmd;
uint32_t mask;
uint32_t timeout;
uint32_t sample_count;
uint32_t bytes_count;
uint32_t count;
bool cyclic;
char device[MAX_DEV_ID];
char channel[MAX_CHN_ID];
char attr[MAX_ATTR_NAME];
char trigger[MAX_TRIG_ID];
enum iio_attr_type type;
};
/* Used to store buffer indexes for non blocking transfers */
struct iiod_buff {
char *buf;
uint32_t idx;
uint32_t len;
};
/* Result after executing a command. */
struct iiod_run_cmd_result {
uint32_t val;
/* If set. Val needs to be sent */
bool write_val;
/* If buf.len != 0 buf has to be sent */
struct iiod_buff buf;
};
/* Internal structure to handle a connection state */
struct iiod_conn_priv {
/* User instance of the connection to be sent in iiod_ctx */
void *conn;
/* Unset when can be used from the connection pool */
bool used;
/* Command data after parsed */
struct comand_desc cmd_data;
/* Result of an executed cmd */
struct iiod_run_cmd_result res;
/* IIOD States */
enum {
/* Reading line until \n */
IIOD_READING_LINE,
/* Execut cmd without I/O operations */
IIOD_RUNNING_CMD,
/* Write result of executed cmd */
IIOD_WRITING_CMD_RESULT,
/* I/O operations for READBUF and WRITEBUF cmds */
IIOD_RW_BUF,
/* I/O operations for WRITE cmd */
IIOD_READING_WRITE_DATA,
/* Set when a operation is finalized */
IIOD_LINE_DONE,
/* Pushing cyclic buffer until IIO device is closed */
IIOD_PUSH_CYCLIC_BUFFER,
} state;
/* Buffer to store received line */
char parser_buf[IIOD_PARSER_MAX_BUF_SIZE];
/* Index in parser_buf. For nonblocking operation */
uint32_t parser_idx;
/* Buffer to store raw data (attributes or buffer data).*/
char *payload_buf;
/* Length of payload_buf_len */
uint32_t payload_buf_len;
/* Used in nonbloking transfers to save indexes */
struct iiod_buff nb_buf;
/* Mask of current opened buffer */
uint32_t mask;
/* Buffer to store mask as a string */
char buf_mask[10];
/* Context for strtok_r function */
char *strtok_ctx;
/* True if the device was open with cyclic buffer flag */
bool is_cyclic_buffer;
};
/* Private iiod information */
struct iiod_desc {
/* Pool of iiod connections */
struct iiod_conn_priv conns[IIOD_MAX_CONNECTIONS];
/* Application operations */
struct iiod_ops ops;
/* Application instance */
void *app_instance;
/* Address of xml */
char *xml;
/* XML length in bytes */
uint32_t xml_len;
/* Backend used by IIOD */
enum physical_link_type phy_type;
};
#endif //IIOD_PRIVATE_H
@@ -0,0 +1,295 @@
/**
* The JESD204 framework
*
* Copyright (c) 2022 Analog Devices Inc.
*/
#ifndef _JESD204_H_
#define _JESD204_H_
#include <stdbool.h>
#include <stddef.h>
#include <stdint.h>
struct jesd204_dev;
enum jesd204_subclass {
JESD204_SUBCLASS_0,
JESD204_SUBCLASS_1,
JESD204_SUBCLASS_2,
};
enum jesd204_version {
JESD204_VERSION_A,
JESD204_VERSION_B,
JESD204_VERSION_C,
};
/* JESD204C Supported encoding scheme */
enum jesd204_encoder {
JESD204_ENCODER_UNKNOWN,
JESD204_ENCODER_8B10B,
JESD204_ENCODER_64B66B,
JESD204_ENCODER_64B80B,
JESD204_ENCODER_MAX
};
enum jesd204_sysref_mode {
JESD204_SYSREF_DISABLED,
JESD204_SYSREF_CONTINUOUS,
JESD204_SYSREF_ONESHOT,
};
enum jesd204_state_change_result {
JESD204_STATE_CHANGE_ERROR = -1,
JESD204_STATE_CHANGE_DEFER = 0,
JESD204_STATE_CHANGE_DONE,
};
#define JESD204_LINKS_ALL ((unsigned int)(-1))
#define JESD204_LMFC_OFFSET_UNINITIALIZED ((uint16_t)-1)
/** @struct jesd204_sysref
* @brief JESD204 parameters for SYSREF
* @param mode: SYSREF mode (see jesd204_sysref_mode)
* @param capture_falling_edge: true if it should capture falling edge
* @param valid_falling_edge: true if falling edge should be valid
* @param lmfc_offset: offset for LMFC
*/
struct jesd204_sysref {
enum jesd204_sysref_mode mode;
uint8_t capture_falling_edge;
uint8_t valid_falling_edge;
uint16_t lmfc_offset;
};
/**
* @struct jesd204_link
* @brief JESD204 link configuration settings
* @param link_id: JESD204 link ID provided via DT configuration
* @param error: error code for this JESD204 link
* @param is_transmit: true if this link is transmit (digital to analog)
* @param sample_rate: sample rate for the link
* @param sample_rate_div: optional sample rate divider for the link
* final rate = sample_rate / sample_rate_div
* @param num_lanes: number of JESD204 lanes (L)
* @param num_converters: number of converters per link (M)
* @param octets_per_frame: number of octets per frame (F)
* @param frames_per_multiframe: number of frames per frame (K)
* @param num_of_multiblocks_in_emb: number of multiblocks in extended multiblock (E) (JESD204C)
* @param bits_per_sample: number of bits per sample (N')
* @param converter_resolution: converter resolution (N)
* @param jesd_version: JESD204 version (A, B or C) (JESDV)
* @param jesd_encoder: JESD204C encoder (8B10B, 64B66B, 64B80B)
* @param subclass: JESD204 subclass (0,1 or 2) (SUBCLASSV)
* @param device_id: device ID (DID)
* @param bank_id: bank ID (BID)
* @param scrambling: true if scrambling enabled (SCR)
* @param high_density: true if high-density format is used (HD)
* @param ctrl_words_per_frame_clk: number of control words per frame clock
* period (CF)
* @param ctrl_bits_per_sample: number of control bits per sample (CS)
* @param samples_per_conv_frame: number of samples per converter per frame
* cycle (S)
* @param lane_ids: array of lane IDs (LID); note that this is an
* array the size of num_lanes
* @param sysref: JESD204 sysref config, see jesd204_sysref
* @param dac_adj_resolution_steps: number of adjustment resolution steps to adjust
* DAC LMFC (ADJCNT) - Subclass 2 only
* @param dac_adj_direction: direction to adjust DAC LMFC (ADJDIR)
* Subclass 2 only
* @param dac_phase_adj: true to do phase adjustment request to DAC
* Subclass 2 only
*/
struct jesd204_link {
uint32_t link_id;
int error;
uint64_t sample_rate;
uint32_t sample_rate_div;
bool is_transmit;
uint8_t num_lanes;
uint8_t num_converters;
uint8_t octets_per_frame;
uint16_t frames_per_multiframe;
uint8_t num_of_multiblocks_in_emb; /* E */
uint8_t bits_per_sample;
uint8_t converter_resolution;
uint8_t jesd_version;
uint8_t jesd_encoder;
uint8_t subclass;
uint8_t device_id;
uint8_t bank_id;
uint8_t scrambling;
uint8_t high_density;
uint8_t ctrl_words_per_frame_clk;
uint8_t ctrl_bits_per_sample;
uint8_t samples_per_conv_frame;
uint8_t *lane_ids;
struct jesd204_sysref sysref;
/* Subclass 2 only */
uint8_t dac_adj_resolution_steps;
uint8_t dac_adj_direction;
uint8_t dac_phase_adj;
};
enum jesd204_state_op_reason {
JESD204_STATE_OP_REASON_INIT,
JESD204_STATE_OP_REASON_UNINIT,
};
static inline const char *jesd204_state_op_reason_str(enum
jesd204_state_op_reason reason)
{
switch (reason) {
case JESD204_STATE_OP_REASON_INIT:
return "initialization";
case JESD204_STATE_OP_REASON_UNINIT:
return "uninitialization";
default:
return "unknown";
}
}
typedef int (*jesd204_sysref_cb)(struct jesd204_dev *jdev);
typedef int (*jesd204_dev_cb)(struct jesd204_dev *jdev,
enum jesd204_state_op_reason reason);
typedef int (*jesd204_link_cb)(struct jesd204_dev *jdev,
enum jesd204_state_op_reason,
struct jesd204_link *lnk);
enum jesd204_state_op_mode {
JESD204_STATE_OP_MODE_PER_LINK,
JESD204_STATE_OP_MODE_PER_DEVICE,
};
/**
* @struct jesd204_state_op
* @brief JESD204 device per-state op
* @param mode: mode for this state op, depending on this per_device or per_link is called
* @param per_device: op called for each JESD204 **device** during a transition
* @param per_link op called for each JESD204 **link** individually during a transition
* // FIXME: maybe pass 'struct jesd204_sysref' for post_state_sysref, to make this configurable? we'll see later
* // FIXME: for now, the device should also be a top-level device, in case of multi-chip setups
* @param post_state_sysref: true if a SYSREF should be issued after the state change
*/
struct jesd204_state_op {
enum jesd204_state_op_mode mode;
jesd204_dev_cb per_device;
jesd204_link_cb per_link;
bool post_state_sysref;
};
enum jesd204_dev_op {
JESD204_OP_DEVICE_INIT,
JESD204_OP_LINK_INIT,
JESD204_OP_LINK_SUPPORTED,
JESD204_OP_LINK_PRE_SETUP,
JESD204_OP_CLK_SYNC_STAGE1,
JESD204_OP_CLK_SYNC_STAGE2,
JESD204_OP_CLK_SYNC_STAGE3,
JESD204_OP_LINK_SETUP,
JESD204_OP_OPT_SETUP_STAGE1,
JESD204_OP_OPT_SETUP_STAGE2,
JESD204_OP_OPT_SETUP_STAGE3,
JESD204_OP_OPT_SETUP_STAGE4,
JESD204_OP_OPT_SETUP_STAGE5,
JESD204_OP_CLOCKS_ENABLE,
JESD204_OP_LINK_ENABLE,
JESD204_OP_LINK_RUNNING,
JESD204_OP_OPT_POST_RUNNING_STAGE,
__JESD204_MAX_OPS,
};
/**
* @struct jesd204_dev_data
* @brief JESD204 device initialization data
* @param sysref_cb: SYSREF callback, if this device/driver supports it
* @param sizeof_priv: amount of data to allocate for private information
* @param max_num_links: maximum number of JESD204 links this device can support
* @param num_retries: number of retries in case of error (only for top-level device)
* @param state_ops: ops for each state transition of type @struct jesd204_state_op
*/
struct jesd204_dev_data {
jesd204_sysref_cb sysref_cb;
size_t sizeof_priv;
unsigned int max_num_links;
unsigned int num_retries;
struct jesd204_state_op state_ops[__JESD204_MAX_OPS];
};
/* no-OS specific */
#define JESD204_MAX_TOPOLOGY_LINKS 16
/* no-OS specific */
struct jesd204_topology_dev {
struct jesd204_dev *jdev;
bool is_top_device;
bool is_sysref_provider;
unsigned int link_ids[JESD204_MAX_TOPOLOGY_LINKS];
unsigned int links_number;
};
/* no-OS specific */
struct jesd204_topology {
struct jesd204_dev_top *dev_top;
struct jesd204_topology_dev *devs;
unsigned int devs_number;
};
/* no-OS specific */
int jesd204_dev_register(struct jesd204_dev **jdev,
const struct jesd204_dev_data *dev_data);
/* no-OS specific */
int jesd204_dev_unregister(struct jesd204_dev *jdev);
/* no-OS specific */
int jesd204_topology_init(struct jesd204_topology **topology,
struct jesd204_topology_dev *devs,
unsigned int devs_number);
/* no-OS specific */
int jesd204_topology_remove(struct jesd204_topology *topology);
/* no-OS specific */
int jesd204_fsm_start(struct jesd204_topology *topology, unsigned int link_idx);
/* no-OS specific */
int jesd204_fsm_stop(struct jesd204_topology *topology, unsigned int link_idx);
void *jesd204_dev_priv(struct jesd204_dev *jdev);
int jesd204_link_get_lmfc_lemc_rate(struct jesd204_link *lnk,
unsigned long *rate_hz);
int jesd204_link_get_rate_khz(struct jesd204_link *lnk,
unsigned long *lane_rate_khz);
int jesd204_link_get_device_clock(struct jesd204_link *lnk,
unsigned long *device_clock);
int jesd204_sysref_async(struct jesd204_dev *jdev);
int jesd204_sysref_async_force(struct jesd204_dev *jdev);
bool jesd204_dev_is_top(struct jesd204_dev *jdev);
void jesd204_copy_link_params(struct jesd204_link *dst,
const struct jesd204_link *src);
#endif
@@ -0,0 +1,906 @@
/* USER CODE BEGIN Header */
/**
******************************************************************************
* @file : main.c
* @brief : Main program body
******************************************************************************
* @attention
*
* Copyright (c) 2025 STMicroelectronics.
* All rights reserved.
*
* This software is licensed under terms that can be found in the LICENSE file
* in the root directory of this software component.
* If no LICENSE file comes with this software, it is provided AS-IS.
*
******************************************************************************
*/
/* USER CODE END Header */
/* Includes ------------------------------------------------------------------*/
#include "main.h"
/* Private includes ----------------------------------------------------------*/
/* USER CODE BEGIN Includes */
#include "si5351.h"
#include "parameters.h"
#include "adf4382.h"
#include "adar1000.h"
#include "hardware_config.h"
#include "no_os_delay.h"
#include "no_os_alloc.h"
#include "no_os_print_log.h"
#include "no_os_error.h"
#include "no_os_units.h"
#include "no_os_dma.h"
#include "no_os_spi.h"
#include "no_os_uart.h"
#include "no_os_util.h"
#include <stdint.h>
#include <errno.h>
#include <math.h>
#include <stdio.h>
#include <string.h>
#include <inttypes.h>
#include <iostream>
#include <vector>
/* USER CODE END Includes */
/* Private typedef -----------------------------------------------------------*/
/* USER CODE BEGIN PTD */
#define debug_uart 1
#define BUFFER_SIZE 16 //ADAR
#define Delay_scan 1 //Delay between each TX,RX scan// 1 corresponds to 15.6 ns// check delay_15ns() function
#define Delay_scan_rx 1 //Delay between each TX,RX scan// 1 corresponds to 15.6 ns// check delay_15ns() function
Si5351 si5351;
////////////////////////////////////////////////////////////////////////////////
///////////////////////////////ADF4382//////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////
struct no_os_uart_init_param adf4382_uart_ip = {
.device_id = UART_DEVICE_ID,
.irq_id = UART_IRQ_ID,
.asynchronous_rx = true,
.baud_rate = UART_BAUDRATE,
.size = NO_OS_UART_CS_8,
.parity = NO_OS_UART_PAR_NO,
.stop = NO_OS_UART_STOP_1_BIT,
.platform_ops = UART_OPS,
.extra = UART_EXTRA,
};
struct no_os_spi_init_param adf4382_spi_ip = {
.device_id = SPI_DEVICE_ID,
.max_speed_hz = 4000000,
.chip_select = SPI_CS,
.mode = NO_OS_SPI_MODE_0,
.bit_order = NO_OS_SPI_BIT_ORDER_MSB_FIRST,
.platform_ops = SPI_OPS,
.extra = SPI_EXTRA,
};
struct adf4382_init_param adf4382_ip = {
.spi_init = &adf4382_spi_ip,
.spi_3wire_en = false,
.cmos_3v3 = false,
.ref_freq_hz = 100000000,
.freq = 10500000000ULL,
.ref_doubler_en = 1,
.ref_div = 1,
.cp_i = 15,
.bleed_word = 4903,
.ld_count = 10,
.id = ID_ADF4382A,
};
struct adf4382_dev *adf4382_device = NULL; // Pointer to device
////////////////////////////////////////////////////////////////////////////////
//////////////////////////////ADAR1000//////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////
uint8_t txBuffer[BUFFER_SIZE] = {0xA1, 0xB2, 0xC3, 0xD4}; // Example data
uint8_t rxBuffer1[BUFFER_SIZE] = {0}; // Receive buffer
uint8_t rxBuffer2[BUFFER_SIZE] = {0}; // Receive buffer
uint8_t rxBuffer3[BUFFER_SIZE] = {0}; // Receive buffer
uint8_t rxBuffer4[BUFFER_SIZE] = {0}; // Receive buffer
uint32_t SpiTransferFunction(uint8_t *p_txData, uint8_t *p_rxData, uint32_t size) {
HAL_GPIO_WritePin(GPIO_ADAR, CS_ADAR_1, GPIO_PIN_RESET);
HAL_GPIO_WritePin(GPIO_ADAR, CS_ADAR_2, GPIO_PIN_RESET);
HAL_GPIO_WritePin(GPIO_ADAR, CS_ADAR_3, GPIO_PIN_RESET);
HAL_GPIO_WritePin(GPIO_ADAR, CS_ADAR_4, GPIO_PIN_RESET);
HAL_StatusTypeDef status = HAL_SPI_TransmitReceive(&hspi1, p_txData, p_rxData, size, HAL_MAX_DELAY);
HAL_GPIO_WritePin(GPIO_ADAR, CS_ADAR_1, GPIO_PIN_SET);
HAL_GPIO_WritePin(GPIO_ADAR, CS_ADAR_2, GPIO_PIN_SET);
HAL_GPIO_WritePin(GPIO_ADAR, CS_ADAR_3, GPIO_PIN_SET);
HAL_GPIO_WritePin(GPIO_ADAR, CS_ADAR_4, GPIO_PIN_SET);
return (status == HAL_OK) ? 0 : 1; // Return 0 on success, 1 on failure
}
/// Generic ADAR device that contains a hardware address, SPI transfer function
/// and a pointer to a buffer to receive data into.
// Define the ADAR1000 device instance
const AdarDevice ADAR1 = {
.dev_addr = 0x00, // Example hardware address
.Transfer = SpiTransferFunction, // Assign SPI function pointer
.p_rx_buffer = rxBuffer1 // Assign receive buffer
};
const AdarDevice ADAR2 = {
.dev_addr = 0x01, // Example hardware address
.Transfer = SpiTransferFunction, // Assign SPI function pointer
.p_rx_buffer = rxBuffer2 // Assign receive buffer
};
const AdarDevice ADAR3 = {
.dev_addr = 0x10, // Example hardware address
.Transfer = SpiTransferFunction, // Assign SPI function pointer
.p_rx_buffer = rxBuffer3 // Assign receive buffer
};
const AdarDevice ADAR4 = {
.dev_addr = 0x11, // Example hardware address
.Transfer = SpiTransferFunction, // Assign SPI function pointer
.p_rx_buffer = rxBuffer4 // Assign receive buffer
};
AdarBiasCurrents ADAR_BC ={ //bias current
.rx_lna = 8, ///< nominal: 8, low power: 5
.rx_vm = 5, ///< nominal: 5, low power: 2
.rx_vga = 10, ///< nominal: 10, low power: 3
.tx_vm = 5, ///< nominal: 5, low power: 2
.tx_vga = 5, ///< nominal: 5, low power: 5
.tx_drv = 6 ///< nominal: 6, low power: 3
};
/* USER CODE END PTD */
/* Private define ------------------------------------------------------------*/
/* USER CODE BEGIN PD */
/* USER CODE END PD */
/* Private macro -------------------------------------------------------------*/
/* USER CODE BEGIN PM */
/* USER CODE END PM */
/* Private variables ---------------------------------------------------------*/
I2C_HandleTypeDef hi2c1;
SPI_HandleTypeDef hspi1;
TIM_HandleTypeDef htim1;
UART_HandleTypeDef huart2;
/* USER CODE BEGIN PV */
/* USER CODE END PV */
/* Private function prototypes -----------------------------------------------*/
void SystemClock_Config(void);
static void MX_GPIO_Init(void);
static void MX_I2C1_Init(void);
static void MX_SPI1_Init(void);
static void MX_TIM1_Init(void);
static void MX_USART2_UART_Init(void);
/* USER CODE BEGIN PFP */
void delay_15ns(volatile long unsigned int ns){
__HAL_TIM_SET_COUNTER(&htim1,0); // set the counter value a
while (__HAL_TIM_GET_COUNTER(&htim1) < ns); // //Clock TIMx -> AHB/APB1 is set to 64MHz/presc+1 presc = 0
//delay_15ns(1) would perform a delay of 15.6ns
}
/* USER CODE END PFP */
/* Private user code ---------------------------------------------------------*/
/* USER CODE BEGIN 0 */
/* USER CODE END 0 */
/**
* @brief The application entry point.
* @retval int
*/
int main(void)
{
/* USER CODE BEGIN 1 */
/* USER CODE END 1 */
/* MCU Configuration--------------------------------------------------------*/
/* Reset of all peripherals, Initializes the Flash interface and the Systick. */
HAL_Init();
/* USER CODE BEGIN Init */
/* USER CODE END Init */
/* Configure the system clock */
SystemClock_Config();
/* USER CODE BEGIN SysInit */
/* USER CODE END SysInit */
/* Initialize all configured peripherals */
MX_GPIO_Init();
MX_I2C1_Init();
MX_SPI1_Init();
MX_TIM1_Init();
MX_USART2_UART_Init();
/* USER CODE BEGIN 2 */
HAL_TIM_Base_Start(&htim1);
//////////////////////////////////////////////////////////////////////////////////////
/////////////////////////////////////Votage Enable////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////////////
//3.3V to ADAR should be set before -5V
HAL_GPIO_WritePin(GPIO_VR, EN_32, GPIO_PIN_SET);//active high
HAL_GPIO_WritePin(GPIO_VR, EN_42, GPIO_PIN_SET);//active High
//////////////////////////////////////////////////////////////////////////////////////
/////////////////////////////////////SI5351///////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////////////
si5351.init(SI5351_CRYSTAL_LOAD_8PF, 0, 0);
HAL_GPIO_WritePin(GPIO_si5351, SI5351_CLK_EN, GPIO_PIN_RESET);//active low
HAL_GPIO_WritePin(GPIO_si5351, SI5351_SS_EN, GPIO_PIN_SET);//active High (Spread Spectrum)
//each unity on set_freq(unityULL, SI5351_CLK4) represents 0.01Hz
si5351.set_freq(10000000000ULL, SI5351_CLK4);//set FPGA main clock to 100MHz
si5351.set_freq(10000000000ULL, SI5351_CLK6);//ADF4382 clock
si5351.update_status();
HAL_Delay(500);
if(debug_uart)
{ //When the synthesizers are locked and the Si5351 is working correctly, you'll see an output similar to this one (the REVID may be different):
//SYS_INIT: 0 LOL_A: 0 LOL_B: 0 LOS: 0 REVID: 3
char buffer[10];
HAL_UART_Transmit(&huart2, (uint8_t*)"PLLA: " , strlen("PLLA: ") , 10);
HAL_UART_Transmit(&huart2, (uint8_t*)buffer, sprintf(buffer, "%llu", si5351.plla_freq/100), 10);
HAL_UART_Transmit(&huart2, (uint8_t*)" PLLB: " , strlen(" PLLB: ") , 10);
HAL_UART_Transmit(&huart2, (uint8_t*)buffer, sprintf(buffer, "%llu", si5351.pllb_freq/100), 10);
HAL_UART_Transmit(&huart2, (uint8_t*)" SYS_INIT: " , strlen(" SYS_INIT: ") , 10);
HAL_UART_Transmit(&huart2, (uint8_t*)buffer, sprintf(buffer, "%u", si5351.dev_status.SYS_INIT), 10);
HAL_UART_Transmit(&huart2, (uint8_t*)" LOL_A: " , strlen(" LOL_A: ") , 10);
HAL_UART_Transmit(&huart2, (uint8_t*)buffer, sprintf(buffer, "%u", si5351.dev_status.LOL_A), 10);
HAL_UART_Transmit(&huart2, (uint8_t*)" LOL_B: " , strlen(" LOL_B ") , 10);
HAL_UART_Transmit(&huart2, (uint8_t*)buffer, sprintf(buffer, "%u", si5351.dev_status.LOL_B), 10);
HAL_UART_Transmit(&huart2, (uint8_t*)" LOS: " , strlen(" LOS: ") , 10);
HAL_UART_Transmit(&huart2, (uint8_t*)buffer, sprintf(buffer, "%u", si5351.dev_status.LOS), 10);
HAL_UART_Transmit(&huart2, (uint8_t*)" REVID: " , strlen(" REVID: ") , 10);
HAL_UART_Transmit(&huart2, (uint8_t*)buffer, sprintf(buffer, "%u", si5351.dev_status.REVID), 10);
HAL_UART_Transmit(&huart2, (uint8_t*)"\r\n" , strlen("\r\n" ) , 10);
}
//////////////////////////////////////////////////////////////////////////////////////
/////////////////////////////////////ADF4382//////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////////////
int status = adf4382_init(&adf4382_device ,&adf4382_ip);
if (status != 0) {
// Handle initialization error
}
status = adf4382_set_freq(adf4382_device);
if (status != 0) {
// Handle frequency setting error
}
adf4382_set_en_chan(adf4382_device, 0, true);
adf4382_set_en_chan(adf4382_device, 1, true);
HAL_GPIO_WritePin(GPIO_ADF, ADF_CE, GPIO_PIN_SET);//active High
//HAL_GPIO_WritePin(GPIO_ADF, ADF_DELSTR, GPIO_PIN_SET);
//HAL_GPIO_WritePin(GPIO_ADF, ADF_DELADJ, GPIO_PIN_SET);
//////////////////////////////////////////////////////////////////////////////////////
/////////////////////////////////////LTC5552 Mixers///////////////////////////////////
//////////////////////////////////////////////////////////////////////////////////////
HAL_GPIO_WritePin(GPIO_DIG, DIG_2, GPIO_PIN_SET); //Enable RX Mixer
HAL_GPIO_WritePin(GPIO_DIG, DIG_3, GPIO_PIN_SET); //Enable TX Mixer
//////////////////////////////////////////////////////////////////////////////////////
/////////////////////////////////////ADAR1000/////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////////////
//phase_step = 0 => phase = 0°
//phase_step = 127 => phase = 360°
//steering angle (rad)= arcsin(phase_dif/Pi)
uint8_t matrix1[22][16];
uint8_t vector_0[16]={0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0};
uint8_t matrix2[22][16];
for(int j=0; j<15;j++){
for(int i=0; i<21;i++){
matrix1[i][j]=(2*(i+1)*(15-j))%127;
matrix2[i][j]=matrix1[i][15-j];
i++;
}
j++;
}
Adar_AdcInit(&ADAR1, BROADCAST_OFF);//init. ADC
Adar_AdcInit(&ADAR2, BROADCAST_OFF);//init. ADC
Adar_AdcInit(&ADAR3, BROADCAST_OFF);//init. ADC
Adar_AdcInit(&ADAR4, BROADCAST_OFF);//init. ADC
uint8_t Temp1 = Adar_AdcRead(&ADAR1,BROADCAST_OFF);//Read ADC from single ADAR
uint8_t Temp2 = Adar_AdcRead(&ADAR2,BROADCAST_OFF);
uint8_t Temp3 = Adar_AdcRead(&ADAR3,BROADCAST_OFF);
uint8_t Temp4 = Adar_AdcRead(&ADAR4,BROADCAST_OFF);
if(debug_uart){
char buffer[10];
HAL_UART_Transmit(&huart2, (uint8_t*)"Temp1: " , strlen("Temp1: ") , 10);
HAL_UART_Transmit(&huart2, (uint8_t*)buffer, sprintf(buffer, "%u", Temp1), 10);
HAL_UART_Transmit(&huart2, (uint8_t*)" Temp2: " , strlen(" Temp2: ") , 10);
HAL_UART_Transmit(&huart2, (uint8_t*)buffer, sprintf(buffer, "%u", Temp2), 10);
HAL_UART_Transmit(&huart2, (uint8_t*)" Temp3: " , strlen(" Temp3: ") , 10);
HAL_UART_Transmit(&huart2, (uint8_t*)buffer, sprintf(buffer, "%u", Temp3), 10);
HAL_UART_Transmit(&huart2, (uint8_t*)" Temp4: " , strlen(" Temp4: ") , 10);
HAL_UART_Transmit(&huart2, (uint8_t*)buffer, sprintf(buffer, "%u", Temp4), 10);
HAL_UART_Transmit(&huart2, (uint8_t*)"\r\n" , strlen("\r\n" ) , 10);
}
Adar_SetBiasCurrents(&ADAR1,&ADAR_BC,BROADCAST_OFF);
Adar_SetBiasCurrents(&ADAR2,&ADAR_BC,BROADCAST_OFF);
Adar_SetBiasCurrents(&ADAR3,&ADAR_BC,BROADCAST_OFF);
Adar_SetBiasCurrents(&ADAR4,&ADAR_BC,BROADCAST_OFF);
uint8_t bias_on_voltage [5] = {0x39, 0x39, 0x39, 0x39, 0x00};//V_PA = -1.1V; V_LNA = 0V
uint8_t bias_off_voltage [5] = {0x85, 0x85, 0x85, 0x85, 0x68};//V_PA = -2.5V; V_LNA = -2V
HAL_GPIO_WritePin(GPIO_DIG, DIG_0, GPIO_PIN_RESET);//reset TR pin on FPGA for RX mode
Adar_SetBiasVoltages(&ADAR1, bias_on_voltage, bias_off_voltage);
Adar_SetBiasVoltages(&ADAR2, bias_on_voltage, bias_off_voltage);
Adar_SetBiasVoltages(&ADAR3, bias_on_voltage, bias_off_voltage);
Adar_SetBiasVoltages(&ADAR4, bias_on_voltage, bias_off_voltage);
Adar_SetRxVgaGain(&ADAR1, 1, 16, BROADCAST_OFF);//16dB is the max
Adar_SetRxVgaGain(&ADAR1, 2, 16, BROADCAST_OFF);
Adar_SetRxVgaGain(&ADAR1, 3, 16, BROADCAST_OFF);
Adar_SetRxVgaGain(&ADAR1, 4, 16, BROADCAST_OFF);
Adar_SetRxVgaGain(&ADAR2, 1, 16, BROADCAST_OFF);//16dB is the max
Adar_SetRxVgaGain(&ADAR2, 2, 16, BROADCAST_OFF);
Adar_SetRxVgaGain(&ADAR2, 3, 16, BROADCAST_OFF);
Adar_SetRxVgaGain(&ADAR2, 4, 16, BROADCAST_OFF);
Adar_SetRxVgaGain(&ADAR3, 1, 16, BROADCAST_OFF);//16dB is the max
Adar_SetRxVgaGain(&ADAR3, 2, 16, BROADCAST_OFF);
Adar_SetRxVgaGain(&ADAR3, 3, 16, BROADCAST_OFF);
Adar_SetRxVgaGain(&ADAR3, 4, 16, BROADCAST_OFF);
Adar_SetRxVgaGain(&ADAR4, 1, 16, BROADCAST_OFF);//16dB is the max
Adar_SetRxVgaGain(&ADAR4, 2, 16, BROADCAST_OFF);
Adar_SetRxVgaGain(&ADAR4, 3, 16, BROADCAST_OFF);
Adar_SetRxVgaGain(&ADAR4, 4, 16, BROADCAST_OFF);
Adar_SetTxBias(&ADAR1, BROADCAST_OFF);//set to nominal...check adar1000.c
Adar_SetTxBias(&ADAR2, BROADCAST_OFF);
Adar_SetTxBias(&ADAR3, BROADCAST_OFF);
Adar_SetTxBias(&ADAR4, BROADCAST_OFF);
Adar_SetTxVgaGain(&ADAR1, 1, 0x7D, BROADCAST_OFF);//0xFF = max
Adar_SetTxVgaGain(&ADAR1, 2, 0x7D, BROADCAST_OFF);
Adar_SetTxVgaGain(&ADAR1, 3, 0x7D, BROADCAST_OFF);
Adar_SetTxVgaGain(&ADAR1, 4, 0x7D, BROADCAST_OFF);
Adar_SetTxVgaGain(&ADAR2, 1, 0x7D, BROADCAST_OFF);//0xFF = max
Adar_SetTxVgaGain(&ADAR2, 2, 0x7D, BROADCAST_OFF);
Adar_SetTxVgaGain(&ADAR2, 3, 0x7D, BROADCAST_OFF);
Adar_SetTxVgaGain(&ADAR2, 4, 0x7D, BROADCAST_OFF);
Adar_SetTxVgaGain(&ADAR3, 1, 0x7D, BROADCAST_OFF);//0xFF = max
Adar_SetTxVgaGain(&ADAR3, 2, 0x7D, BROADCAST_OFF);
Adar_SetTxVgaGain(&ADAR3, 3, 0x7D, BROADCAST_OFF);
Adar_SetTxVgaGain(&ADAR3, 4, 0x7D, BROADCAST_OFF);
Adar_SetTxVgaGain(&ADAR4, 1, 0x7D, BROADCAST_OFF);//0xFF = max
Adar_SetTxVgaGain(&ADAR4, 2, 0x7D, BROADCAST_OFF);
Adar_SetTxVgaGain(&ADAR4, 3, 0x7D, BROADCAST_OFF);
Adar_SetTxVgaGain(&ADAR4, 4, 0x7D, BROADCAST_OFF);
/* USER CODE END 2 */
/* Infinite loop */
/* USER CODE BEGIN WHILE */
while (1)
{
//////////////////////////////////////////////////////////////////////////////////////
/////////////////////////////////////ADAR1000/////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////////////
//phase_step = 0 => phase = 0°
//phase_step = 127 => phase = 360°
//steering angle (rad)= arcsin(phase_dif/Pi)
HAL_GPIO_WritePin(GPIO_DIG, DIG_1, GPIO_PIN_SET); // Send to FPGA_FT2232HQ start frame from ADC Matrix
HAL_Delay(1);
HAL_GPIO_WritePin(GPIO_DIG, DIG_1, GPIO_PIN_RESET); // Send to FPGA_FT2232HQ start frame from ADC Matrix
for(int i = 0; i<21; i++){
Adar_SetTxPhase(&ADAR1,1 ,matrix1[i][0] , BROADCAST_OFF);
Adar_SetTxPhase(&ADAR1,2 ,matrix1[i][1] , BROADCAST_OFF);
Adar_SetTxPhase(&ADAR1,3 ,matrix1[i][2] , BROADCAST_OFF);
Adar_SetTxPhase(&ADAR1,4 ,matrix1[i][3] , BROADCAST_OFF);
Adar_SetTxPhase(&ADAR2,1 ,matrix1[i][4] , BROADCAST_OFF);
Adar_SetTxPhase(&ADAR2,2 ,matrix1[i][5] , BROADCAST_OFF);
Adar_SetTxPhase(&ADAR2,3 ,matrix1[i][6] , BROADCAST_OFF);
Adar_SetTxPhase(&ADAR2,4 ,matrix1[i][7] , BROADCAST_OFF);
Adar_SetTxPhase(&ADAR3,1 ,matrix1[i][8] , BROADCAST_OFF);
Adar_SetTxPhase(&ADAR3,2 ,matrix1[i][9] , BROADCAST_OFF);
Adar_SetTxPhase(&ADAR3,3 ,matrix1[i][10] , BROADCAST_OFF);
Adar_SetTxPhase(&ADAR3,4 ,matrix1[i][11] , BROADCAST_OFF);
Adar_SetTxPhase(&ADAR4,1 ,matrix1[i][12] , BROADCAST_OFF);
Adar_SetTxPhase(&ADAR4,2 ,matrix1[i][13] , BROADCAST_OFF);
Adar_SetTxPhase(&ADAR4,3 ,matrix1[i][14] , BROADCAST_OFF);
Adar_SetTxPhase(&ADAR4,4 ,matrix1[i][15] , BROADCAST_OFF);
HAL_GPIO_WritePin(GPIO_DIG, DIG_0, GPIO_PIN_SET);//set TR pin on FPGA for TX mode
HAL_GPIO_TogglePin(GPIO_LED, LED_1);
delay_15ns(Delay_scan);
Adar_SetRxPhase(&ADAR1,1 ,matrix1[i][0] , BROADCAST_OFF);
Adar_SetRxPhase(&ADAR1,2 ,matrix1[i][1] , BROADCAST_OFF);
Adar_SetRxPhase(&ADAR1,3 ,matrix1[i][2] , BROADCAST_OFF);
Adar_SetRxPhase(&ADAR1,4 ,matrix1[i][3] , BROADCAST_OFF);
Adar_SetRxPhase(&ADAR2,1 ,matrix1[i][4] , BROADCAST_OFF);
Adar_SetRxPhase(&ADAR2,2 ,matrix1[i][5] , BROADCAST_OFF);
Adar_SetRxPhase(&ADAR2,3 ,matrix1[i][6] , BROADCAST_OFF);
Adar_SetRxPhase(&ADAR2,4 ,matrix1[i][7] , BROADCAST_OFF);
Adar_SetRxPhase(&ADAR3,1 ,matrix1[i][8] , BROADCAST_OFF);
Adar_SetRxPhase(&ADAR3,2 ,matrix1[i][9] , BROADCAST_OFF);
Adar_SetRxPhase(&ADAR3,3 ,matrix1[i][10] , BROADCAST_OFF);
Adar_SetRxPhase(&ADAR3,4 ,matrix1[i][11] , BROADCAST_OFF);
Adar_SetRxPhase(&ADAR4,1 ,matrix1[i][12] , BROADCAST_OFF);
Adar_SetRxPhase(&ADAR4,2 ,matrix1[i][13] , BROADCAST_OFF);
Adar_SetRxPhase(&ADAR4,3 ,matrix1[i][14] , BROADCAST_OFF);
Adar_SetRxPhase(&ADAR4,4 ,matrix1[i][15] , BROADCAST_OFF);
HAL_GPIO_WritePin(GPIO_DIG, DIG_0, GPIO_PIN_RESET);//reset TR pin on FPGA for RX mode
HAL_GPIO_TogglePin(GPIO_LED, LED_2);
delay_15ns(Delay_scan_rx);
}
for(int i = 0; i<15; i++){
Adar_SetTxPhase(&ADAR1,1 ,vector_0[0] , BROADCAST_OFF);
Adar_SetTxPhase(&ADAR1,2 ,vector_0[1] , BROADCAST_OFF);
Adar_SetTxPhase(&ADAR1,3 ,vector_0[2] , BROADCAST_OFF);
Adar_SetTxPhase(&ADAR1,4 ,vector_0[3] , BROADCAST_OFF);
Adar_SetTxPhase(&ADAR2,1 ,vector_0[4] , BROADCAST_OFF);
Adar_SetTxPhase(&ADAR2,2 ,vector_0[5] , BROADCAST_OFF);
Adar_SetTxPhase(&ADAR2,3 ,vector_0[6] , BROADCAST_OFF);
Adar_SetTxPhase(&ADAR2,4 ,vector_0[7] , BROADCAST_OFF);
Adar_SetTxPhase(&ADAR3,1 ,vector_0[8] , BROADCAST_OFF);
Adar_SetTxPhase(&ADAR3,2 ,vector_0[9] , BROADCAST_OFF);
Adar_SetTxPhase(&ADAR3,3 ,vector_0[10] , BROADCAST_OFF);
Adar_SetTxPhase(&ADAR3,4 ,vector_0[11] , BROADCAST_OFF);
Adar_SetTxPhase(&ADAR4,1 ,vector_0[12] , BROADCAST_OFF);
Adar_SetTxPhase(&ADAR4,2 ,vector_0[13] , BROADCAST_OFF);
Adar_SetTxPhase(&ADAR4,3 ,vector_0[14] , BROADCAST_OFF);
Adar_SetTxPhase(&ADAR4,4 ,vector_0[15] , BROADCAST_OFF);
HAL_GPIO_WritePin(GPIO_DIG, DIG_0, GPIO_PIN_SET);//set TR pin on FPGA for TX mode
HAL_GPIO_TogglePin(GPIO_LED, LED_1);
delay_15ns(Delay_scan);
Adar_SetRxPhase(&ADAR1,1 ,vector_0[0] , BROADCAST_OFF);
Adar_SetRxPhase(&ADAR1,2 ,vector_0[1] , BROADCAST_OFF);
Adar_SetRxPhase(&ADAR1,3 ,vector_0[2] , BROADCAST_OFF);
Adar_SetRxPhase(&ADAR1,4 ,vector_0[3] , BROADCAST_OFF);
Adar_SetRxPhase(&ADAR2,1 ,vector_0[4] , BROADCAST_OFF);
Adar_SetRxPhase(&ADAR2,2 ,vector_0[5] , BROADCAST_OFF);
Adar_SetRxPhase(&ADAR2,3 ,vector_0[6] , BROADCAST_OFF);
Adar_SetRxPhase(&ADAR2,4 ,vector_0[7] , BROADCAST_OFF);
Adar_SetRxPhase(&ADAR3,1 ,vector_0[8] , BROADCAST_OFF);
Adar_SetRxPhase(&ADAR3,2 ,vector_0[9] , BROADCAST_OFF);
Adar_SetRxPhase(&ADAR3,3 ,vector_0[10] , BROADCAST_OFF);
Adar_SetRxPhase(&ADAR3,4 ,vector_0[11] , BROADCAST_OFF);
Adar_SetRxPhase(&ADAR4,1 ,vector_0[12] , BROADCAST_OFF);
Adar_SetRxPhase(&ADAR4,2 ,vector_0[13] , BROADCAST_OFF);
Adar_SetRxPhase(&ADAR4,3 ,vector_0[14] , BROADCAST_OFF);
Adar_SetRxPhase(&ADAR4,4 ,vector_0[15] , BROADCAST_OFF);
HAL_GPIO_WritePin(GPIO_DIG, DIG_0, GPIO_PIN_RESET);//reset TR pin on FPGA for RX mode
HAL_GPIO_TogglePin(GPIO_LED, LED_2);
delay_15ns(Delay_scan_rx);
}
for(int i = 0; i<21; i++){
Adar_SetTxPhase(&ADAR1,1 ,matrix2[i][0] , BROADCAST_OFF);
Adar_SetTxPhase(&ADAR1,2 ,matrix2[i][1] , BROADCAST_OFF);
Adar_SetTxPhase(&ADAR1,3 ,matrix2[i][2] , BROADCAST_OFF);
Adar_SetTxPhase(&ADAR1,4 ,matrix2[i][3] , BROADCAST_OFF);
Adar_SetTxPhase(&ADAR2,1 ,matrix2[i][4] , BROADCAST_OFF);
Adar_SetTxPhase(&ADAR2,2 ,matrix2[i][5] , BROADCAST_OFF);
Adar_SetTxPhase(&ADAR2,3 ,matrix2[i][6] , BROADCAST_OFF);
Adar_SetTxPhase(&ADAR2,4 ,matrix2[i][7] , BROADCAST_OFF);
Adar_SetTxPhase(&ADAR3,1 ,matrix2[i][8] , BROADCAST_OFF);
Adar_SetTxPhase(&ADAR3,2 ,matrix2[i][9] , BROADCAST_OFF);
Adar_SetTxPhase(&ADAR3,3 ,matrix2[i][10] , BROADCAST_OFF);
Adar_SetTxPhase(&ADAR3,4 ,matrix2[i][11] , BROADCAST_OFF);
Adar_SetTxPhase(&ADAR4,1 ,matrix2[i][12] , BROADCAST_OFF);
Adar_SetTxPhase(&ADAR4,2 ,matrix2[i][13] , BROADCAST_OFF);
Adar_SetTxPhase(&ADAR4,3 ,matrix2[i][14] , BROADCAST_OFF);
Adar_SetTxPhase(&ADAR4,4 ,matrix2[i][15] , BROADCAST_OFF);
HAL_GPIO_WritePin(GPIO_DIG, DIG_0, GPIO_PIN_SET);//set TR pin on FPGA for TX mode
HAL_GPIO_TogglePin(GPIO_LED, LED_1);
delay_15ns(Delay_scan);
Adar_SetRxPhase(&ADAR1,1 ,matrix2[i][0] , BROADCAST_OFF);
Adar_SetRxPhase(&ADAR1,2 ,matrix2[i][1] , BROADCAST_OFF);
Adar_SetRxPhase(&ADAR1,3 ,matrix2[i][2] , BROADCAST_OFF);
Adar_SetRxPhase(&ADAR1,4 ,matrix2[i][3] , BROADCAST_OFF);
Adar_SetRxPhase(&ADAR2,1 ,matrix2[i][4] , BROADCAST_OFF);
Adar_SetRxPhase(&ADAR2,2 ,matrix2[i][5] , BROADCAST_OFF);
Adar_SetRxPhase(&ADAR2,3 ,matrix2[i][6] , BROADCAST_OFF);
Adar_SetRxPhase(&ADAR2,4 ,matrix2[i][7] , BROADCAST_OFF);
Adar_SetRxPhase(&ADAR3,1 ,matrix2[i][8] , BROADCAST_OFF);
Adar_SetRxPhase(&ADAR3,2 ,matrix2[i][9] , BROADCAST_OFF);
Adar_SetRxPhase(&ADAR3,3 ,matrix2[i][10] , BROADCAST_OFF);
Adar_SetRxPhase(&ADAR3,4 ,matrix2[i][11] , BROADCAST_OFF);
Adar_SetRxPhase(&ADAR4,1 ,matrix2[i][12] , BROADCAST_OFF);
Adar_SetRxPhase(&ADAR4,2 ,matrix2[i][13] , BROADCAST_OFF);
Adar_SetRxPhase(&ADAR4,3 ,matrix2[i][14] , BROADCAST_OFF);
Adar_SetRxPhase(&ADAR4,4 ,matrix2[i][15] , BROADCAST_OFF);
HAL_GPIO_WritePin(GPIO_DIG, DIG_0, GPIO_PIN_RESET);//reset TR pin on FPGA for RX mode
HAL_GPIO_TogglePin(GPIO_LED, LED_2);
delay_15ns(Delay_scan_rx);
}
//Send commands to the auxilliary board to set motor position and get GPS data
/* USER CODE END WHILE */
/* USER CODE BEGIN 3 */
}
/* USER CODE END 3 */
}
/**
* @brief System Clock Configuration
* @retval None
*/
void SystemClock_Config(void)
{
RCC_OscInitTypeDef RCC_OscInitStruct = {0};
RCC_ClkInitTypeDef RCC_ClkInitStruct = {0};
/** Configure LSE Drive Capability
*/
HAL_PWR_EnableBkUpAccess();
/** Configure the main internal regulator output voltage
*/
__HAL_RCC_PWR_CLK_ENABLE();
__HAL_PWR_VOLTAGESCALING_CONFIG(PWR_REGULATOR_VOLTAGE_SCALE3);
/** Initializes the RCC Oscillators according to the specified parameters
* in the RCC_OscInitTypeDef structure.
*/
RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSE;
RCC_OscInitStruct.HSEState = RCC_HSE_ON;
RCC_OscInitStruct.PLL.PLLState = RCC_PLL_ON;
RCC_OscInitStruct.PLL.PLLSource = RCC_PLLSOURCE_HSE;
RCC_OscInitStruct.PLL.PLLM = 4;
RCC_OscInitStruct.PLL.PLLN = 64;
RCC_OscInitStruct.PLL.PLLP = RCC_PLLP_DIV2;
RCC_OscInitStruct.PLL.PLLQ = 2;
if (HAL_RCC_OscConfig(&RCC_OscInitStruct) != HAL_OK)
{
Error_Handler();
}
/** Initializes the CPU, AHB and APB buses clocks
*/
RCC_ClkInitStruct.ClockType = RCC_CLOCKTYPE_HCLK|RCC_CLOCKTYPE_SYSCLK
|RCC_CLOCKTYPE_PCLK1|RCC_CLOCKTYPE_PCLK2;
RCC_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_PLLCLK;
RCC_ClkInitStruct.AHBCLKDivider = RCC_SYSCLK_DIV1;
RCC_ClkInitStruct.APB1CLKDivider = RCC_HCLK_DIV2;
RCC_ClkInitStruct.APB2CLKDivider = RCC_HCLK_DIV1;
if (HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_2) != HAL_OK)
{
Error_Handler();
}
}
/**
* @brief I2C1 Initialization Function
* @param None
* @retval None
*/
static void MX_I2C1_Init(void)
{
/* USER CODE BEGIN I2C1_Init 0 */
/* USER CODE END I2C1_Init 0 */
/* USER CODE BEGIN I2C1_Init 1 */
/* USER CODE END I2C1_Init 1 */
hi2c1.Instance = I2C1;
hi2c1.Init.Timing = 0x00707CBB;
hi2c1.Init.OwnAddress1 = 0;
hi2c1.Init.AddressingMode = I2C_ADDRESSINGMODE_7BIT;
hi2c1.Init.DualAddressMode = I2C_DUALADDRESS_DISABLE;
hi2c1.Init.OwnAddress2 = 0;
hi2c1.Init.OwnAddress2Masks = I2C_OA2_NOMASK;
hi2c1.Init.GeneralCallMode = I2C_GENERALCALL_DISABLE;
hi2c1.Init.NoStretchMode = I2C_NOSTRETCH_DISABLE;
if (HAL_I2C_Init(&hi2c1) != HAL_OK)
{
Error_Handler();
}
/** Configure Analogue filter
*/
if (HAL_I2CEx_ConfigAnalogFilter(&hi2c1, I2C_ANALOGFILTER_ENABLE) != HAL_OK)
{
Error_Handler();
}
/** Configure Digital filter
*/
if (HAL_I2CEx_ConfigDigitalFilter(&hi2c1, 0) != HAL_OK)
{
Error_Handler();
}
/* USER CODE BEGIN I2C1_Init 2 */
/* USER CODE END I2C1_Init 2 */
}
/**
* @brief SPI1 Initialization Function
* @param None
* @retval None
*/
static void MX_SPI1_Init(void)
{
/* USER CODE BEGIN SPI1_Init 0 */
/* USER CODE END SPI1_Init 0 */
/* USER CODE BEGIN SPI1_Init 1 */
/* USER CODE END SPI1_Init 1 */
/* SPI1 parameter configuration*/
hspi1.Instance = SPI1;
hspi1.Init.Mode = SPI_MODE_MASTER;
hspi1.Init.Direction = SPI_DIRECTION_2LINES;
hspi1.Init.DataSize = SPI_DATASIZE_8BIT;
hspi1.Init.CLKPolarity = SPI_POLARITY_LOW;
hspi1.Init.CLKPhase = SPI_PHASE_1EDGE;
hspi1.Init.NSS = SPI_NSS_SOFT;
hspi1.Init.BaudRatePrescaler = SPI_BAUDRATEPRESCALER_16;
hspi1.Init.FirstBit = SPI_FIRSTBIT_MSB;
hspi1.Init.TIMode = SPI_TIMODE_DISABLE;
hspi1.Init.CRCCalculation = SPI_CRCCALCULATION_DISABLE;
hspi1.Init.CRCPolynomial = 7;
hspi1.Init.CRCLength = SPI_CRC_LENGTH_DATASIZE;
hspi1.Init.NSSPMode = SPI_NSS_PULSE_ENABLE;
if (HAL_SPI_Init(&hspi1) != HAL_OK)
{
Error_Handler();
}
/* USER CODE BEGIN SPI1_Init 2 */
/* USER CODE END SPI1_Init 2 */
}
/**
* @brief TIM1 Initialization Function
* @param None
* @retval None
*/
static void MX_TIM1_Init(void)
{
/* USER CODE BEGIN TIM1_Init 0 */
/* USER CODE END TIM1_Init 0 */
TIM_ClockConfigTypeDef sClockSourceConfig = {0};
TIM_MasterConfigTypeDef sMasterConfig = {0};
/* USER CODE BEGIN TIM1_Init 1 */
/* USER CODE END TIM1_Init 1 */
htim1.Instance = TIM1;
htim1.Init.Prescaler = 0;
htim1.Init.CounterMode = TIM_COUNTERMODE_UP;
htim1.Init.Period = 65535;
htim1.Init.ClockDivision = TIM_CLOCKDIVISION_DIV1;
htim1.Init.RepetitionCounter = 0;
htim1.Init.AutoReloadPreload = TIM_AUTORELOAD_PRELOAD_DISABLE;
if (HAL_TIM_Base_Init(&htim1) != HAL_OK)
{
Error_Handler();
}
sClockSourceConfig.ClockSource = TIM_CLOCKSOURCE_INTERNAL;
if (HAL_TIM_ConfigClockSource(&htim1, &sClockSourceConfig) != HAL_OK)
{
Error_Handler();
}
sMasterConfig.MasterOutputTrigger = TIM_TRGO_RESET;
sMasterConfig.MasterOutputTrigger2 = TIM_TRGO2_RESET;
sMasterConfig.MasterSlaveMode = TIM_MASTERSLAVEMODE_DISABLE;
if (HAL_TIMEx_MasterConfigSynchronization(&htim1, &sMasterConfig) != HAL_OK)
{
Error_Handler();
}
/* USER CODE BEGIN TIM1_Init 2 */
/* USER CODE END TIM1_Init 2 */
}
/**
* @brief USART2 Initialization Function
* @param None
* @retval None
*/
static void MX_USART2_UART_Init(void)
{
/* USER CODE BEGIN USART2_Init 0 */
/* USER CODE END USART2_Init 0 */
/* USER CODE BEGIN USART2_Init 1 */
/* USER CODE END USART2_Init 1 */
huart2.Instance = USART2;
huart2.Init.BaudRate = 115200;
huart2.Init.WordLength = UART_WORDLENGTH_8B;
huart2.Init.StopBits = UART_STOPBITS_1;
huart2.Init.Parity = UART_PARITY_NONE;
huart2.Init.Mode = UART_MODE_TX_RX;
huart2.Init.HwFlowCtl = UART_HWCONTROL_NONE;
huart2.Init.OverSampling = UART_OVERSAMPLING_16;
huart2.Init.OneBitSampling = UART_ONE_BIT_SAMPLE_DISABLE;
huart2.AdvancedInit.AdvFeatureInit = UART_ADVFEATURE_NO_INIT;
if (HAL_UART_Init(&huart2) != HAL_OK)
{
Error_Handler();
}
/* USER CODE BEGIN USART2_Init 2 */
/* USER CODE END USART2_Init 2 */
}
/**
* @brief GPIO Initialization Function
* @param None
* @retval None
*/
static void MX_GPIO_Init(void)
{
GPIO_InitTypeDef GPIO_InitStruct = {0};
/* USER CODE BEGIN MX_GPIO_Init_1 */
/* USER CODE END MX_GPIO_Init_1 */
/* GPIO Ports Clock Enable */
__HAL_RCC_GPIOC_CLK_ENABLE();
__HAL_RCC_GPIOH_CLK_ENABLE();
__HAL_RCC_GPIOA_CLK_ENABLE();
__HAL_RCC_GPIOB_CLK_ENABLE();
__HAL_RCC_GPIOD_CLK_ENABLE();
/*Configure GPIO pin Output Level */
HAL_GPIO_WritePin(GPIOC, GPIO_PIN_4|GPIO_PIN_5|GPIO_PIN_6|GPIO_PIN_7, GPIO_PIN_RESET);
/*Configure GPIO pin Output Level */
HAL_GPIO_WritePin(GPIOB, GPIO_PIN_14|GPIO_PIN_15|GPIO_PIN_4|GPIO_PIN_5, GPIO_PIN_RESET);
/*Configure GPIO pin Output Level */
HAL_GPIO_WritePin(GPIOD, GPIO_PIN_10|GPIO_PIN_11|GPIO_PIN_12|GPIO_PIN_13
|GPIO_PIN_0|GPIO_PIN_1|GPIO_PIN_2|GPIO_PIN_3, GPIO_PIN_RESET);
/*Configure GPIO pin Output Level */
HAL_GPIO_WritePin(GPIOA, GPIO_PIN_8|GPIO_PIN_9|GPIO_PIN_10|GPIO_PIN_11, GPIO_PIN_RESET);
/*Configure GPIO pins : PC4 PC5 PC6 PC7 */
GPIO_InitStruct.Pin = GPIO_PIN_4|GPIO_PIN_5|GPIO_PIN_6|GPIO_PIN_7;
GPIO_InitStruct.Mode = GPIO_MODE_INPUT;
GPIO_InitStruct.Pull = GPIO_NOPULL;
HAL_GPIO_Init(GPIOC, &GPIO_InitStruct);
/*Configure GPIO pins : PC0 PC1 PC2 PC3 */
GPIO_InitStruct.Pin = GPIO_PIN_0|GPIO_PIN_1|GPIO_PIN_2|GPIO_PIN_3;
GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
GPIO_InitStruct.Pull = GPIO_NOPULL;
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;
HAL_GPIO_Init(GPIOC, &GPIO_InitStruct);
/*Configure GPIO pins : PB14 PB15 PB4 PB5 */
GPIO_InitStruct.Pin = GPIO_PIN_14|GPIO_PIN_15|GPIO_PIN_4|GPIO_PIN_5;
GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
GPIO_InitStruct.Pull = GPIO_NOPULL;
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;
HAL_GPIO_Init(GPIOB, &GPIO_InitStruct);
/*Configure GPIO pins : PD10 PD11 PD12 PD13
PD0 PD1 PD2 PD3 */
GPIO_InitStruct.Pin = GPIO_PIN_10|GPIO_PIN_11|GPIO_PIN_12|GPIO_PIN_13
|GPIO_PIN_0|GPIO_PIN_1|GPIO_PIN_2|GPIO_PIN_3;
GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
GPIO_InitStruct.Pull = GPIO_NOPULL;
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;
HAL_GPIO_Init(GPIOD, &GPIO_InitStruct);
/*Configure GPIO pins : PA8 PA9 PA10 PA11 */
GPIO_InitStruct.Pin = GPIO_PIN_8|GPIO_PIN_9|GPIO_PIN_10|GPIO_PIN_11;
GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
GPIO_InitStruct.Pull = GPIO_NOPULL;
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;
HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);
/* USER CODE BEGIN MX_GPIO_Init_2 */
/* USER CODE END MX_GPIO_Init_2 */
}
/* USER CODE BEGIN 4 */
/* USER CODE END 4 */
/**
* @brief This function is executed in case of error occurrence.
* @retval None
*/
void Error_Handler(void)
{
/* USER CODE BEGIN Error_Handler_Debug */
/* User can add his own implementation to report the HAL error return state */
__disable_irq();
while (1)
{
}
/* USER CODE END Error_Handler_Debug */
}
#ifdef USE_FULL_ASSERT
/**
* @brief Reports the name of the source file and the source line number
* where the assert_param error has occurred.
* @param file: pointer to the source file name
* @param line: assert_param error line source number
* @retval None
*/
void assert_failed(uint8_t *file, uint32_t line)
{
/* USER CODE BEGIN 6 */
/* User can add his own implementation to report the file name and line number,
ex: printf("Wrong parameters value: file %s on line %d\r\n", file, line) */
/* USER CODE END 6 */
}
#endif /* USE_FULL_ASSERT */
@@ -0,0 +1,70 @@
/* USER CODE BEGIN Header */
/**
******************************************************************************
* @file : main.h
* @brief : Header for main.c file.
* This file contains the common defines of the application.
******************************************************************************
* @attention
*
* Copyright (c) 2025 STMicroelectronics.
* All rights reserved.
*
* This software is licensed under terms that can be found in the LICENSE file
* in the root directory of this software component.
* If no LICENSE file comes with this software, it is provided AS-IS.
*
******************************************************************************
*/
/* USER CODE END Header */
/* Define to prevent recursive inclusion -------------------------------------*/
#ifndef __MAIN_H
#define __MAIN_H
#ifdef __cplusplus
extern "C" {
#endif
/* Includes ------------------------------------------------------------------*/
#include "stm32f7xx_hal.h"
/* Private includes ----------------------------------------------------------*/
/* USER CODE BEGIN Includes */
/* USER CODE END Includes */
/* Exported types ------------------------------------------------------------*/
/* USER CODE BEGIN ET */
/* USER CODE END ET */
/* Exported constants --------------------------------------------------------*/
/* USER CODE BEGIN EC */
/* USER CODE END EC */
/* Exported macro ------------------------------------------------------------*/
/* USER CODE BEGIN EM */
/* USER CODE END EM */
/* Exported functions prototypes ---------------------------------------------*/
void Error_Handler(void);
/* USER CODE BEGIN EFP */
/* USER CODE END EFP */
/* Private defines -----------------------------------------------------------*/
/* USER CODE BEGIN Private defines */
/* USER CODE END Private defines */
#ifdef __cplusplus
}
#endif
#endif /* __MAIN_H */
@@ -0,0 +1,70 @@
/***************************************************************************//**
* @file no_os_ain.h
* @author PMallick (Pratyush.Mallick@analog.com)
********************************************************************************
* Copyright (c) 2021-22 Analog Devices, Inc.
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* 3. Neither the name of Analog Devices, Inc. nor the names of its
* contributors may be used to endorse or promote products derived from this
* software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY ANALOG DEVICES, INC. “AS IS” AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
* EVENT SHALL ANALOG DEVICES, INC. BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
* OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
* EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*******************************************************************************/
#ifndef NO_OS_AIN_H
#define NO_OS_AIN_H
#include <stdint.h>
/**
* @struct ain_init_param
* @brief Structure holding parameters for analog input initialization
*/
struct no_os_ain_init_param {
/* Analog input reference voltage */
float vref;
/* Analog extra parameters (device specific) */
void *extra;
};
/**
* @struct ain_desc
* @brief Structure holding analog input descriptor
*/
struct no_os_ain_desc {
/* Analog input reference voltage */
float vref;
/* Analog extra parameters (device specific) */
void *extra;
};
/* Read analog input voltage */
int32_t no_os_ain_get_voltage(struct no_os_ain_desc *desc, float *value);
/* Initialize the analog input peripheral*/
int32_t no_os_ain_init(struct no_os_ain_desc **desc,
const struct no_os_ain_init_param *param);
/* Free the resources allocated by no_os_ain_init() */
int32_t no_os_ain_remove(struct no_os_ain_desc *desc);
#endif // end of NO_OS_AIN_H
@@ -0,0 +1,67 @@
/*******************************************************************************
* @file util/no_os_alloc.c
* @brief Implementation of no-OS memory allocation functions.
* @author GMois (george.mois@analog.com)
********************************************************************************
* Copyright 2023(c) Analog Devices, Inc.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* 3. Neither the name of Analog Devices, Inc. nor the names of its
* contributors may be used to endorse or promote products derived from this
* software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY ANALOG DEVICES, INC. “AS IS” AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
* EVENT SHALL ANALOG DEVICES, INC. BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
* OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
* EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*******************************************************************************/
#include "no_os_alloc.h"
/**
* @brief Allocate memory and return a pointer to it.
* @param size - Size of the memory block, in bytes.
* @return Pointer to the allocated memory, or NULL if the request fails.
*/
__attribute__((weak)) void *no_os_malloc(size_t size)
{
return malloc(size);
}
/**
* @brief Allocate memory and return a pointer to it, set memory to 0.
* @param nitems - Number of elements to be allocated.
* @param size - Size of elements.
* @return Pointer to the allocated memory, or NULL if the request fails.
*/
__attribute__((weak)) void *no_os_calloc(size_t nitems, size_t size)
{
return calloc(nitems, size);
}
/**
* @brief Deallocate memory previously allocated by a call to no_os_calloc
* or no_os_malloc.
* @param ptr - Pointer to a memory block previously allocated by a call
* to no_os_calloc or no_os_malloc.
* @return None.
*/
__attribute__((weak)) void no_os_free(void *ptr)
{
free(ptr);
}
@@ -0,0 +1,49 @@
/*******************************************************************************
* @file no_os_alloc.h
* @brief Header file of memory allocator.
* @author GMois (george.mois@analog.com)
********************************************************************************
* Copyright 2023(c) Analog Devices, Inc.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* 3. Neither the name of Analog Devices, Inc. nor the names of its
* contributors may be used to endorse or promote products derived from this
* software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY ANALOG DEVICES, INC. “AS IS” AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
* EVENT SHALL ANALOG DEVICES, INC. BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
* OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
* EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*******************************************************************************/
#ifndef _NO_OS_ALLOC_H_
#define _NO_OS_ALLOC_H_
#include <stdio.h>
#include <stdlib.h>
/* Allocate memory and return a pointer to it */
void *no_os_malloc(size_t size);
/* Allocate memory and return a pointer to it, set memory to 0 */
void *no_os_calloc(size_t nitems, size_t size);
/* Deallocate memory previously allocated by a call to no_os_calloc or
* no_os_malloc */
void no_os_free(void *ptr);
#endif // _NO_OS_ALLOC_H_
@@ -0,0 +1,78 @@
/***************************************************************************//**
* @file no_os_aout.h
* @author PMallick (Pratyush.Mallick@analog.com)
********************************************************************************
* Copyright (c) 2021-22 Analog Devices, Inc.
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* 3. Neither the name of Analog Devices, Inc. nor the names of its
* contributors may be used to endorse or promote products derived from this
* software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY ANALOG DEVICES, INC. “AS IS” AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
* EVENT SHALL ANALOG DEVICES, INC. BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
* OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
* EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*******************************************************************************/
#ifndef NO_OS_AOUT_H
#define NO_OS_AOUT_H
#include <stdint.h>
/**
* @struct aout_init_param
* @brief Structure holding the parameters for analog output initialization
*/
struct no_os_aout_init_param {
/* Min output range of DAC in volts */
float aout_min_v;
/* Max output range of DAC in volts */
float aout_max_v;
/* Analog output reference voltage */
float vref;
/* Analog extra parameters (device specific) */
void *extra;
};
/**
* @struct aout_desc
* @brief Structure holding analog output descriptor
*/
struct no_os_aout_desc {
/* Min output value of DAC in volts */
float aout_min_v;
/* Max output value of DAC in volts */
float aout_max_v;
/* Analog output reference voltage */
float vref;
/* Analog extra parameters (device specific) */
void *extra;
};
/* Write analog output voltage */
int32_t no_os_aout_set_voltage(struct no_os_aout_desc *desc, float value);
/* Initialize the analog output peripheral */
int32_t no_so_aout_init(struct no_os_aout_desc **desc,
const struct no_os_aout_init_param *param);
/* Free the resources allocated by no_os_aout_init() */
int32_t no_os_aout_remove(struct no_os_aout_desc *desc);
#endif // end of NO_OS_AOUT_H
@@ -0,0 +1,45 @@
/***************************************************************************//**
* @file no_os_axi_io.h
* @brief Header file of AXI IO.
* @author Antoniu Miclaus (antoniu.miclaus@analog.com)
********************************************************************************
* Copyright 2019(c) Analog Devices, Inc.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* 3. Neither the name of Analog Devices, Inc. nor the names of its
* contributors may be used to endorse or promote products derived from this
* software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY ANALOG DEVICES, INC. “AS IS” AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
* EVENT SHALL ANALOG DEVICES, INC. BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
* OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
* EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*******************************************************************************/
#ifndef _NO_OS_AXI_IO_H_
#define _NO_OS_AXI_IO_H_
#include <stdint.h>
/* AXI IO Read data */
int32_t no_os_axi_io_read(uint32_t base, uint32_t offset, uint32_t *data);
/* AXI IO Write data */
int32_t no_os_axi_io_write(uint32_t base, uint32_t offset, uint32_t data);
#endif // _NO_OS_AXI_IO_H_
@@ -0,0 +1,390 @@
/***************************************************************************//**
* @file no_os_circular_buffer.c
* @brief Circular buffer implementation
* @author Mihail Chindris (mihail.chindris@analog.com)
********************************************************************************
* @copyright
* Copyright 2020(c) Analog Devices, Inc.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* 3. Neither the name of Analog Devices, Inc. nor the names of its
* contributors may be used to endorse or promote products derived from this
* software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY ANALOG DEVICES, INC. “AS IS” AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
* EVENT SHALL ANALOG DEVICES, INC. BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
* OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
* EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*******************************************************************************/
#include <string.h>
#include <stdlib.h>
#include <stdbool.h>
#include "no_os_circular_buffer.h"
#include "no_os_error.h"
#include "no_os_util.h"
#include "no_os_alloc.h"
int32_t no_os_cb_cfg(struct no_os_circular_buffer *desc, int8_t *buff,
uint32_t size)
{
if (!desc)
return -EINVAL;
memset(desc, 0, sizeof(*desc));
desc->size = size;
desc->buff = buff;
return 0;
}
/**
* @brief Create circular buffer structure.
*
* @note Circular buffer implementation is thread safe for one write
* and one reader.
* If multiple writer or multiple readers access the circular buffer then
* function that updates the structure should be called inside a critical
* critical section.
*
* @param desc - Where to store the circular buffer reference
* @param buff_size - Buffer size
* @return
* - 0 : On success
* - -1 : Otherwise
*/
int32_t no_os_cb_init(struct no_os_circular_buffer **desc, uint32_t buff_size)
{
struct no_os_circular_buffer *ldesc;
if (!desc || !buff_size)
return -EINVAL;
ldesc = (struct no_os_circular_buffer*)no_os_calloc(1, sizeof(*ldesc));
if (!ldesc)
return -ENOMEM;
*desc = ldesc;
ldesc->size = buff_size;
ldesc->buff = no_os_calloc(1, buff_size);
if (!ldesc->buff) {
no_os_free(ldesc);
return -ENOMEM;
}
return 0;
}
/**
* @brief Free the resources allocated for the circular buffer structure.
* @param desc - Circular buffer reference
* @return
* - 0 : On success
* - -1 : Otherwise
*/
int32_t no_os_cb_remove(struct no_os_circular_buffer *desc)
{
if (!desc)
return -1;
if (desc->buff)
no_os_free(desc->buff);
no_os_free(desc);
return 0;
}
/**
* @brief Get the number of elements in the buffer.
* @param desc - Circular buffer reference
* @param size - Where to store size of data available to read
* @return
* - 0 - No errors
* - -EINVAL - Wrong parameters used
* - -NO_OS_EOVERRUN - A buffer overrun occurred
*/
int32_t no_os_cb_size(struct no_os_circular_buffer *desc, uint32_t *size)
{
uint32_t nb_spins;
if (!desc || !size)
return -EINVAL;
if (desc->write.spin_count > desc->read.spin_count)
nb_spins = desc->write.spin_count - desc->read.spin_count;
else
/* Integer overflow on desc->write.spin_count */
nb_spins = UINT32_MAX - desc->read.spin_count +
desc->write.spin_count + 1;
if (nb_spins > 0)
*size = desc->size + desc->write.idx - desc->read.idx;
else
*size = desc->write.idx - desc->read.idx;
if (*size > desc->size) {
*size = desc->size;
return -NO_OS_EOVERRUN;
}
return 0;
}
/*
* Functionality described at no_os_cb_prepare_async_write/read having the is_read
* parameter to specifiy if it is a read or write operation.
*/
static int32_t no_os_cb_prepare_async_operation(struct no_os_circular_buffer
*desc,
uint32_t requested_size,
void **buff,
uint32_t *raw_size_available,
bool is_read)
{
struct no_os_cb_ptr *ptr;
uint32_t available_size;
int32_t ret;
if (!desc || !buff || !raw_size_available)
return -EINVAL;
ret = 0;
/* Select if read or write index will be updated */
ptr = is_read ? &desc->read : &desc->write;
/* Only one transaction type possible at a single time */
if (ptr->async_started)
return -EBUSY;
if (is_read) {
ret = no_os_cb_size(desc, &available_size);
if (ret == -NO_OS_EOVERRUN) {
/* Update read index */
desc->read.spin_count = desc->write.spin_count - 1;
#ifndef IIO_IGNORE_BUFF_OVERRUN_ERR
desc->read.idx = desc->write.idx;
#endif
}
if (!available_size)
/* No data to read */
return 0;
/* We can only read available data */
requested_size = no_os_min(requested_size, available_size);
if (!requested_size)
return -EAGAIN;
}
/* Size to end of buffer */
ptr->async_size = no_os_min(requested_size, desc->size - ptr->idx);
*raw_size_available = ptr->async_size;
/* Convert index to address in the buffer */
*buff = (void *)(desc->buff + ptr->idx);
ptr->async_started = true;
return ret;
}
/*
* Functionality described at no_os_cb_end_async_write/read having the is_read
* parameter to specifiy if it is a read or write operation.
*/
static int32_t no_os_cb_end_async_operation(struct no_os_circular_buffer *desc,
bool is_read)
{
struct no_os_cb_ptr *ptr;
uint32_t new_val;
if (!desc)
return -EINVAL;
/* Select if read or write index will be updated */
ptr = is_read ? &desc->read : &desc->write;
/* Transaction not started */
if (!ptr->async_started)
return -1;
/* Update pointer value */
new_val = ptr->idx + ptr->async_size;
if (new_val >= desc->size) {
ptr->spin_count++;
new_val %= desc->size;
}
ptr->idx = new_val;
ptr->async_size = 0;
ptr->async_started = false;
return 0;
}
/*
* Functionality described at cb_write/read having the is_read
* parameter to specifiy if it is a read or write operation.
*/
static int32_t no_os_cb_operation(struct no_os_circular_buffer *desc,
void *data, uint32_t size,
bool is_read)
{
uint8_t *buff;
uint32_t available_size = 0;
int32_t ret;
uint32_t i;
bool sticky_overrun;
if (!desc || !data || !size)
return -EINVAL;
sticky_overrun = 0;
i = 0;
while (i < size) {
do {
ret = no_os_cb_prepare_async_operation(desc, size - i,
(void **)&buff,
&available_size,
is_read);
} while (ret == -EBUSY || ret == -EAGAIN);
if (ret == -NO_OS_EOVERRUN)
sticky_overrun = true;
/* If no data is available return error */
if (!available_size)
return -1;
if (is_read)
memcpy((uint8_t *)data + i, buff, available_size);
else
memcpy(buff, (uint8_t *)data + i, available_size);
no_os_cb_end_async_operation(desc, is_read);
i += available_size;
}
if (sticky_overrun)
return -NO_OS_EOVERRUN;
return 0;
}
/**
* @brief Prepare asynchronous write.
*
* Get the inside raw buffer to be used in DMA transactions.
*
* @param desc - Circular buffer reference
* @param size_to_write - Number of bytes needed to write to the buffer.
* @param write_buff - Address where to store the buffer where to write to.
* @param size_avilable - no_os_min(size_to_write, size until end of allocated buffer)
* @return
* - 0 - No errors
* - -EINVAL - Wrong parameters used
* - -EBUSY - Asynchronous transaction already started
*/
int32_t no_os_cb_prepare_async_write(struct no_os_circular_buffer *desc,
uint32_t size_to_write,
void **write_buff,
uint32_t *size_avilable)
{
return no_os_cb_prepare_async_operation(desc, size_to_write, write_buff,
size_avilable, 0);
}
/**
* @brief Prepare asynchronous read.
*
* Get the inside raw buffer to be used in DMA transactions.
*
* @param desc - Circular buffer reference
* @param size_to_read - Number of bytes needed to write to the buffer.
* @param read_buff - Address where to store the buffer where data will be read.
* @param size_avilable - no_os_min(size_to_read, size until end of allocated buffer)
* @return
* - 0 - No errors
* - -EAGAIN - No data available at this moment
* - -EINVAL - Wrong parameters used
* - -EBUSY - Asynchronous transaction already started
* - -NO_OS_EOVERRUN - An overrun occurred and some data have been overwritten
*/
int32_t no_os_cb_prepare_async_read(struct no_os_circular_buffer *desc,
uint32_t size_to_read,
void **read_buff,
uint32_t *size_avilable)
{
return no_os_cb_prepare_async_operation(desc, size_to_read, read_buff,
size_avilable, 1);
}
/**
* \defgroup end_async_group End Ashyncronous functions
* @brief End asynchronous transaction.
*
* @param desc - Circular buffer reference
* @return
* - 0 - No errors
* - -1 - Asynchronous transaction not started
* - -EINVAL - Wrong parameters used
* @{
*/
int32_t no_os_cb_end_async_write(struct no_os_circular_buffer *desc)
{
return no_os_cb_end_async_operation(desc, 0);
}
int32_t no_os_cb_end_async_read(struct no_os_circular_buffer *desc)
{
return no_os_cb_end_async_operation(desc, 1);
}
/** @} */
/**
* @brief Write data to the buffer (Blocking).
* @param desc - Circular buffer reference
* @param data - Buffer from where data is copied to the circular buffer
* @param size - Size to write
* @return
* - 0 - No errors
* - -EINVAL - Wrong parameters used
*/
int32_t no_os_cb_write(struct no_os_circular_buffer *desc, const void *data,
uint32_t size)
{
return no_os_cb_operation(desc, (void *)data, size, 0);
}
/**
* @brief Read data from the buffer (Blocking).
* @param desc - Circular buffer reference
* @param data - Buffer where to data is copied from the circular buffer
* @param size - Size to read
* @return
* - 0 - No errors
* - -EINVAL - Wrong parameters used
* - -NO_OS_EOVERRUN - An overrun occurred and some data have been overwritten
*/
int32_t no_os_cb_read(struct no_os_circular_buffer *desc, void *data,
uint32_t size)
{
return no_os_cb_operation(desc, data, size, 1);
}
@@ -0,0 +1,94 @@
/***************************************************************************//**
* @file no_os_circular_buffer.h
* @brief Circular buffer library header
* @author Mihail Chindris (mihail.chindris@analog.com)
********************************************************************************
* @copyright
* Copyright 2020(c) Analog Devices, Inc.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* 3. Neither the name of Analog Devices, Inc. nor the names of its
* contributors may be used to endorse or promote products derived from this
* software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY ANALOG DEVICES, INC. “AS IS” AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
* EVENT SHALL ANALOG DEVICES, INC. BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
* OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
* EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*******************************************************************************/
#ifndef _NO_OS_CIRCULAR_BUFFER_H_
#define _NO_OS_CIRCULAR_BUFFER_H_
#include <stdint.h>
/**
* @struct no_os_cb_ptr
* @brief Circular buffer pointer
*/
struct no_os_cb_ptr {
/** Index of data in the buffer */
uint32_t idx;
/** Counts the number of times idx exceeds the liniar buffer */
uint32_t spin_count;
/** Set if async transaction is active */
bool async_started;
/** Number of bytes to update after an async transaction is finished */
uint32_t async_size;
};
/**
* @struct no_os_circular_buffer
* @brief Circular buffer descriptor
*/
struct no_os_circular_buffer {
/** Size of the buffer in bytes */
uint32_t size;
/** Address of the buffer */
int8_t *buff;
/** Write pointer */
struct no_os_cb_ptr write;
/** Read pointer */
struct no_os_cb_ptr read;
};
int32_t no_os_cb_init(struct no_os_circular_buffer **desc, uint32_t size);
/* Configure cb structure with given parameters without memory allocation */
int32_t no_os_cb_cfg(struct no_os_circular_buffer *desc, int8_t *buf,
uint32_t size);
int32_t no_os_cb_remove(struct no_os_circular_buffer *desc);
int32_t no_os_cb_size(struct no_os_circular_buffer *desc, uint32_t *size);
int32_t no_os_cb_write(struct no_os_circular_buffer *desc, const void *data,
uint32_t nb_elements);
int32_t no_os_cb_read(struct no_os_circular_buffer *desc, void *data,
uint32_t nb_elements);
int32_t no_os_cb_prepare_async_write(struct no_os_circular_buffer *desc,
uint32_t raw_size_to_write,
void **write_buff,
uint32_t *raw_size_avilable);
int32_t no_os_cb_end_async_write(struct no_os_circular_buffer *desc);
int32_t no_os_cb_prepare_async_read(struct no_os_circular_buffer *desc,
uint32_t raw_size_to_read,
void **read_buff,
uint32_t *raw_size_avilable);
int32_t no_os_cb_end_async_read(struct no_os_circular_buffer *desc);
#endif //_NO_OS_CIRCULAR_BUFFER_H_
@@ -0,0 +1,193 @@
/***************************************************************************//**
* @file no_os_clk.c
* @brief Implementation of Clock Driver.
* @author DBogdan (dragos.bogdan@analog.com)
********************************************************************************
* Copyright 2020(c) Analog Devices, Inc.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* 3. Neither the name of Analog Devices, Inc. nor the names of its
* contributors may be used to endorse or promote products derived from this
* software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY ANALOG DEVICES, INC. “AS IS” AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
* EVENT SHALL ANALOG DEVICES, INC. BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
* OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
* EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*******************************************************************************/
/******************************************************************************/
/***************************** Include Files **********************************/
/******************************************************************************/
#include "no_os_alloc.h"
#include "no_os_error.h"
#include "no_os_clk.h"
/******************************************************************************/
/************************** Functions Implementation **************************/
/******************************************************************************/
/**
* Initialize clock.
* @param desc - CLK descriptor.
* @param param - The structure that contains CLK parameters.
* @return 0 in case of success, -1 otherwise.
*/
int32_t no_os_clk_init(struct no_os_clk_desc **desc,
const struct no_os_clk_init_param *param)
{
struct no_os_clk_desc *clk;
int ret;
if (!desc || !param || !param->platform_ops)
return -EINVAL;
clk = (struct no_os_clk_desc *)no_os_calloc(1, sizeof(*clk));
if (!clk)
return -ENOMEM;
clk->name = param->name;
clk->hw_ch_num = param->hw_ch_num;
clk->dev_desc = param->dev_desc;
clk->platform_ops = param->platform_ops;
if (param->platform_ops->init) {
ret = param->platform_ops->init(desc, param);
if (ret)
goto error;
}
*desc = clk;
return 0;
error:
no_os_free(clk);
return ret;
}
/**
* @brief Free the resources allocated by no_os_clk_init().
* @param desc - The clock descriptor.
* @return 0 in case of success, -1 otherwise.
*/
int32_t no_os_clk_remove(struct no_os_clk_desc *desc)
{
int ret;
if (!desc || !desc->platform_ops)
return -EINVAL;
if (desc->platform_ops->remove) {
ret = desc->platform_ops->remove(desc);
if (ret)
return ret;
}
no_os_free(desc);
return 0;
}
/**
* Start the clock.
* @param clk - The clock descriptor.
* @return 0 in case of success, negative error code otherwise.
*/
int32_t no_os_clk_enable(struct no_os_clk_desc *desc)
{
if (!desc || !desc->platform_ops)
return -EINVAL;
if (!desc->platform_ops->clk_enable)
return -ENOSYS;
return desc->platform_ops->clk_enable(desc);
}
/**
* Stop the clock.
* @param clk - The clock descriptor.
* @return 0 in case of success, negative error code otherwise.
*/
int32_t no_os_clk_disable(struct no_os_clk_desc *desc)
{
if (!desc || !desc->platform_ops)
return -EINVAL;
if (!desc->platform_ops->clk_disable)
return -ENOSYS;
return desc->platform_ops->clk_disable(desc);
}
/**
* Get the current frequency of the clock.
* @param clk - The clock descriptor.
* @param rate - The current frequency.
* @return 0 in case of success, negative error code otherwise.
*/
int32_t no_os_clk_recalc_rate(struct no_os_clk_desc *desc,
uint64_t *rate)
{
if (!desc || !desc->platform_ops || !rate)
return -EINVAL;
if (!desc->platform_ops->clk_recalc_rate)
return -ENOSYS;
return desc->platform_ops->clk_recalc_rate(desc, rate);
}
/**
* Round the desired frequency to a rate that the clock can actually output.
* @param clk - The clock descriptor.
* @param rate - The desired frequency.
* @param rounded_rate - The rounded frequency.
* @return 0 in case of success, negative error code otherwise.
*/
int32_t no_os_clk_round_rate(struct no_os_clk_desc *desc,
uint64_t rate,
uint64_t *rounded_rate)
{
if (!desc || !desc->platform_ops || !rounded_rate)
return -EINVAL;
if (!desc->platform_ops->clk_round_rate)
return -ENOSYS;
return desc->platform_ops->clk_round_rate(desc, rate, rounded_rate);
}
/**
* Change the frequency of the clock.
* @param clk - The clock descriptor.
* @param rate - The desired frequency.
* @return 0 in case of success, negative error code otherwise.
*/
int32_t no_os_clk_set_rate(struct no_os_clk_desc *desc,
uint64_t rate)
{
if (!desc || !desc->platform_ops)
return -EINVAL;
if (!desc->platform_ops->clk_set_rate)
return -ENOSYS;
return desc->platform_ops->clk_set_rate(desc, rate);
}
@@ -0,0 +1,128 @@
/***************************************************************************//**
* @file no_os_clk.h
* @brief Header file of Clock Driver.
* @author DBogdan (dragos.bogdan@analog.com)
********************************************************************************
* Copyright 2020(c) Analog Devices, Inc.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* 3. Neither the name of Analog Devices, Inc. nor the names of its
* contributors may be used to endorse or promote products derived from this
* software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY ANALOG DEVICES, INC. “AS IS” AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
* EVENT SHALL ANALOG DEVICES, INC. BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
* OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
* EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*******************************************************************************/
#ifndef _NO_OS_CLK_H_
#define _NO_OS_CLK_H_
#include <stdint.h>
struct no_os_clk_init_param {
/** Device name */
const char *name;
/** Channel number */
uint8_t hw_ch_num;
/** CLK function pointers */
const struct no_os_clk_platform_ops *platform_ops;
/** CLK hardware device descriptor */
void *dev_desc;
};
struct no_os_clk_hw {
void *dev;
int32_t (*dev_clk_enable)();
int32_t (*dev_clk_disable)();
int32_t (*dev_clk_recalc_rate)();
int32_t (*dev_clk_set_rate)();
int32_t (*dev_clk_round_rate)();
};
struct no_os_clk {
struct no_os_clk_hw *hw;
uint32_t hw_ch_num;
const char *name;
const struct no_os_clk_desc *clk_desc;
};
/**
* @struct no_os_clk_desc
* @brief Structure holding CLK descriptor.
*/
typedef struct no_os_clk_desc {
/** Device name */
const char *name;
/** Channel number */
uint8_t hw_ch_num;
/** CLK function pointers */
const struct no_os_clk_platform_ops *platform_ops;
/** CLK hardware device descriptor */
void *dev_desc;
} no_os_clk_desc;
/**
* @struct no_os_clk_platform_ops
* @brief Structure holding CLK function pointers that point to the platform
* specific function
*/
struct no_os_clk_platform_ops {
/** Initialize CLK function pointer. */
int (*init)(struct no_os_clk_desc **, const struct no_os_clk_init_param *);
/** Start CLK function pointer. */
int (*clk_enable)(struct no_os_clk_desc *);
/** Stop CLK function pointer. */
int (*clk_disable)(struct no_os_clk_desc *);
/** Get the current frequency of CLK function pointer. */
int (*clk_recalc_rate)(struct no_os_clk_desc *, uint64_t *);
/* Round the desired frequency to a rate that CLK can actually output. */
int (*clk_round_rate)(struct no_os_clk_desc *, uint64_t, uint64_t *);
/* Change CLK frequency function pointer. */
int (*clk_set_rate)(struct no_os_clk_desc *, uint64_t);
/** CLK remove function pointer */
int (*remove)(struct no_os_clk_desc *);
};
/* Initialize CLK ops. */
int32_t no_os_clk_init(struct no_os_clk_desc **desc,
const struct no_os_clk_init_param *param);
/* Free the resources allocated by no_os_clk_init(). */
int32_t no_os_clk_remove(struct no_os_clk_desc *desc);
/* Start the clock. */
int32_t no_os_clk_enable(struct no_os_clk_desc *desc);
/* Stop the clock. */
int32_t no_os_clk_disable(struct no_os_clk_desc *desc);
/* Get the current frequency of the clock. */
int32_t no_os_clk_recalc_rate(struct no_os_clk_desc *desc,
uint64_t *rate);
/* Round the desired frequency to a rate that the clock can actually output. */
int32_t no_os_clk_round_rate(struct no_os_clk_desc *desc,
uint64_t rate,
uint64_t *rounded_rate);
/* Change the frequency of the clock. */
int32_t no_os_clk_set_rate(struct no_os_clk_desc *desc,
uint64_t rate);
#endif // _NO_OS_CLK_H_
@@ -0,0 +1,40 @@
/***************************************************************************//**
* @file no_os_crc.h
* @brief Generic header file for all CRC computation algorithms.
* @author Darius Berghe (darius.berghe@analog.com)
********************************************************************************
* Copyright 2020(c) Analog Devices, Inc.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* 3. Neither the name of Analog Devices, Inc. nor the names of its
* contributors may be used to endorse or promote products derived from this
* software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY ANALOG DEVICES, INC. “AS IS” AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
* EVENT SHALL ANALOG DEVICES, INC. BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
* OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
* EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*******************************************************************************/
#ifndef _NO_OS_CRC_H_
#define _NO_OS_CRC_H_
#include "no_os_crc8.h"
#include "no_os_crc16.h"
#include "no_os_crc24.h"
#endif // _NO_OS_CRC_H_
@@ -0,0 +1,97 @@
/***************************************************************************//**
* @file no_os_crc16.c
* @brief Source file of CRC-16 computation.
* @author Darius Berghe (darius.berghe@analog.com)
********************************************************************************
* Copyright 2020(c) Analog Devices, Inc.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* 3. Neither the name of Analog Devices, Inc. nor the names of its
* contributors may be used to endorse or promote products derived from this
* software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY ANALOG DEVICES, INC. “AS IS” AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
* EVENT SHALL ANALOG DEVICES, INC. BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
* OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
* EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*******************************************************************************/
#include "no_os_crc16.h"
/***************************************************************************//**
* @brief Creates the CRC-16 lookup table for a given polynomial.
*
* @param table - Pointer to a CRC-16 lookup table to write to.
* @param polynomial - Msb-first representation of desired polynomial.
*
* Polynomials in CRC algorithms are typically represented as shown below.
*
* poly = x^16 + x^14 + x^13 + x^12 + x^10 + x^8 + x^6 + x^4 + x^3 +
* x^1 + 1
*
* Using msb-first direction, x^15 maps to the msb.
*
* msb first: poly = (1)0111010101011011 = 0x755B
* ^
*
* @return None.
*******************************************************************************/
void no_os_crc16_populate_msb(uint16_t * table, const uint16_t polynomial)
{
if (!table)
return;
for (int16_t n = 0; n < NO_OS_CRC16_TABLE_SIZE; n++) {
uint16_t currByte = (uint16_t)(n << 8);
for (uint8_t bit = 0; bit < 8; bit++) {
if ((currByte & 0x8000) != 0) {
currByte <<= 1;
currByte ^= polynomial;
} else {
currByte <<= 1;
}
}
table[n] = currByte;
}
}
/***************************************************************************//**
* @brief Computes the CRC-16 over a buffer of data.
*
* @param table - Pointer to a CRC-16 lookup table for the desired polynomial.
* @param pdata - Pointer to data buffer.
* @param nbytes - Number of bytes to compute the CRC-16 over.
* @param crc - Initial value for the CRC-16 computation. Can be used to
* cascade calls to this function by providing a previous
* output of this function as the crc parameter.
*
* @return crc - Computed CRC-16 value.
*******************************************************************************/
uint16_t no_os_crc16(const uint16_t * table, const uint8_t *pdata,
size_t nbytes,
uint16_t crc)
{
unsigned int idx;
while (nbytes--) {
idx = ((crc >> 8) ^ *pdata) & 0xff;
crc = (table[idx] ^ (crc << 8)) & 0xffff;
pdata++;
}
return crc;
}
@@ -0,0 +1,49 @@
/***************************************************************************//**
* @file no_os_crc16.h
* @brief Header file of CRC-16 computation.
* @author Darius Berghe (darius.berghe@analog.com)
********************************************************************************
* Copyright 2020(c) Analog Devices, Inc.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* 3. Neither the name of Analog Devices, Inc. nor the names of its
* contributors may be used to endorse or promote products derived from this
* software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY ANALOG DEVICES, INC. “AS IS” AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
* EVENT SHALL ANALOG DEVICES, INC. BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
* OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
* EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*******************************************************************************/
#ifndef _NO_OS_CRC16_H_
#define _NO_OS_CRC16_H_
#include <stdint.h>
#include <stddef.h>
#define NO_OS_CRC16_TABLE_SIZE 256
#define NO_OS_DECLARE_CRC16_TABLE(_table) \
static uint16_t _table[NO_OS_CRC16_TABLE_SIZE]
void no_os_crc16_populate_msb(uint16_t * table, const uint16_t polynomial);
uint16_t no_os_crc16(const uint16_t * table, const uint8_t *pdata,
size_t nbytes,
uint16_t crc);
#endif // _NO_OS_CRC16_H_
@@ -0,0 +1,98 @@
/***************************************************************************//**
* @file no_os_crc24.c
* @brief Source file of CRC-24 computation.
* @author Antoniu Miclaus (antoniu.miclaus@analog.com)
********************************************************************************
* Copyright 2021(c) Analog Devices, Inc.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* 3. Neither the name of Analog Devices, Inc. nor the names of its
* contributors may be used to endorse or promote products derived from this
* software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY ANALOG DEVICES, INC. “AS IS” AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
* EVENT SHALL ANALOG DEVICES, INC. BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
* OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
* EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*******************************************************************************/
#include "no_os_crc24.h"
/***************************************************************************//**
* @brief Creates the CRC-24 lookup table for a given polynomial.
*
* @param table - Pointer to a CRC-24 lookup table to write to.
* @param polynomial - msb-first representation of desired polynomial.
*
* Polynomials in CRC algorithms are typically represented as shown below.
*
* poly = x^24 + x^22 + x^20 + x^19 + x^18 + x^16 + x^14 + x^13 + x^11 +
* x^10 + x^8 + x^7 + x^6 + x^3 + x^1 + 1
*
* Using msb-first direction, x^24 maps to the msb.
*
* msb first: poly = (1)010111010110110111001011 = 5D6DCB
* ^
*
* @return None.
*******************************************************************************/
void no_os_crc24_populate_msb(uint32_t * table, const uint32_t polynomial)
{
if (!table)
return;
for (int16_t n = 0; n < NO_OS_CRC24_TABLE_SIZE; n++) {
uint32_t currByte = (uint32_t)(n << 16);
for (uint8_t bit = 0; bit < 8; bit++) {
if ((currByte & 0x800000) != 0) {
currByte &= 0x7FFFFF;
currByte <<= 1;
currByte ^= polynomial;
} else {
currByte <<= 1;
}
}
table[n] = currByte;
}
}
/***************************************************************************//**
* @brief Computes the CRC-24 over a buffer of data.
*
* @param table - Pointer to a CRC-24 lookup table for the desired polynomial.
* @param pdata - Pointer to data buffer.
* @param nbytes - Number of bytes to compute the CRC-24 over.
* @param crc - Initial value for the CRC-24 computation. Can be used to
* cascade calls to this function by providing a previous
* output of this function as the crc parameter.
*
* @return crc - Computed CRC-24 value.
*******************************************************************************/
uint32_t no_os_crc24(const uint32_t * table, const uint8_t *pdata,
size_t nbytes,
uint32_t crc)
{
unsigned int idx;
while (nbytes--) {
idx = ((crc >> 16) ^ *pdata) & 0xff;
crc = (table[idx] ^ (crc << 8)) & 0xffffff;
pdata++;
}
return (crc & 0xffffff);
}
@@ -0,0 +1,49 @@
/***************************************************************************//**
* @file no_os_crc24.h
* @brief Header file of CRC-24 computation.
* @author Antoniu Miclaus (antoniu.miclaus@analog.com)
********************************************************************************
* Copyright 2021(c) Analog Devices, Inc.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* 3. Neither the name of Analog Devices, Inc. nor the names of its
* contributors may be used to endorse or promote products derived from this
* software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY ANALOG DEVICES, INC. “AS IS” AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
* EVENT SHALL ANALOG DEVICES, INC. BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
* OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
* EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*******************************************************************************/
#ifndef _NO_OS_CRC24_H_
#define _NO_OS_CRC24_H_
#include <stdint.h>
#include <stddef.h>
#define NO_OS_CRC24_TABLE_SIZE 256
#define NO_OS_DECLARE_CRC24_TABLE(_table) \
static uint32_t _table[NO_OS_CRC24_TABLE_SIZE]
void no_os_crc24_populate_msb(uint32_t * table, const uint32_t polynomial);
uint32_t no_os_crc24(const uint32_t * table, const uint8_t *pdata,
size_t nbytes,
uint32_t crc);
#endif // _NO_OS_CRC24_H_
@@ -0,0 +1,94 @@
/***************************************************************************//**
* @file no_os_crc8.c
* @brief Source file of CRC-8 computation.
* @author Darius Berghe (darius.berghe@analog.com)
********************************************************************************
* Copyright 2020(c) Analog Devices, Inc.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* 3. Neither the name of Analog Devices, Inc. nor the names of its
* contributors may be used to endorse or promote products derived from this
* software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY ANALOG DEVICES, INC. “AS IS” AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
* EVENT SHALL ANALOG DEVICES, INC. BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
* OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
* EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*******************************************************************************/
#include "no_os_crc8.h"
/***************************************************************************//**
* @brief Creates the CRC-8 lookup table for a given polynomial.
*
* @param table - Pointer to a CRC-8 lookup table to write to.
* @param polynomial - msb-first representation of desired polynomial.
*
* Polynomials in CRC algorithms are typically represented as shown below.
*
* poly = x^8 + x^2 + x^1 + 1
*
* Using msb-first direction, x^7 maps to the msb.
*
* msb first: poly = (1)00000111 = 0x07
*
* @return None.
*******************************************************************************/
void no_os_crc8_populate_msb(uint8_t * table, const uint8_t polynomial)
{
if (!table)
return;
for (int16_t n = 0; n < NO_OS_CRC8_TABLE_SIZE; n++) {
uint8_t currByte = (uint8_t)n;
for (uint8_t bit = 0; bit < 8; bit++) {
if ((currByte & 0x80) != 0) {
currByte <<= 1;
currByte ^= polynomial;
} else {
currByte <<= 1;
}
}
table[n] = currByte;
}
}
/***************************************************************************//**
* @brief Computes the CRC-8 over a buffer of data.
*
* @param table - Pointer to a CRC-8 lookup table for the desired polynomial.
* @param pdata - Pointer to 8-bit data buffer.
* @param nbytes - Number of bytes to compute the CRC-8 over.
* @param crc - Initial value for the CRC-8 computation. Can be used to
* cascade calls to this function by providing a previous
* output of this function as the crc parameter.
*
* @return crc - Computed CRC-8 value.
*******************************************************************************/
uint8_t no_os_crc8(const uint8_t * table, const uint8_t *pdata, size_t nbytes,
uint8_t crc)
{
unsigned int idx;
while (nbytes--) {
idx = (crc ^ *pdata);
crc = (table[idx]) & 0xff;
pdata++;
}
return crc;
}
@@ -0,0 +1,48 @@
/***************************************************************************//**
* @file no_os_crc8.h
* @brief Header file of CRC-8 computation.
* @author Darius Berghe (darius.berghe@analog.com)
********************************************************************************
* Copyright 2020(c) Analog Devices, Inc.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* 3. Neither the name of Analog Devices, Inc. nor the names of its
* contributors may be used to endorse or promote products derived from this
* software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY ANALOG DEVICES, INC. “AS IS” AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
* EVENT SHALL ANALOG DEVICES, INC. BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
* OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
* EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*******************************************************************************/
#ifndef _NO_OS_CRC8_H_
#define _NO_OS_CRC8_H_
#include <stdint.h>
#include <stddef.h>
#define NO_OS_CRC8_TABLE_SIZE 256
#define NO_OS_DECLARE_CRC8_TABLE(_table) \
static uint8_t _table[NO_OS_CRC8_TABLE_SIZE]
void no_os_crc8_populate_msb(uint8_t * table, const uint8_t polynomial);
uint8_t no_os_crc8(const uint8_t * table, const uint8_t *pdata, size_t nbytes,
uint8_t crc);
#endif // _NO_OS_CRC8_H_
@@ -0,0 +1,56 @@
/***************************************************************************//**
* @file no_os_delay.h
* @brief Header file of Delay functions
* @author DBogdan (dragos.bogdan@analog.com)
********************************************************************************
* Copyright 2019(c) Analog Devices, Inc.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* 3. Neither the name of Analog Devices, Inc. nor the names of its
* contributors may be used to endorse or promote products derived from this
* software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY ANALOG DEVICES, INC. “AS IS” AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
* EVENT SHALL ANALOG DEVICES, INC. BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
* OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
* EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*******************************************************************************/
#ifndef _NO_OS_DELAY_H_
#define _NO_OS_DELAY_H_
#include <stdint.h>
/**
* @struct no_os_time
* @brief Structure holding time data (seconds, microseconds).
*/
struct no_os_time {
unsigned int s, us;
};
/* Generate microseconds delay. */
void no_os_udelay(uint32_t usecs);
/* Generate miliseconds delay. */
void no_os_mdelay(uint32_t msecs);
/* Get current time */
struct no_os_time no_os_get_time(void);
#endif // _NO_OS_DELAY_H_
@@ -0,0 +1,449 @@
/***************************************************************************//**
* @file no_os_dma.c
* @brief Platform independent implementation for the DMA API.
* @author Ciprian Regus (ciprian.regus@analog.com)
********************************************************************************
* Copyright 2024(c) Analog Devices, Inc.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* 3. Neither the name of Analog Devices, Inc. nor the names of its
* contributors may be used to endorse or promote products derived from this
* software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY ANALOG DEVICES, INC. “AS IS” AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
* EVENT SHALL ANALOG DEVICES, INC. BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
* OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
* EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*******************************************************************************/
#include <inttypes.h>
#include "no_os_dma.h"
#include <stdlib.h>
#include "no_os_error.h"
#include "no_os_mutex.h"
#include "no_os_irq.h"
#include "no_os_alloc.h"
#include "no_os_list.h"
/**
* @brief Default handler for cycling though the channel's list of transfers
* @param context - structure which stores the state of the current channel
* and DMA controller state.
*/
static void default_sg_callback(void *context)
{
struct no_os_dma_default_handler_data *data = context;
struct no_os_dma_xfer_desc *next_xfer;
struct no_os_dma_xfer_desc *old_xfer;
uint32_t list_size;
int ret;
/* Handle the next transfer from the SG list */
ret = no_os_list_get_first(data->channel->sg_list, (void **)&old_xfer);
if (ret) {
/*
* This should only happen if the list descriptor is NULL.
* The case in which there is no transfer left in the list should
* have been handled in the previous interrupt.
*/
no_os_dma_xfer_abort(data->desc, data->channel);
return;
}
no_os_list_read_first(data->channel->sg_list, (void **)&next_xfer);
no_os_list_get_size(data->channel->sg_list, &list_size);
if (old_xfer->xfer_complete_cb)
old_xfer->xfer_complete_cb(old_xfer, next_xfer,
old_xfer->xfer_complete_ctx);
if (!list_size) {
no_os_irq_disable(data->desc->irq_ctrl, data->channel->irq_num);
data->channel->free = true;
return;
}
data->desc->platform_ops->dma_config_xfer(data->channel, next_xfer);
no_os_dma_xfer_start(data->desc, data->channel);
}
/**
* @brief Initialize the DMA controller.
* @param desc - Structure containing the state of the DMA controller
* @param param - Initialization parameter for the DMA controller.
* @return 0 in case of success, negative error code otherwise.
*/
int no_os_dma_init(struct no_os_dma_desc **desc,
struct no_os_dma_init_param *param)
{
int ret;
uint32_t i, j;
void *mutex;
if (!param || !param->platform_ops)
return -EINVAL;
if (!param->platform_ops->dma_init)
return -ENOSYS;
no_os_mutex_init(&mutex);
no_os_mutex_lock(mutex);
ret = param->platform_ops->dma_init(desc, param);
if (ret)
goto unlock;
no_os_mutex_init(&(*desc)->mutex);
(*desc)->platform_ops = param->platform_ops;
for (i = 0; i < param->num_ch; i++) {
ret = no_os_list_init(&(*desc)->channels[i].sg_list, NO_OS_LIST_QUEUE, NULL);
if (ret)
goto list_err;
no_os_mutex_init(&(*desc)->channels[i].mutex);
}
(*desc)->ref++;
no_os_mutex_unlock(mutex);
return 0;
list_err:
for (j = 0; j < i; j++)
no_os_list_remove((*desc)->channels[i].sg_list);
no_os_dma_remove(*desc);
unlock:
no_os_mutex_unlock(mutex);
return ret;
}
/**
* @brief Remove resources allocated for the DMA controller.
* @param desc - Structure containing the state of the DMA controller
* @return 0 in case of success, negative error code otherwise.
*/
int no_os_dma_remove(struct no_os_dma_desc *desc)
{
uint32_t i;
int ret;
if (!desc)
return -EINVAL;
if (!desc->ref)
return 0;
for (i = 0; i < desc->num_ch; i++) {
ret = no_os_list_remove(desc->channels->sg_list);
if (ret)
return ret;
no_os_mutex_remove(desc->channels[i].mutex);
if (desc->irq_ctrl && desc->channels[i].cb_desc.handle) {
no_os_irq_unregister_callback(desc->irq_ctrl,
desc->channels[i].irq_num,
&desc->channels[i].cb_desc);
}
}
no_os_mutex_remove(desc->mutex);
ret = desc->platform_ops->dma_remove(desc);
if (ret)
return ret;
desc->ref--;
return 0;
}
/**
* @brief Get a free DMA channel.
* @param desc - Structure containing the state of the DMA controller.
* @param channel - Reference to the acquired channel.
* @return 0 in case of success, negative error code otherwise.
*/
int no_os_dma_acquire_channel(struct no_os_dma_desc *desc,
struct no_os_dma_ch **channel)
{
uint32_t ch_num;
int ret;
if (!desc || !desc->platform_ops)
return -EINVAL;
if (!desc->platform_ops->dma_acquire_ch)
return -ENOSYS;
no_os_mutex_lock(desc->mutex);
ret = desc->platform_ops->dma_acquire_ch(desc, &ch_num);
if (ret)
goto unlock;
*channel = &desc->channels[ch_num];
unlock:
no_os_mutex_unlock(desc->mutex);
return ret;
}
/**
* @brief Free DMA channel.
* @param desc - Structure containing the state of the DMA controller.
* @param channel - Reference to the currently acquired channel.
* @return 0 in case of success, negative error code otherwise.
*/
int no_os_dma_release_channel(struct no_os_dma_desc *desc,
struct no_os_dma_ch *channel)
{
int ret;
if (!desc || !desc->platform_ops || !channel)
return -EINVAL;
if (!desc->platform_ops->dma_release_ch)
return -ENOSYS;
no_os_mutex_lock(channel->mutex);
ret = desc->platform_ops->dma_release_ch(desc, channel->id);
no_os_mutex_unlock(channel->mutex);
return ret;
}
/**
* @brief Acquire a channel and configure the list of transfers.
* @param desc - Structure containing the state of the DMA controller
* @param xfer - Array of DMA transfers.
* @param len - The number of transfers in the xfer list.
* @param ch - Previously acquired channel, for which the transfer will be configured.
* @return 0 in case of success, negative error code otherwise.
*/
int no_os_dma_config_xfer(struct no_os_dma_desc *desc,
struct no_os_dma_xfer_desc *xfer,
uint32_t len, struct no_os_dma_ch *ch)
{
uint32_t i;
int ret;
void *discard;
struct no_os_callback_desc *sg_callback;
if (!desc || !xfer || !len || !ch)
return -EINVAL;
no_os_mutex_lock(ch->mutex);
/*
* Add the transfers to the channel's SG list. It's safe to do so, since
* there are no ongoing transfers on this channel.
*/
for (i = 0; i < len; i++)
no_os_list_add_last(ch->sg_list, &xfer[i]);
if (desc->irq_ctrl) {
sg_callback = &ch->cb_desc;
sg_callback->ctx = &ch->irq_ctx;
sg_callback->handle = (void *)ch->id;
sg_callback->peripheral = xfer[0].periph;
ch->irq_ctx.desc = desc;
ch->irq_ctx.channel = ch;
switch (xfer[0].xfer_type) {
case MEM_TO_DEV:
case MEM_TO_MEM:
sg_callback->event = NO_OS_EVT_DMA_TX_COMPLETE;
break;
case DEV_TO_MEM:
sg_callback->event = NO_OS_EVT_DMA_RX_COMPLETE;
break;
default:
ret = -EINVAL;
goto err;
}
ret = desc->platform_ops->dma_config_xfer(ch, xfer);
if (ret)
goto err;
if (desc->sg_handler)
sg_callback->callback = desc->sg_handler;
else
sg_callback->callback = default_sg_callback;
ret = no_os_irq_register_callback(desc->irq_ctrl,
ch->irq_num,
sg_callback);
if (ret)
goto err;
no_os_irq_set_priority(desc->irq_ctrl, ch->irq_num, xfer[0].irq_priority);
}
no_os_mutex_unlock(ch->mutex);
return 0;
err:
for (i = 0; i < len; i++)
no_os_list_get_first(ch->sg_list, &discard);
no_os_mutex_unlock(ch->mutex);
return ret;
}
/**
* @brief Lock a DMA channel, so it won't be acquired even if it's free.
* @param ch - Reference to the DMA channel
* @return 0 in case of success, -EINVAL if a NULL channel reference is provided.
*/
int no_os_dma_chan_lock(struct no_os_dma_ch *ch)
{
no_os_mutex_lock(ch->mutex);
if (!ch)
return -EINVAL;
ch->sync_lock = true;
no_os_mutex_unlock(ch->mutex);
return 0;
}
/**
* @brief Unlock a DMA channel, marking it available for acquisition.
* @param ch - Reference to the DMA channel
* @return 0 in case of success, -EINVAL if a NULL channel reference is provided.
*/
int no_os_dma_chan_unlock(struct no_os_dma_ch *ch)
{
no_os_mutex_lock(ch->mutex);
if (!ch)
return -EINVAL;
ch->sync_lock = false;
no_os_mutex_unlock(ch->mutex);
return 0;
}
/**
* @brief Acquire a channel and configure the list of transfers.
* @param desc - Structure containing the state of the DMA controller
* @param ch - Index for the channel we want to start the transfer on.
* @return 0 in case of success, negative error code otherwise.
*/
int no_os_dma_xfer_start(struct no_os_dma_desc *desc, struct no_os_dma_ch *ch)
{
int ret;
if (!desc || !desc->platform_ops || !ch)
return -EINVAL;
if (!desc->platform_ops->dma_xfer_start)
return -ENOSYS;
no_os_mutex_lock(ch->mutex);
if (desc->irq_ctrl)
no_os_irq_enable(desc->irq_ctrl, ch->irq_num);
ret = desc->platform_ops->dma_xfer_start(desc, ch);
no_os_mutex_unlock(ch->mutex);
return ret;
}
/**
* @brief Abort the ongoing and any other future transfers scheduled for a channel.
* @param desc - Structure containing the state of the DMA controller
* @param ch - Index for the channel we want to abort the transfer.
* @return 0 in case of success, negative error code otherwise.
*/
int no_os_dma_xfer_abort(struct no_os_dma_desc *desc, struct no_os_dma_ch *ch)
{
void *discard;
int ret;
if (!desc || !desc->platform_ops || !ch)
return -EINVAL;
if (!desc->platform_ops->dma_xfer_abort)
return -ENOSYS;
no_os_mutex_lock(ch->mutex);
if (desc->irq_ctrl)
no_os_irq_disable(desc->irq_ctrl, ch->irq_num);
do {
ret = no_os_list_get_first(ch->sg_list, &discard);
} while (!ret);
ret = desc->platform_ops->dma_xfer_abort(desc, ch);
no_os_mutex_unlock(ch->mutex);
return ret;
}
/**
* @brief Get the state of a DMA channel (free or not).
* @param desc - Reference to the DMA controller.
* @param ch - Reference to the DMA channel.
* @return true if a channel is free, false otherwise.
*/
bool no_os_dma_is_completed(struct no_os_dma_desc *desc,
struct no_os_dma_ch *ch)
{
(void)desc;
if (!ch)
return -EINVAL;
return ch->free;
}
/**
* @brief Whether or not there is a transfer in progress on a specific channel.
* @param desc - Reference to the DMA controller.
* @param ch - Reference to the DMA channel.
* @return true if a channel is free, false otherwise.
*/
bool no_os_dma_in_progress(struct no_os_dma_desc *desc, struct no_os_dma_ch *ch)
{
int ret;
if (!desc || !desc->platform_ops || !ch)
return -EINVAL;
if (!desc->platform_ops->dma_ch_in_progress)
return -ENOSYS;
no_os_mutex_lock(ch->mutex);
ret = desc->platform_ops->dma_ch_in_progress(desc, ch);
no_os_mutex_unlock(ch->mutex);
return ret;
}
@@ -0,0 +1,265 @@
/***************************************************************************//**
* @file no_os_dma.h
* @brief Platform independent function definitions and data types
* for the DMA API.
* @author Ciprian Regus (ciprian.regus@analog.com)
********************************************************************************
* Copyright 2024(c) Analog Devices, Inc.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* 3. Neither the name of Analog Devices, Inc. nor the names of its
* contributors may be used to endorse or promote products derived from this
* software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY ANALOG DEVICES, INC. “AS IS” AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
* EVENT SHALL ANALOG DEVICES, INC. BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
* OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
* EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*******************************************************************************/
#ifndef _NO_OS_DMA_H_
#define _NO_OS_DMA_H_
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#include "no_os_list.h"
#include "no_os_irq.h"
#include "no_os_mutex.h"
/**
* @enum no_os_dma_xfer_type
* @brief Supported transfer directions
*/
enum no_os_dma_xfer_type {
MEM_TO_MEM,
MEM_TO_DEV,
DEV_TO_MEM,
};
/**
* @struct no_os_dma_default_handler_data
* @brief IRQ parameter for the default inter transfer handler
*/
struct no_os_dma_default_handler_data {
struct no_os_dma_desc *desc;
struct no_os_dma_ch *channel;
void *extra;
};
struct no_os_dma_platform_ops;
/**
* @struct no_os_dma_xfer_desc
* @brief It's used to setup a generic DMA transfer.
*/
struct no_os_dma_xfer_desc {
/** Source address for the data */
uint8_t *src;
/** Destination address for the data */
uint8_t *dst;
/** Transfer length in bytes */
uint32_t length;
/** Transfer direction */
enum no_os_dma_xfer_type xfer_type;
/** This function will be called once the transfer completes. */
void (*xfer_complete_cb)(struct no_os_dma_xfer_desc *,
struct no_os_dma_xfer_desc *,
void *);
/**
* Parameter for the transfer complete callback. This data should
* be valid at least until the callback is invoked.
*/
void *xfer_complete_ctx;
/** Transfer complete interrupt priority level */
uint32_t irq_priority;
/**
* Peripheral which originated the transfer. Will be used to add
* the callback to the proper event list.
*/
enum no_os_irq_peripheral periph;
/** User or platform defined data */
void *extra;
};
/**
* @struct no_os_dma_ch
* @brief Describes the state of a DMA channel.
*/
struct no_os_dma_ch {
/** Channel number */
uint32_t id;
/** Whether or not there is a transfer in progress on this channel */
bool free;
/** List of transfers for this channel */
struct no_os_list_desc *sg_list;
/** Channel specific interrupt line number */
uint32_t irq_num;
/** irq callback */
struct no_os_callback_desc cb_desc;
/** IRQ parameter for the default inter transfer handler */
struct no_os_dma_default_handler_data irq_ctx;
void *extra;
/** Used to synchronize channel specific operations */
void *mutex;
/**
* Mark the channel as locked, in order to prevent it from being acquired
* even if it's free. Used as a synchronization mechanism between channels.
*/
bool sync_lock;
};
/**
* @struct no_os_dma_desc
* @brief Describes the state of the DMA controller.
*/
struct no_os_dma_desc {
/** Unique id of a DMA controller */
uint32_t id;
/** The number of channels associated with the controller */
uint32_t num_ch;
/** References to channels associated with the controller */
struct no_os_dma_ch *channels;
/** Platform specific DMA functions */
struct no_os_dma_platform_ops *platform_ops;
/**
* Interrupt controller configured by the platform specific DMA functions.
* May be left uninitialized,Start resulting in the interrupt handler not being
* called once a transfer completes. As such, the user (or platform code) has
* to provide the cycling mechanism.
*/
struct no_os_irq_ctrl_desc *irq_ctrl;
/** Platform specific data */
void *extra;
/** Reference counter */
uint32_t ref;
/** Used to synchronize DMA controller specific operations */
void *mutex;
/**
* Interrupt handler function called when a transfer is completed.
* It's used to configure the DMA controller for the next transfer in
* a channel's list.
*/
void (*sg_handler)(void *);
};
/**
* @struct no_os_dma_init_param
* @brief Initialization parameter for the DMA controller
*/
struct no_os_dma_init_param {
/** Unique id of a DMA controller */
uint32_t id;
/** The number of channels associated with the controller */
uint32_t num_ch;
/** Platform specific DMA functions */
struct no_os_dma_platform_ops *platform_ops;
/** Platform specific data */
void *extra;
/**
* Optional custom scatter gather callback. May be set to NULL in
* order to use the default one.
*/
void (*sg_handler)(void *);
/**
* Optional custom parameter for the scatter gather callback. Only takes
* effect if the handler is also provided.
*/
void *ctx;
};
/** Initialize a DMA controller. */
int no_os_dma_init(struct no_os_dma_desc **,
struct no_os_dma_init_param *);
/** Free the resources allocated by the DMA layer. Disables the DMA controller. */
int no_os_dma_remove(struct no_os_dma_desc *);
/** Acquire a channel and add the transfers to it's SG list. */
int no_os_dma_config_xfer(struct no_os_dma_desc *,
struct no_os_dma_xfer_desc *,
uint32_t,
struct no_os_dma_ch *);
/** Prevent a channel from being acquired, even if it's free. */
int no_os_dma_chan_lock(struct no_os_dma_ch *);
/** Allow a channel to be acquired, in case it's free. */
int no_os_dma_chan_unlock(struct no_os_dma_ch *);
/** Start the DMA transactions for a specific channel. */
int no_os_dma_xfer_start(struct no_os_dma_desc *, struct no_os_dma_ch *);
/**
* Stop the DMA transactions for a specific channel and remove the transfers
* from the SG list.
*/
int no_os_dma_xfer_abort(struct no_os_dma_desc *, struct no_os_dma_ch *);
/**
* Check whether a transfer is complete. By default, it requires the interrupt
* handler to set the free flag for the channel.
*/
bool no_os_dma_is_completed(struct no_os_dma_desc *, struct no_os_dma_ch *);
/** Whether or not a specific channel has an ongoing transfer. */
bool no_os_dma_in_progress(struct no_os_dma_desc *, struct no_os_dma_ch *);
/** Get a free DMA channel. */
int no_os_dma_acquire_channel(struct no_os_dma_desc *, struct no_os_dma_ch **);
/** Free a DMA channel. */
int no_os_dma_release_channel(struct no_os_dma_desc *, struct no_os_dma_ch *);
/**
* @struct no_os_irq_platform_ops
* @brief Structure holding IRQ function pointers that point to the platform
* specific function
*/
struct no_os_dma_platform_ops {
/** Initialize platform specific resources for the DMA controller. */
int (*dma_init)(struct no_os_dma_desc **, struct no_os_dma_init_param *);
/** Remove resources allocated for the DMA controller. */
int (*dma_remove)(struct no_os_dma_desc *desc);
/** Get a free channel and set it as busy. */
int (*dma_acquire_ch)(struct no_os_dma_desc *, uint32_t *);
int (*dma_release_ch)(struct no_os_dma_desc *, uint32_t);
/** Configure platform specific settings required for the current DMA transfer */
int (*dma_config_xfer)(struct no_os_dma_ch *,
struct no_os_dma_xfer_desc *);
/** Signal the DMA controller to start the transfer. */
int (*dma_xfer_start)(struct no_os_dma_desc *, struct no_os_dma_ch *);
/** Signal the DMA controller to stop the transfer. */
int (*dma_xfer_abort)(struct no_os_dma_desc *, struct no_os_dma_ch *);
/** Whether or not a specific channel has an ongoing or future transfer configured */
bool (*dma_ch_is_completed)(struct no_os_dma_desc *, struct no_os_dma_ch *);
/**
* Whether or not a specific channel has an ongoing transfer.
* This returns true between transfers.
*/
bool (*dma_ch_in_progress)(struct no_os_dma_desc *, struct no_os_dma_ch *);
};
#endif
@@ -0,0 +1,119 @@
/***************************************************************************//**
* @file no_os_eeprom.c
* @brief Implementation of the EEPROM APIs
* @author Mahesh Phalke (mahesh.phalke@analog.com)
********************************************************************************
* Copyright 2022(c) Analog Devices, Inc.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* 3. Neither the name of Analog Devices, Inc. nor the names of its
* contributors may be used to endorse or promote products derived from this
* software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY ANALOG DEVICES, INC. “AS IS” AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
* EVENT SHALL ANALOG DEVICES, INC. BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
* OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
* EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*******************************************************************************/
#include <inttypes.h>
#include <stdlib.h>
#include "no_os_eeprom.h"
#include "no_os_error.h"
/**
* @brief Initialize the EEPROM
* @param desc - EEPROM descriptor
* @param param - EEPROM init parameters
* @return 0 in case of success, negative error code otherwise
*/
int32_t no_os_eeprom_init(struct no_os_eeprom_desc **desc,
const struct no_os_eeprom_init_param *param)
{
int32_t ret;
if (!param || !param->platform_ops)
return -EINVAL;
if (!param->platform_ops->init)
return -ENOSYS;
ret = param->platform_ops->init(desc, param);
if (ret)
return ret;
(*desc)->platform_ops = param->platform_ops;
return 0;
}
/**
* @brief Free the resources allocated by no_os_eeprom_init()
* @param desc - EEPROM descriptor
* @return 0 in case of success, negative error code otherwise
*/
int32_t no_os_eeprom_remove(struct no_os_eeprom_desc *desc)
{
if (!desc || !desc->platform_ops)
return -EINVAL;
if (!desc->platform_ops->remove)
return -ENOSYS;
return desc->platform_ops->remove(desc);
}
/**
* @brief Write the EEPROM data
* @param desc - EEPROM descriptor
* @param address - EEPROM address/location to write
* @param data - EEPROM data (pointer)
* @param bytes - Number of data bytes to write
* @return 0 in case of success, negative error code otherwise
*/
int32_t no_os_eeprom_write(struct no_os_eeprom_desc *desc, uint32_t address,
uint8_t *data, uint16_t bytes)
{
if (!desc || !desc->platform_ops || !data)
return -EINVAL;
if (!desc->platform_ops->write)
return -ENOSYS;
return desc->platform_ops->write(desc, address, data, bytes);
}
/**
* @brief Read the EEPROM data
* @param desc - EEPROM descriptor
* @param address - EEPROM address/location to read
* @param data - EEPROM data (pointer)
* @param bytes - Number of data bytes to read
* @return 0 in case of success, negative error code otherwise
*/
int32_t no_os_eeprom_read(struct no_os_eeprom_desc *desc, uint32_t address,
uint8_t *data, uint16_t bytes)
{
if (!desc || !desc->platform_ops || !data)
return -EINVAL;
if (!desc->platform_ops->read)
return -ENOSYS;
return desc->platform_ops->read(desc, address, data, bytes);
}
@@ -0,0 +1,99 @@
/***************************************************************************//**
* @file no_os_eeprom.h
* @brief Header file for EEPROM APIs
* @author Mahesh Phalke (mahesh.phalke@analog.com)
********************************************************************************
* Copyright 2022(c) Analog Devices, Inc.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* 3. Neither the name of Analog Devices, Inc. nor the names of its
* contributors may be used to endorse or promote products derived from this
* software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY ANALOG DEVICES, INC. “AS IS” AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
* EVENT SHALL ANALOG DEVICES, INC. BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
* OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
* EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*******************************************************************************/
#ifndef _NO_OS_EEPROM_H_
#define _NO_OS_EEPROM_H_
#include <stdint.h>
/* Forward declaration of structure */
struct no_os_eeprom_platform_ops;
/**
* @struct no_os_eeprom_init_param
* @brief Structure holding the parameters for EEPROM initialization
*/
struct no_os_eeprom_init_param {
/** Device ID */
uint32_t device_id;
const struct no_os_eeprom_platform_ops *platform_ops;
/** EEPROM extra parameters (device specific) */
void *extra;
};
/**
* @struct no_os_eeprom_desc
* @brief Structure holding the EEPROM descriptor
*/
struct no_os_eeprom_desc {
/** Device ID */
uint32_t device_id;
const struct no_os_eeprom_platform_ops *platform_ops;
/** EEPROM extra parameters (device specific) */
void *extra;
};
/**
* @struct no_os_eeprom_platform_ops
* @brief Structure holding the EEPROM function pointers that point to the
* platform specific function
*/
struct no_os_eeprom_platform_ops {
/** EEPROM initialization function pointer */
int32_t (*init)(struct no_os_eeprom_desc **,
const struct no_os_eeprom_init_param *);
/** EEPROM data write function pointer */
int32_t (*write)(struct no_os_eeprom_desc *, uint32_t, uint8_t *, uint16_t);
/** EEPROM data read function pointer */
int32_t (*read)(struct no_os_eeprom_desc *, uint32_t, uint8_t *, uint16_t);
/** EEPROM remove function pointer */
int32_t (*remove)(struct no_os_eeprom_desc *);
};
/* Initialize the EEPROM */
int32_t no_os_eeprom_init(struct no_os_eeprom_desc **desc,
const struct no_os_eeprom_init_param *param);
/* Write into EEPROM */
int32_t no_os_eeprom_write(struct no_os_eeprom_desc *desc, uint32_t address,
uint8_t *data, uint16_t bytes);
/* Read from EEPROM */
int32_t no_os_eeprom_read(struct no_os_eeprom_desc *desc, uint32_t address,
uint8_t *data, uint16_t bytes);
/* Free the resources allocated by no_os_eeprom_init() */
int32_t no_os_eeprom_remove(struct no_os_eeprom_desc *desc);
#endif // _NO_OS_EEPROM_H_
@@ -0,0 +1,48 @@
/***************************************************************************//**
* @file no_os_error.h
* @brief Error codes definition
* @author DBogdan (dragos.bogdan@analog.com)
********************************************************************************
* Copyright 2019(c) Analog Devices, Inc.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* 3. Neither the name of Analog Devices, Inc. nor the names of its
* contributors may be used to endorse or promote products derived from this
* software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY ANALOG DEVICES, INC. “AS IS” AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
* EVENT SHALL ANALOG DEVICES, INC. BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
* OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
* EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*******************************************************************************/
#ifndef _NO_OS_ERROR_H_
#define _NO_OS_ERROR_H_
#include <errno.h>
#ifndef __NO_OS_ELASTERROR
#define __NO_OS_ELASTERROR 2000
#endif
#define NO_OS_EOVERRUN (__NO_OS_ELASTERROR + 1) /* Circular buffer overrun */
#define NO_OS_IS_ERR_VALUE(x) ((x) < 0)
#endif // _NO_OS_ERROR_H_
@@ -0,0 +1,126 @@
/***************************************************************************//**
* @file no_os_fifo.c
* @brief Implementation of fifo.
* @author Cristian Pop (cristian.pop@analog.com)
********************************************************************************
* Copyright 2019(c) Analog Devices, Inc.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* 3. Neither the name of Analog Devices, Inc. nor the names of its
* contributors may be used to endorse or promote products derived from this
* software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY ANALOG DEVICES, INC. “AS IS” AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
* EVENT SHALL ANALOG DEVICES, INC. BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
* OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
* EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*******************************************************************************/
#include <string.h>
#include <stdlib.h>
#include "no_os_fifo.h"
#include "no_os_error.h"
#include "no_os_alloc.h"
/**
* @brief Create new fifo element
* @param buff - Data to be saved in fifo.
* @param len - Length of the data.
* @return fifo element in case of success, NULL otherwise
*/
static struct no_os_fifo_element * fifo_new_element(char *buff, uint32_t len)
{
struct no_os_fifo_element *q = no_os_calloc(1,
sizeof(struct no_os_fifo_element));
if (!q)
return NULL;
q->len = len;
q->data = no_os_calloc(1, len);
if (!(q->data)) {
no_os_free(q);
return NULL;
}
memcpy(q->data, buff, len);
return q;
}
/**
* @brief Get last element in fifo
* @param p_fifo - pointer to fifo
* @return fifo last element if exists, NULL otherwise
*/
static struct no_os_fifo_element *no_os_fifo_get_last(struct no_os_fifo_element
*p_fifo)
{
if (p_fifo == NULL)
return NULL;
while (p_fifo->next) {
p_fifo = p_fifo->next;
}
return p_fifo;
}
/**
* @brief Insert element to fifo, in the last position.
* @param p_fifo - Pointer to fifo.
* @param buff - Data to be saved in fifo.
* @param len - Length of the data.
* @return 0 in case of success, -1 otherwise
*/
int32_t no_os_fifo_insert(struct no_os_fifo_element **p_fifo, char *buff,
uint32_t len)
{
struct no_os_fifo_element *p, *q;
if (len <= 0)
return -1;
q = fifo_new_element(buff, len);
if (!q)
return -1;
if (!(*p_fifo)) {
*p_fifo = q;
} else {
p = no_os_fifo_get_last(*p_fifo);
p->next = q;
}
return 0;
}
/**
* @brief Remove fifo head
* @param p_fifo - Pointer to fifo.
* @return next element in fifo if exists, NULL otherwise.
*/
struct no_os_fifo_element * no_os_fifo_remove(struct no_os_fifo_element *p_fifo)
{
struct no_os_fifo_element *p = p_fifo;
if (p_fifo != NULL) {
p_fifo = p_fifo->next;
no_os_free(p->data);
no_os_free(p);
}
return p_fifo;
}
@@ -0,0 +1,58 @@
/***************************************************************************//**
* @file no_os_fifo.h
* @brief Header file of fifo
* @author Cristian Pop (cristian.pop@analog.com)
********************************************************************************
* Copyright 2019(c) Analog Devices, Inc.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* 3. Neither the name of Analog Devices, Inc. nor the names of its
* contributors may be used to endorse or promote products derived from this
* software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY ANALOG DEVICES, INC. “AS IS” AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
* EVENT SHALL ANALOG DEVICES, INC. BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
* OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
* EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*******************************************************************************/
#ifndef _NO_OS_FIFO_H_
#define _NO_OS_FIFO_H_
#include <stdint.h>
/**
* @struct no_os_fifo_element
* @brief Structure holding the fifo element parameters.
*/
struct no_os_fifo_element {
/** next FIFO element */
struct no_os_fifo_element *next;
/** FIFO data pointer */
char *data;
/** FIFO length */
uint32_t len;
};
/* Insert element to fifo tail. */
int32_t no_os_fifo_insert(struct no_os_fifo_element **p_fifo, char *buff,
uint32_t len);
/* Remove fifo head. */
struct no_os_fifo_element *no_os_fifo_remove(struct no_os_fifo_element *p_fifo);
#endif // _NO_OS_FIFO_H_
@@ -0,0 +1,96 @@
/***************************************************************************//**
* @file no_os_flash.h
* @brief Header file for flash controller driver.
* @author Andrei Drimbarean (andrei.drimbarean@analog.com)
********************************************************************************
* Copyright 2021(c) Analog Devices, Inc.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* 3. Neither the name of Analog Devices, Inc. nor the names of its
* contributors may be used to endorse or promote products derived from this
* software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY ANALOG DEVICES, INC. “AS IS” AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
* EVENT SHALL ANALOG DEVICES, INC. BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
* OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
* EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*******************************************************************************/
#ifndef _NO_OS_FLASH_H_
#define _NO_OS_FLASH_H_
#include <stdint.h>
/**
* @struct no_os_flash_dev
* @brief Flash controller device structure
*/
struct no_os_flash_dev {
/** Flash Device ID */
uint8_t id;
/** Size of flash memory in bytes */
uint32_t flash_size;
/** Size of flash page in bytes */
uint32_t page_size;
/** Flash extra parameters */
void *extra;
};
/**
* @struct no_os_flash_init_param
* @brief Flash controller initialization structure
*/
struct no_os_flash_init_param {
/** Flash Device ID */
uint8_t id;
/** Size of flash memory in bytes */
uint32_t flash_size;
/** Size of flash page in bytes */
uint32_t flash_page_size;
/** Flash extra parameters */
void *extra;
};
/** Initialize flash controller. */
int32_t no_os_flash_init(struct no_os_flash_dev **device,
struct no_os_flash_init_param *init_param);
/** Free memory allocated by no_os_flash_init(). */
int32_t no_os_flash_remove(struct no_os_flash_dev *dev);
/** Erase a flash page. */
int32_t no_os_flash_clear_page(struct no_os_flash_dev *dev, int32_t page_no);
/** Write a flash page. */
int32_t no_os_flash_write_page(struct no_os_flash_dev *dev, int32_t page_no,
uint32_t *data);
/** Read a flash page. */
int32_t flash_read_page(struct no_os_flash_dev *dev, int32_t page_no,
uint32_t *data);
/** Write data in flash memory. */
int32_t no_os_flash_write(struct no_os_flash_dev *dev, uint32_t flash_addr,
uint32_t *array, uint32_t array_size);
/** Read data from the flash memory. */
int32_t no_os_flash_read(struct no_os_flash_dev *dev, uint32_t flash_addr,
uint32_t *array,
uint32_t size);
#endif // _NO_OS_FLASH_H_
@@ -0,0 +1,166 @@
/***************************************************************************//**
* @file no_os_font_8x8.c
* @brief Font style for 8x8 characters.
* @author Andrei Porumb (andrei.porumb@analog.com)
********************************************************************************
* Copyright 2021(c) Analog Devices, Inc.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* 3. Neither the name of Analog Devices, Inc. nor the names of its
* contributors may be used to endorse or promote products derived from this
* software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY ANALOG DEVICES, INC. “AS IS” AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
* EVENT SHALL ANALOG DEVICES, INC. BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
* OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
* EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*******************************************************************************/
#include <stdint.h>
/* ASCII to bitmap */
const uint8_t no_os_chr_8x8[128][8] = {
{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},
{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},
{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},
{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},
{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},
{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},
{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},
{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},
{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},
{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},
{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},
{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},
{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},
{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},
{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},
{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},
{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},
{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},
{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},
{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},
{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},
{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},
{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},
{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},
{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},
{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},
{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},
{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},
{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},
{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},
{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},
{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},
{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},
{0x00, 0x00, 0x00, 0x5f, 0x00, 0x00, 0x00, 0x00},
{0x00, 0x00, 0x03, 0x00, 0x03, 0x00, 0x00, 0x00},
{0x64, 0x3c, 0x26, 0x64, 0x3c, 0x26, 0x24, 0x00},
{0x26, 0x49, 0x49, 0x7f, 0x49, 0x49, 0x32, 0x00},
{0x42, 0x25, 0x12, 0x08, 0x24, 0x52, 0x21, 0x00},
{0x20, 0x50, 0x4e, 0x55, 0x22, 0x58, 0x28, 0x00},
{0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00},
{0x00, 0x00, 0x1c, 0x22, 0x41, 0x00, 0x00, 0x00},
{0x00, 0x00, 0x00, 0x41, 0x22, 0x1c, 0x00, 0x00},
{0x00, 0x15, 0x15, 0x0e, 0x0e, 0x15, 0x15, 0x00},
{0x00, 0x08, 0x08, 0x3e, 0x08, 0x08, 0x00, 0x00},
{0x00, 0x00, 0x00, 0x50, 0x30, 0x00, 0x00, 0x00},
{0x00, 0x08, 0x08, 0x08, 0x08, 0x08, 0x00, 0x00},
{0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00, 0x00},
{0x40, 0x20, 0x10, 0x08, 0x04, 0x02, 0x01, 0x00},
{0x00, 0x3e, 0x41, 0x41, 0x41, 0x3e, 0x00, 0x00},
{0x00, 0x00, 0x41, 0x7f, 0x40, 0x00, 0x00, 0x00},
{0x00, 0x42, 0x61, 0x51, 0x49, 0x6e, 0x00, 0x00},
{0x00, 0x22, 0x41, 0x49, 0x49, 0x36, 0x00, 0x00},
{0x00, 0x18, 0x14, 0x12, 0x7f, 0x10, 0x00, 0x00},
{0x00, 0x27, 0x49, 0x49, 0x49, 0x71, 0x00, 0x00},
{0x00, 0x3c, 0x4a, 0x49, 0x48, 0x70, 0x00, 0x00},
{0x00, 0x43, 0x21, 0x11, 0x0d, 0x03, 0x00, 0x00},
{0x00, 0x36, 0x49, 0x49, 0x49, 0x36, 0x00, 0x00},
{0x00, 0x06, 0x09, 0x49, 0x29, 0x1e, 0x00, 0x00},
{0x00, 0x00, 0x00, 0x12, 0x00, 0x00, 0x00, 0x00},
{0x00, 0x00, 0x00, 0x52, 0x30, 0x00, 0x00, 0x00},
{0x00, 0x00, 0x08, 0x14, 0x14, 0x22, 0x00, 0x00},
{0x00, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x00},
{0x00, 0x00, 0x22, 0x14, 0x14, 0x08, 0x00, 0x00},
{0x00, 0x02, 0x01, 0x59, 0x05, 0x02, 0x00, 0x00},
{0x3e, 0x41, 0x5d, 0x55, 0x4d, 0x51, 0x2e, 0x00},
{0x40, 0x7c, 0x4a, 0x09, 0x4a, 0x7c, 0x40, 0x00},
{0x41, 0x7f, 0x49, 0x49, 0x49, 0x49, 0x36, 0x00},
{0x1c, 0x22, 0x41, 0x41, 0x41, 0x41, 0x22, 0x00},
{0x41, 0x7f, 0x41, 0x41, 0x41, 0x22, 0x1c, 0x00},
{0x41, 0x7f, 0x49, 0x49, 0x5d, 0x41, 0x63, 0x00},
{0x41, 0x7f, 0x49, 0x09, 0x1d, 0x01, 0x03, 0x00},
{0x1c, 0x22, 0x41, 0x49, 0x49, 0x3a, 0x08, 0x00},
{0x41, 0x7f, 0x08, 0x08, 0x08, 0x7f, 0x41, 0x00},
{0x00, 0x41, 0x41, 0x7F, 0x41, 0x41, 0x00, 0x00},
{0x30, 0x40, 0x41, 0x41, 0x3F, 0x01, 0x01, 0x00},
{0x41, 0x7f, 0x08, 0x0c, 0x12, 0x61, 0x41, 0x00},
{0x41, 0x7f, 0x41, 0x40, 0x40, 0x40, 0x60, 0x00},
{0x41, 0x7f, 0x42, 0x0c, 0x42, 0x7f, 0x41, 0x00},
{0x41, 0x7f, 0x42, 0x0c, 0x11, 0x7f, 0x01, 0x00},
{0x1c, 0x22, 0x41, 0x41, 0x41, 0x22, 0x1c, 0x00},
{0x41, 0x7f, 0x49, 0x09, 0x09, 0x09, 0x06, 0x00},
{0x0c, 0x12, 0x21, 0x21, 0x61, 0x52, 0x4c, 0x00},
{0x41, 0x7f, 0x09, 0x09, 0x19, 0x69, 0x46, 0x00},
{0x66, 0x49, 0x49, 0x49, 0x49, 0x49, 0x33, 0x00},
{0x03, 0x01, 0x41, 0x7f, 0x41, 0x01, 0x03, 0x00},
{0x01, 0x3f, 0x41, 0x40, 0x41, 0x3f, 0x01, 0x00},
{0x01, 0x0f, 0x31, 0x40, 0x31, 0x0f, 0x01, 0x00},
{0x01, 0x1f, 0x61, 0x14, 0x61, 0x1f, 0x01, 0x00},
{0x41, 0x41, 0x36, 0x08, 0x36, 0x41, 0x41, 0x00},
{0x01, 0x03, 0x44, 0x78, 0x44, 0x03, 0x01, 0x00},
{0x43, 0x61, 0x51, 0x49, 0x45, 0x43, 0x61, 0x00},
{0x00, 0x00, 0x7f, 0x41, 0x41, 0x00, 0x00, 0x00},
{0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x00},
{0x00, 0x00, 0x41, 0x41, 0x7f, 0x00, 0x00, 0x00},
{0x00, 0x04, 0x02, 0x01, 0x01, 0x02, 0x04, 0x00},
{0x00, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x00},
{0x00, 0x01, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00},
{0x00, 0x34, 0x4a, 0x4a, 0x4a, 0x3c, 0x40, 0x00},
{0x00, 0x41, 0x3f, 0x48, 0x48, 0x48, 0x30, 0x00},
{0x00, 0x3c, 0x42, 0x42, 0x42, 0x24, 0x00, 0x00},
{0x00, 0x30, 0x48, 0x48, 0x49, 0x3f, 0x40, 0x00},
{0x00, 0x3c, 0x4a, 0x4a, 0x4a, 0x2c, 0x00, 0x00},
{0x00, 0x00, 0x48, 0x7e, 0x49, 0x09, 0x00, 0x00},
{0x00, 0x26, 0x49, 0x49, 0x49, 0x3f, 0x01, 0x00},
{0x41, 0x7f, 0x48, 0x04, 0x44, 0x78, 0x40, 0x00},
{0x00, 0x00, 0x44, 0x7d, 0x40, 0x00, 0x00, 0x00},
{0x00, 0x00, 0x40, 0x44, 0x3d, 0x00, 0x00, 0x00},
{0x41, 0x7f, 0x10, 0x18, 0x24, 0x42, 0x42, 0x00},
{0x00, 0x40, 0x41, 0x7f, 0x40, 0x40, 0x00, 0x00},
{0x42, 0x7e, 0x02, 0x7c, 0x02, 0x7e, 0x40, 0x00},
{0x42, 0x7e, 0x44, 0x02, 0x42, 0x7c, 0x40, 0x00},
{0x00, 0x3c, 0x42, 0x42, 0x42, 0x3c, 0x00, 0x00},
{0x00, 0x41, 0x7f, 0x49, 0x09, 0x09, 0x06, 0x00},
{0x00, 0x06, 0x09, 0x09, 0x49, 0x7f, 0x41, 0x00},
{0x00, 0x42, 0x7e, 0x44, 0x02, 0x02, 0x04, 0x00},
{0x00, 0x64, 0x4a, 0x4a, 0x4a, 0x36, 0x00, 0x00},
{0x00, 0x04, 0x3f, 0x44, 0x44, 0x20, 0x00, 0x00},
{0x00, 0x02, 0x3e, 0x40, 0x40, 0x22, 0x7e, 0x40},
{0x02, 0x0e, 0x32, 0x40, 0x32, 0x0e, 0x02, 0x00},
{0x02, 0x1e, 0x62, 0x18, 0x62, 0x1e, 0x02, 0x00},
{0x42, 0x62, 0x14, 0x08, 0x14, 0x62, 0x42, 0x00},
{0x01, 0x43, 0x45, 0x38, 0x05, 0x03, 0x01, 0x00},
{0x00, 0x46, 0x62, 0x52, 0x4a, 0x46, 0x62, 0x00},
{0x00, 0x00, 0x08, 0x36, 0x41, 0x00, 0x00, 0x00},
{0x00, 0x00, 0x00, 0x7f, 0x00, 0x00, 0x00, 0x00},
{0x00, 0x00, 0x00, 0x41, 0x36, 0x08, 0x00, 0x00},
{0x00, 0x18, 0x08, 0x08, 0x10, 0x10, 0x18, 0x00},
{0xAA, 0x55, 0xAA, 0x55, 0xAA, 0x55, 0xAA, 0x55}
};
@@ -0,0 +1,231 @@
/***************************************************************************//**
* @file no_os_gpio.c
* @brief Implementation of the GPIO Interface
* @author Antoniu Miclaus (antoniu.miclaus@analog.com)
********************************************************************************
* Copyright 2020(c) Analog Devices, Inc.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* 3. Neither the name of Analog Devices, Inc. nor the names of its
* contributors may be used to endorse or promote products derived from this
* software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY ANALOG DEVICES, INC. “AS IS” AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
* EVENT SHALL ANALOG DEVICES, INC. BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
* OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
* EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*******************************************************************************/
#include <inttypes.h>
#include "no_os_gpio.h"
#include <stdlib.h>
#include "no_os_error.h"
/**
* @brief Obtain the GPIO decriptor.
* @param desc - The GPIO descriptor.
* @param param - GPIO Initialization parameters.
* @return 0 in case of success, -1 otherwise.
*/
int32_t no_os_gpio_get(struct no_os_gpio_desc **desc,
const struct no_os_gpio_init_param *param)
{
int32_t ret;
if (!param || !param->platform_ops)
return -EINVAL;
if (!param->platform_ops->gpio_ops_get)
return -ENOSYS;
ret = param->platform_ops->gpio_ops_get(desc, param);
if (ret)
return ret;
(*desc)->platform_ops = param->platform_ops;
return 0;
}
/**
* @brief Get the value of an optional GPIO.
* @param desc - The GPIO descriptor.
* @param param - GPIO Initialization parameters.
* @return 0 in case of success, -1 otherwise.
*/
int32_t no_os_gpio_get_optional(struct no_os_gpio_desc **desc,
const struct no_os_gpio_init_param *param)
{
int32_t ret;
if (!param || (param->number == -1)) {
*desc = NULL;
return 0;
}
if (!param->platform_ops)
return -EINVAL;
if (!param->platform_ops->gpio_ops_get_optional)
return -ENOSYS;
ret = param->platform_ops->gpio_ops_get_optional(desc, param);
if (ret)
return ret;
(*desc)->platform_ops = param->platform_ops;
return 0;
}
/**
* @brief Free the resources allocated by no_os_gpio_get().
* @param desc - The GPIO descriptor.
* @return 0 in case of success, -1 otherwise.
*/
int32_t no_os_gpio_remove(struct no_os_gpio_desc *desc)
{
if (desc) {
if (!desc->platform_ops)
return -EINVAL;
if (!desc->platform_ops->gpio_ops_remove)
return -ENOSYS;
return desc->platform_ops->gpio_ops_remove(desc);
}
return 0;
}
/**
* @brief Enable the input direction of the specified GPIO.
* @param desc - The GPIO descriptor.
* @return 0 in case of success, -1 otherwise.
*/
int32_t no_os_gpio_direction_input(struct no_os_gpio_desc *desc)
{
if (desc) {
if (!desc->platform_ops)
return -EINVAL;
if (!desc->platform_ops->gpio_ops_direction_input)
return -ENOSYS;
return desc->platform_ops->gpio_ops_direction_input(desc);
}
return 0;
}
/**
* @brief Enable the output direction of the specified GPIO.
* @param desc - The GPIO descriptor.
* @param value - The value.
* Example: NO_OS_GPIO_HIGH
* NO_OS_GPIO_LOW
* @return 0 in case of success, -1 otherwise.
*/
int32_t no_os_gpio_direction_output(struct no_os_gpio_desc *desc,
uint8_t value)
{
if (desc) {
if (!desc->platform_ops)
return -EINVAL;
if (!desc->platform_ops->gpio_ops_direction_output)
return -ENOSYS;
return desc->platform_ops->
gpio_ops_direction_output(desc, value);
}
return 0;
}
/**
* @brief Get the direction of the specified GPIO.
* @param desc - The GPIO descriptor.
* @param direction - The direction.
* Example: NO_OS_GPIO_OUT
* NO_OS_GPIO_IN
* @return 0 in case of success, -1 otherwise.
*/
int32_t no_os_gpio_get_direction(struct no_os_gpio_desc *desc,
uint8_t *direction)
{
if (desc) {
if (!desc->platform_ops)
return -EINVAL;
if (!desc->platform_ops->gpio_ops_get_direction)
return -ENOSYS;
return desc->platform_ops->
gpio_ops_get_direction(desc, direction);
}
return 0;
}
/**
* @brief Set the value of the specified GPIO.
* @param desc - The GPIO descriptor.
* @param value - The value.
* Example: NO_OS_GPIO_HIGH
* NO_OS_GPIO_LOW
* @return 0 in case of success, -1 otherwise.
*/
int32_t no_os_gpio_set_value(struct no_os_gpio_desc *desc,
uint8_t value)
{
if (desc) {
if (!desc->platform_ops)
return -EINVAL;
if (!desc->platform_ops->gpio_ops_set_value)
return -ENOSYS;
return desc->platform_ops->gpio_ops_set_value(desc, value);
}
return 0;
}
/**
* @brief Get the value of the specified GPIO.
* @param desc - The GPIO descriptor.
* @param value - The value.
* Example: NO_OS_GPIO_HIGH
* NO_OS_GPIO_LOW
* @return 0 in case of success, -1 otherwise.
*/
int32_t no_os_gpio_get_value(struct no_os_gpio_desc *desc,
uint8_t *value)
{
if (desc) {
if (!desc->platform_ops)
return -EINVAL;
if (!desc->platform_ops->gpio_ops_set_value)
return -ENOSYS;
return desc->platform_ops->gpio_ops_get_value(desc, value);
}
return 0;
}
@@ -0,0 +1,166 @@
/***************************************************************************//**
* @file no_os_gpio.h
* @brief Header file of GPIO Interface
* @author DBogdan (dragos.bogdan@analog.com)
********************************************************************************
* Copyright 2019(c) Analog Devices, Inc.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* 3. Neither the name of Analog Devices, Inc. nor the names of its
* contributors may be used to endorse or promote products derived from this
* software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY ANALOG DEVICES, INC. “AS IS” AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
* EVENT SHALL ANALOG DEVICES, INC. BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
* OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
* EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*******************************************************************************/
#ifndef _NO_OS_GPIO_H_
#define _NO_OS_GPIO_H_
#include <stdint.h>
#define NO_OS_GPIO_OUT 0x01
#define NO_OS_GPIO_IN 0x00
/**
* @struct no_os_gpio_platform_ops
* @brief Structure holding gpio function pointers that point to the platform
* specific function
*/
struct no_os_gpio_platform_ops ;
/**
* @enum no_os_gpio_pull_up
* @brief Enum that holds the possible pull up/ pull down resistor configuration.
*/
enum no_os_gpio_pull_up {
NO_OS_PULL_NONE,
/** Strong pull up */
NO_OS_PULL_UP,
/** Strong pull down */
NO_OS_PULL_DOWN,
NO_OS_PULL_UP_WEAK,
NO_OS_PULL_DOWN_WEAK
};
/**
* @struct no_os_gpio_init_param
* @brief Structure holding the parameters for GPIO initialization.
*/
struct no_os_gpio_init_param {
/** Port number */
int32_t port;
/** GPIO number */
int32_t number;
/** Pull up/down resistor configuration */
enum no_os_gpio_pull_up pull;
/** GPIO platform specific functions */
const struct no_os_gpio_platform_ops *platform_ops;
/** GPIO extra parameters (device specific) */
void *extra;
};
/**
* @struct no_os_gpio_desc
* @brief Structure holding the GPIO descriptor.
*/
struct no_os_gpio_desc {
/** Port number */
int32_t port;
/** GPIO number */
int32_t number;
/** Pull up/down resistor configuration */
enum no_os_gpio_pull_up pull;
/** GPIO platform specific functions */
const struct no_os_gpio_platform_ops *platform_ops;
/** GPIO extra parameters (device specific) */
void *extra;
};
/**
* @enum no_os_gpio_values
* @brief Enum that holds the possible output states of a GPIO.
*/
enum no_os_gpio_values {
/** GPIO logic low */
NO_OS_GPIO_LOW,
/** GPIO logic high */
NO_OS_GPIO_HIGH,
/** GPIO high impedance */
NO_OS_GPIO_HIGH_Z
};
/**
* @struct no_os_gpio_platform_ops
* @brief Structure holding gpio function pointers that point to the platform
* specific function
*/
struct no_os_gpio_platform_ops {
/** gpio initialization function pointer */
int32_t (*gpio_ops_get)(struct no_os_gpio_desc **,
const struct no_os_gpio_init_param *);
/** gpio optional descriptor function pointer */
int32_t (*gpio_ops_get_optional)(struct no_os_gpio_desc **,
const struct no_os_gpio_init_param *);
/** gpio remove function pointer */
int32_t (*gpio_ops_remove)(struct no_os_gpio_desc *);
/** gpio direction input function pointer */
int32_t (*gpio_ops_direction_input)(struct no_os_gpio_desc *);
/** gpio direction output function pointer */
int32_t (*gpio_ops_direction_output)(struct no_os_gpio_desc *, uint8_t);
/** gpio get direction function pointer */
int32_t (*gpio_ops_get_direction)(struct no_os_gpio_desc *, uint8_t *);
/** gpio set value function pointer */
int32_t (*gpio_ops_set_value)(struct no_os_gpio_desc *, uint8_t);
/** gpio get value function pointer */
int32_t (*gpio_ops_get_value)(struct no_os_gpio_desc *, uint8_t *);
};
/* Obtain the GPIO decriptor. */
int32_t no_os_gpio_get(struct no_os_gpio_desc **desc,
const struct no_os_gpio_init_param *param);
/* Obtain optional GPIO descriptor. */
int32_t no_os_gpio_get_optional(struct no_os_gpio_desc **desc,
const struct no_os_gpio_init_param *param);
/* Free the resources allocated by no_os_gpio_get(). */
int32_t no_os_gpio_remove(struct no_os_gpio_desc *desc);
/* Enable the input direction of the specified GPIO. */
int32_t no_os_gpio_direction_input(struct no_os_gpio_desc *desc);
/* Enable the output direction of the specified GPIO. */
int32_t no_os_gpio_direction_output(struct no_os_gpio_desc *desc,
uint8_t value);
/* Get the direction of the specified GPIO. */
int32_t no_os_gpio_get_direction(struct no_os_gpio_desc *desc,
uint8_t *direction);
/* Set the value of the specified GPIO. */
int32_t no_os_gpio_set_value(struct no_os_gpio_desc *desc,
uint8_t value);
/* Get the value of the specified GPIO. */
int32_t no_os_gpio_get_value(struct no_os_gpio_desc *desc,
uint8_t *value);
#endif // _NO_OS_GPIO_H_
@@ -0,0 +1,209 @@
/***************************************************************************//**
* @file no_os_i2c.c
* @brief Implementation of the I2C Interface
* @author Antoniu Miclaus (antoniu.miclaus@analog.com)
********************************************************************************
* Copyright 2020(c) Analog Devices, Inc.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* 3. Neither the name of Analog Devices, Inc. nor the names of its
* contributors may be used to endorse or promote products derived from this
* software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY ANALOG DEVICES, INC. “AS IS” AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
* EVENT SHALL ANALOG DEVICES, INC. BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
* OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
* EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*******************************************************************************/
#include <inttypes.h>
#include "no_os_i2c.h"
#include <stdlib.h>
#include "no_os_error.h"
#include "no_os_mutex.h"
#include "no_os_alloc.h"
/**
* @brief i2c_table contains the pointers towards the i2c buses
*/
static void *i2c_table[I2C_MAX_BUS_NUMBER + 1];
/**
* @brief Initialize the I2C communication peripheral.
* @param desc - The I2C descriptor.
* @param param - The structure that contains the I2C parameters.
* @return 0 in case of success, -1 otherwise.
*/
int32_t no_os_i2c_init(struct no_os_i2c_desc **desc,
const struct no_os_i2c_init_param *param)
{
int32_t ret;
if (!param || !param->platform_ops)
return -EINVAL;
if (!param->platform_ops->i2c_ops_init)
return -ENOSYS;
if (param->device_id > I2C_MAX_BUS_NUMBER)
return -EINVAL;
// Initializing BUS descriptor
if (i2c_table[param->device_id] == NULL) {
ret = no_os_i2cbus_init(param);
if (ret)
return ret;
}
// Initilize I2C descriptor
ret = param->platform_ops->i2c_ops_init(desc, param);
if (ret)
return ret;
(*desc)->bus = i2c_table[param->device_id];
(*desc)->bus->slave_number++;
(*desc)->platform_ops = param->platform_ops;
return 0;
}
/**
* @brief Initialize the i2c bus communication peripheral.
* @param param - The structure that containes the i2c bus parameters
* @return 0 in case of success, error code otherwise
*/
int32_t no_os_i2cbus_init(const struct no_os_i2c_init_param *param)
{
struct no_os_i2cbus_desc *bus = (struct no_os_i2cbus_desc *)no_os_calloc(1,
sizeof(struct no_os_i2cbus_desc));
if (!bus)
return -ENOMEM;
no_os_mutex_init(&(bus->mutex));
bus->slave_number = 0;
bus->device_id = param->device_id;
bus->max_speed_hz = param->max_speed_hz;
bus->platform_ops = param->platform_ops;
bus->extra = param->extra;
i2c_table[param->device_id] = bus;
return 0;
}
/**
* @brief Free the resources allocated by no_os_i2c_init().
* @param desc - The I2C descriptor.
* @return 0 in case of success, -1 otherwise.
*/
int32_t no_os_i2c_remove(struct no_os_i2c_desc *desc)
{
if (!desc || !desc->platform_ops)
return -EINVAL;
if (desc->bus)
no_os_i2cbus_remove(desc->bus->device_id);
if (!desc->platform_ops->i2c_ops_remove)
return -ENOSYS;
return desc->platform_ops->i2c_ops_remove(desc);
}
/**
* @brief Removes i2c bus instance
* @param bus_number - i2c bus number
*/
void no_os_i2cbus_remove(uint32_t bus_number)
{
struct no_os_i2cbus_desc *bus = (struct no_os_i2cbus_desc *)
i2c_table[bus_number];
if (bus->slave_number > 0)
bus->slave_number--;
if (bus->slave_number == 0) {
no_os_mutex_remove(bus->mutex);
if (bus != NULL) {
no_os_free(bus);
i2c_table[bus_number] = NULL;
}
}
}
/**
* @brief I2C Write data to slave device.
* @param desc - The I2C descriptor.
* @param data - The buffer with the transmitted/received data.
* @param bytes_number - Number of bytes to write.
* @param stop_bit - Stop conditional control.
* Example: 0 - A stop condition will not be generated.
* 1 - A stop condition will be generated.
* @return 0 in case of success, -1 otherwise.
*/
int32_t no_os_i2c_write(struct no_os_i2c_desc *desc,
uint8_t *data,
uint8_t bytes_number,
uint8_t stop_bit)
{
int32_t ret;
if (!desc || !desc->platform_ops)
return -EINVAL;
if (!desc->platform_ops->i2c_ops_write)
return -ENOSYS;
no_os_mutex_lock(desc->bus->mutex);
ret = desc->platform_ops->i2c_ops_write(desc, data, bytes_number,
stop_bit);
no_os_mutex_unlock(desc->bus->mutex);
return ret;
}
/**
* @brief I2C Read data from slave device.
* @param desc - The i2c descriptor.
* @param data - The buffer with the transmitted/received data.
* @param bytes_number - Number of bytes to read.
* @param stop_bit - Stop conditional control.
* Example: 0 - A stop condition will not be generated.
* 1 - A stop condition will be generated.
* @return 0 in case of success, -1 otherwise.
*/
int32_t no_os_i2c_read(struct no_os_i2c_desc *desc,
uint8_t *data,
uint8_t bytes_number,
uint8_t stop_bit)
{
int32_t ret;
if (!desc || !desc->platform_ops)
return -EINVAL;
if (!desc->platform_ops->i2c_ops_read)
return -ENOSYS;
no_os_mutex_lock(desc->bus->mutex);
ret = desc->platform_ops->i2c_ops_read(desc, data, bytes_number,
stop_bit);
no_os_mutex_unlock(desc->bus->mutex);
return ret;
}
@@ -0,0 +1,146 @@
/***************************************************************************//**
* @file no_os_i2c.h
* @brief Header file of I2C Interface
* @author DBogdan (dragos.bogdan@analog.com)
********************************************************************************
* Copyright 2019(c) Analog Devices, Inc.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* 3. Neither the name of Analog Devices, Inc. nor the names of its
* contributors may be used to endorse or promote products derived from this
* software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY ANALOG DEVICES, INC. “AS IS” AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
* EVENT SHALL ANALOG DEVICES, INC. BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
* OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
* EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*******************************************************************************/
#ifndef _NO_OS_I2C_H_
#define _NO_OS_I2C_H_
#include <stdint.h>
#define I2C_MAX_BUS_NUMBER 4
/**
* @struct no_os_i2c_platform_ops
* @brief Structure holding I2C function pointers that point to the platform
* specific function
*/
struct no_os_i2c_platform_ops ;
/**
* @struct no_os_i2c_init_param
* @brief Structure holding the parameters for I2C initialization.
*/
struct no_os_i2c_init_param {
/** Device ID */
uint32_t device_id;
/** I2C maximum transfer speed supported */
uint32_t max_speed_hz;
/** Slave address */
uint8_t slave_address;
/** I2C platform specific functions */
const struct no_os_i2c_platform_ops *platform_ops;
/** I2C extra parameters (device specific parameters) */
void *extra;
};
/**
* @struct no_os_i2cbus_desc
* @brief Structure holding I2C bus descriptor
*/
struct no_os_i2cbus_desc {
/** I2C bus mutex(lock)*/
void* mutex;
/** I2C bus slave number*/
uint8_t slave_number;
/** I2C bus Device ID */
uint32_t device_id;
/** I2C bus maximum transfer speed supported */
uint32_t max_speed_hz;
/** I2C bus platform specific functions */
const struct no_os_i2c_platform_ops *platform_ops;
/** I2C bus extra parameters (device specific parameters) */
void *extra;
};
/**
* @struct no_os_i2c_desc
* @brief Structure holding I2C address descriptor
*/
struct no_os_i2c_desc {
/** I2C bus address*/
struct no_os_i2cbus_desc *bus;
/** Device ID */
uint32_t device_id;
/** I2C maximum transfer speed supported */
uint32_t max_speed_hz;
/** Slave address */
uint8_t slave_address;
/** I2C platform specific functions */
const struct no_os_i2c_platform_ops *platform_ops;
/** I2C extra parameters (device specific parameters) */
void *extra;
};
/**
* @struct no_os_i2c_platform_ops
* @brief Structure holding i2c function pointers that point to the platform
* specific function
*/
struct no_os_i2c_platform_ops {
/** i2c initialization function pointer */
int32_t (*i2c_ops_init)(struct no_os_i2c_desc **,
const struct no_os_i2c_init_param *);
/** i2c write function pointer */
int32_t (*i2c_ops_write)(struct no_os_i2c_desc *, uint8_t *, uint8_t, uint8_t);
/** i2c write function pointer */
int32_t (*i2c_ops_read)(struct no_os_i2c_desc *, uint8_t *, uint8_t, uint8_t);
/** i2c remove function pointer */
int32_t (*i2c_ops_remove)(struct no_os_i2c_desc *);
};
/* Initialize the I2C communication peripheral. */
int32_t no_os_i2c_init(struct no_os_i2c_desc **desc,
const struct no_os_i2c_init_param *param);
/* Free the resources allocated by no_os_i2c_init(). */
int32_t no_os_i2c_remove(struct no_os_i2c_desc *desc);
/* Write data to a slave device. */
int32_t no_os_i2c_write(struct no_os_i2c_desc *desc,
uint8_t *data,
uint8_t bytes_number,
uint8_t stop_bit);
/* Read data from a slave device. */
int32_t no_os_i2c_read(struct no_os_i2c_desc *desc,
uint8_t *data,
uint8_t bytes_number,
uint8_t stop_bit);
/* Initialize I2C bus descriptor*/
int32_t no_os_i2cbus_init(const struct no_os_i2c_init_param *param);
/* Free the resources allocated for I2C bus desc*/
void no_os_i2cbus_remove(uint32_t bus_number);
#endif // _NO_OS_I2C_H_
@@ -0,0 +1,698 @@
/***************************************************************************//**
* @file no_os_i3c.c
* @brief Implementation of the I3C Interface
* @author Jorge Marques (jorge.marques@analog.com)
********************************************************************************
* Copyright 2024(c) Analog Devices, Inc.
*
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
* - Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* - Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in
* the documentation and/or other materials provided with the
* distribution.
* - Neither the name of Analog Devices, Inc. nor the names of its
* contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
* - The use of this software may or may not infringe the patent rights
* of one or more patent holders. This license does not release you
* from the requirement that you obtain separate licenses from these
* patent holders to use this software.
* - Use of the software either in source or binary form, must be run
* on or directly connected to an Analog Devices Inc. component.
*
* THIS SOFTWARE IS PROVIDED BY ANALOG DEVICES "AS IS" AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, NON-INFRINGEMENT,
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
* IN NO EVENT SHALL ANALOG DEVICES BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, INTELLECTUAL PROPERTY RIGHTS, PROCUREMENT OF SUBSTITUTE GOODS OR
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*******************************************************************************/
#include <inttypes.h>
#include <stdlib.h>
#include <string.h>
#include "no_os_i3c.h"
#include "no_os_error.h"
#include "no_os_mutex.h"
#include "no_os_alloc.h"
/**
* @brief i3c_table contains the pointers towards the I3C buses.
*/
struct no_os_i3c_bus_desc *i3c_table [NO_OS_I3C_MAX_BUS_NUMBER + 1] = {NULL};
static enum no_os_i3c_slot_status no_os_i3c_addr_get_status(
struct no_os_i3c_bus_desc *desc, uint8_t addr);
static bool no_os_i3c_addr_is_avail(struct no_os_i3c_bus_desc *desc,
uint8_t addr);
static void no_os_i3c_addr_init(struct no_os_i3c_bus_desc *desc);
/**
* @brief Initialize the I3C device.
* If the bus of the I3C device is not initialized, it will call to init it.
* @param desc - The I3C device descriptor.
* @param param - The structure that contains the I3C device parameters, to match PID.
* @return 0 in case of success, error code otherwise.
*/
int no_os_i3c_init(struct no_os_i3c_desc **desc,
const struct no_os_i3c_init_param *param)
{
int ret;
struct no_os_i3c_desc *device_desc;
struct no_os_i3c_bus_desc **bus_desc;
struct no_os_i3c_bus_init_param *param_bus;
struct no_os_i3c_desc **it;
uint8_t i;
if (!param->bus->device_id ||
param->bus->device_id > NO_OS_I3C_MAX_BUS_NUMBER)
return -EINVAL;
bus_desc = &i3c_table[param->bus->device_id - 1];
if (!*bus_desc) {
/* Initialize bus if not already */
ret = no_os_i3c_init_bus(bus_desc, param->bus);
if (ret)
return ret;
}
/* Initialize device */
param_bus = param->bus;
device_desc = (struct no_os_i3c_desc *)no_os_malloc(
sizeof(struct no_os_i3c_desc));
if (!device_desc)
return -ENOMEM;
/* Set is_attached flag */
if (!param->is_i3c || param->is_static)
device_desc->is_attached = 1;
else {
for (i = 0; i < NO_OS_I3C_MAX_DEV_NUMBER; i++) {
if ((*bus_desc)->daa_candidates[i].pid == param->pid)
break;
}
if (i == NO_OS_I3C_MAX_DEV_NUMBER) {
ret = -EFAULT;
goto error_device;
}
device_desc->is_attached = (*bus_desc)->daa_candidates[i].is_attached;
if (!device_desc->is_attached) {
ret = -EPERM;
goto error_device;
}
}
/* Copy from init param to dev descriptor */
device_desc->pid = param->pid;
device_desc->addr = param->addr;
device_desc->is_static = param->is_static;
device_desc->is_i3c = param->is_i3c;
device_desc->platform_ops = param_bus->platform_ops;
device_desc->bus = *bus_desc;
device_desc->event_callback = NULL;
/* Find free slot */
it = (*bus_desc)->devs;
while (it < (*bus_desc)->devs + NO_OS_I3C_MAX_DEV_NUMBER) {
if (!*it)
break;
it++;
};
if (it == (*bus_desc)->devs + NO_OS_I3C_MAX_DEV_NUMBER)
goto error_device;
*it = device_desc;
ret = device_desc->platform_ops->i3c_ops_init(device_desc, param);
if (ret)
goto error_device;
ret = device_desc->platform_ops->i3c_ops_is_dev_ready(device_desc);
if (ret)
goto error_device;
*desc = device_desc;
return 0;
error_device:
no_os_free(device_desc);
return ret;
}
/**
* @brief Initialize the I3C bus.
* @param desc - The I3C bus descriptor.
* @param param - The structure that contains the I3C bus parameters.
* @return 0 in case of success, error code otherwise.
*/
int no_os_i3c_init_bus(struct no_os_i3c_bus_desc **desc,
const struct no_os_i3c_bus_init_param *param)
{
struct no_os_i3c_bus_desc *bus_desc;
bool has_static_i3c_addr = 0;
int ret;
int i = 0;
uint8_t data;
const struct no_os_i3c_init_param **it;
if (!param || !param->platform_ops)
return -EINVAL;
if (!param->platform_ops->i3c_ops_init_bus ||
!param->platform_ops->i3c_ops_remove_bus)
return -ENOSYS;
bus_desc = (struct no_os_i3c_bus_desc *)no_os_calloc(1,
sizeof(struct no_os_i3c_bus_desc));
if (!bus_desc)
return -ENOMEM;
bus_desc->device_id = param->device_id;
bus_desc->num_devs = param->num_devs;
bus_desc->num_devs_unknown = 0;
bus_desc->async_irq = 0;
bus_desc->platform_ops = param->platform_ops;
/*
* Execute the platform specific init routine,
* which allocate the extra features.
*/
ret = param->platform_ops->i3c_ops_init_bus(bus_desc, param);
if (ret)
goto error_bus_1;
i3c_table[param->device_id - 1] = bus_desc;
no_os_i3c_addr_init(bus_desc);
/*
* Set status for addr, and
* If a device supports static addr, set it with CCC STAASA.
* If not, add to the PID-DA LUT for the DAA procedure.
*/
for (it = param->devs; it < param->devs + param->num_devs; it++) {
if (!*it)
continue;
if (!no_os_i3c_addr_is_avail(bus_desc, (*it)->addr)) {
ret = -EINVAL;
goto error_bus_2;
}
if ((*it)->is_i3c) {
if ((*it)->is_static) {
has_static_i3c_addr = 1;
no_os_i3c_addr_set_status(bus_desc, (*it)->addr,
NO_OS_I3C_ADDR_SLOT_I3C_DEV);
} else {
bus_desc->daa_candidates[i].pid = (*it)->pid;
bus_desc->daa_candidates[i].addr = (*it)->addr;
i++;
}
} else
no_os_i3c_addr_set_status(bus_desc, (*it)->addr,
NO_OS_I3C_ADDR_SLOT_I2C_DEV);
}
/* Ensure other candidates fields are empty */
memset(&bus_desc->daa_candidates[i], 0,
sizeof(struct no_os_i3c_daa_lut) * (NO_OS_I3C_MAX_DEV_NUMBER - i));
/* Reset fully every device on the bus */
data = NO_OS_I3C_CCC_RSTACT_WHOLE_TARGET;
ret = no_os_i3c_send_ccc(*desc,
NO_OS_I3C_BCAST_ADDR,
NO_OS_I3C_CCC_RSTACT_BCAST, &data);
if (ret)
goto error_bus_2;
/* Set I3C devices that support static addresses to use them */
if (has_static_i3c_addr) {
ret = no_os_i3c_send_ccc(bus_desc, NO_OS_I3C_BCAST_ADDR, NO_OS_I3C_CCC_SETAASA,
NULL);
if (ret)
goto error_bus_2;
}
ret = no_os_i3c_do_daa(bus_desc, 1);
if (ret)
goto error_bus_2;
no_os_mutex_init(bus_desc->mutex);
*desc = bus_desc;
return 0;
error_bus_2:
ret = param->platform_ops->i3c_ops_remove_bus(bus_desc);
error_bus_1:
no_os_free(bus_desc);
return ret;
}
/**
* @brief Free the resources allocated by no_os_i3c_init().
* @param desc - The I3C device descriptor.
* @return 0 in case of success, error code otherwise.
*/
int no_os_i3c_remove(struct no_os_i3c_desc *desc)
{
struct no_os_i3c_bus_desc *bus_desc;
struct no_os_i3c_desc **it;
if (!desc || !desc->platform_ops)
return -EINVAL;
if (!desc->platform_ops->i3c_ops_remove)
return -ENOSYS;
bus_desc = desc->bus;
it = bus_desc->devs;
while (it < bus_desc->devs + NO_OS_I3C_MAX_DEV_NUMBER) {
if (*it == desc)
*it = NULL;
it++;
}
/* Only error case is !desc */
desc->platform_ops->i3c_ops_remove(desc);
no_os_free(desc);
return 0;
}
/**
* @brief Free the resources allocated by no_os_i3c_init_bus.
* Must remove all devices first, if not, -EFAULT is returned.
* @param desc - The I3C bus descriptor.
* @return 0 in case of success, error code otherwise.
*/
int no_os_i3c_remove_bus(struct no_os_i3c_bus_desc *desc)
{
struct no_os_i3c_desc **it;
if (!desc || !desc->platform_ops)
return -EINVAL;
if (!desc->platform_ops->i3c_ops_remove_bus)
return -ENOSYS;
/* Verify if all devices are removed */
for (it = desc->devs; it < desc->devs + NO_OS_I3C_MAX_DEV_NUMBER; it++) {
if (*it)
return -EFAULT;
}
no_os_mutex_remove(desc->mutex);
/* Only error case is !desc */
desc->platform_ops->i3c_ops_remove_bus(desc);
i3c_table[desc->device_id - 1] = NULL;
no_os_free(desc);
return 0;
}
/**
* @brief Do DAA to assign the dynamic addresses.
* @param desc - The I3C descriptor.
* @param rstdaa - Do RSTDAA CCC before the DAA.
* @return 0 in case of success, error code otherwise.
*/
int no_os_i3c_do_daa(struct no_os_i3c_bus_desc *desc, bool rstdaa)
{
if (!desc || !desc->platform_ops)
return -EINVAL;
if (!desc->platform_ops->i3c_ops_do_daa)
return -ENOSYS;
return desc->platform_ops->i3c_ops_do_daa(desc, rstdaa);
}
/**
* @brief Send CCC, either to a device device or broadcast to all.
* @param desc - The I3C descriptor.
* @param addr - Device address or broadcast address.
* @param ccc - CCC RnW, CCC Length, CCC ID.
* @param data - The buffer with the transmitted/received data.
* @return 0 in case of success, error code otherwise.
*/
int no_os_i3c_send_ccc(struct no_os_i3c_bus_desc *desc,
uint8_t addr,
uint32_t ccc,
uint8_t *data)
{
int ret;
if (!desc || !desc->platform_ops)
return -EINVAL;
if (!desc->platform_ops->i3c_ops_send_ccc)
return -ENOSYS;
if ((NO_OS_I3C_CCC_GET_RNW(ccc) && addr == NO_OS_I3C_BCAST_ADDR) ||
((addr == NO_OS_I3C_BCAST_ADDR) && (ccc & NO_OS_I3C_CCC_DIRECT)) ||
((addr != NO_OS_I3C_BCAST_ADDR) && !(ccc & NO_OS_I3C_CCC_DIRECT)))
return -EINVAL;
no_os_mutex_lock(desc->mutex);
ret = desc->platform_ops->i3c_ops_send_ccc(desc, addr, NO_OS_I3C_CCC_ADDR(ccc),
NO_OS_I3C_CCC_GET_RNW(ccc), NO_OS_I3C_CCC_GET_DEF(ccc),
data, NO_OS_I3C_CCC_GET_LEN(ccc));
no_os_mutex_unlock(desc->mutex);
return ret;
}
/**
* @brief Send CCC to device device.
* @param desc - The I3C descriptor.
* @param ccc - CCC RnW, CCC length, CCC id.
* @param data - The buffer with the transmitted/received data.
* @return 0 in case of success, error code otherwise.
*/
int no_os_i3c_send_direct_ccc(struct no_os_i3c_desc *desc,
uint32_t ccc,
uint8_t *data)
{
if (!desc || !desc->bus)
return -EINVAL;
if (!(ccc & NO_OS_I3C_CCC_DIRECT))
return -EINVAL;
return no_os_i3c_send_ccc(desc->bus, desc->addr, ccc, data);
}
/**
* @brief Write data to device device.
* @param desc - The I3C descriptor.
* @param data - The buffer with the transmitted data.
* @param size - Number of bytes to write.
* @return 0 in case of success, error code otherwise.
*/
int no_os_i3c_write(struct no_os_i3c_desc *desc,
uint8_t *data,
uint8_t size)
{
int ret;
if (!desc || !desc->platform_ops)
return -EINVAL;
if (!desc->platform_ops->i3c_ops_write)
return -ENOSYS;
no_os_mutex_lock(desc->bus->mutex);
ret = desc->bus->platform_ops->i3c_ops_write(desc,
data, size);
no_os_mutex_unlock(desc->bus->mutex);
return ret;
}
/**
* @brief Read data from device device.
* @param desc - The I3C descriptor.
* @param data - The buffer with the received data.
* @param size - Number of bytes to read.
* @return 0 in case of success, error code otherwise.
*/
int no_os_i3c_read(struct no_os_i3c_desc *desc,
uint8_t *data,
uint8_t size)
{
int ret;
if (!desc || !desc->platform_ops)
return -EINVAL;
if (!desc->platform_ops->i3c_ops_read)
return -ENOSYS;
no_os_mutex_lock(desc->bus->mutex);
ret = desc->bus->platform_ops->i3c_ops_read(desc,
data, size);
no_os_mutex_unlock(desc->bus->mutex);
return ret;
}
/**
* @brief Read and write the device.
* @param desc - The I3C descriptor.
* @param tx_data - The buffer with the transmitted data.
* @param tx_data_len - Number of bytes to write.
* @param rx_data - The buffer with the received data.
* @param rx_data_len - Number of bytes to read.
* @return 0 in case of success, -1 otherwise.
*/
int no_os_i3c_write_and_read(struct no_os_i3c_desc *desc,
uint8_t *tx_data,
uint8_t tx_data_len,
uint8_t *rx_data,
uint8_t rx_data_len)
{
int ret;
if (!desc || !desc->platform_ops)
return -EINVAL;
if (!desc->platform_ops->i3c_ops_read)
return -ENOSYS;
no_os_mutex_lock(desc->bus->mutex);
ret = desc->bus->platform_ops->i3c_ops_write_and_read(desc,
tx_data, tx_data_len, rx_data, rx_data_len);
no_os_mutex_unlock(desc->bus->mutex);
return ret;
}
/**
* @brief Configure I3C interrupts.
* @param desc - The I3C descriptor.
* @param irq - The interrupt type to enable.
* @param en - 1 to enable, 0 to disable irq type.
* @return 0 in case of success, -1 otherwise.
*/
int no_os_i3c_conf_irq(struct no_os_i3c_bus_desc *desc,
uint8_t irq, bool en)
{
if (!desc || !desc->platform_ops)
return -EINVAL;
if (!desc->platform_ops->i3c_ops_conf_irq)
return -ENOSYS;
return desc->platform_ops->i3c_ops_conf_irq(desc, irq, en);
}
/**
* @brief Enable I3C non-blocking interrupts.
* @param desc - The I3C descriptor.
* @param en - 1 to enable, 0 to disable async callback.
* @return 0 in case of success, -EINVAL otherwise.
*/
int no_os_i3c_async_irq(struct no_os_i3c_bus_desc *desc, bool en)
{
if (!desc)
return -EINVAL;
desc->async_irq = en;
return 0;
}
/**
* @brief Wait I3C interrupt.
* Set async_irq on call to false to ensure single entry point.
* @param desc - The I3C descriptor.
* @param irq - The interrupt to wait for.
* @return 0 in case of success, -EINVAL if in async mode or error codes.
*/
int no_os_i3c_wait_irq(struct no_os_i3c_bus_desc* desc,
uint8_t irq)
{
if (!desc || desc->async_irq)
return -EINVAL;
while (!(desc->irq_events & irq)) {}
return no_os_i3c_call_irq(desc);
}
/**
* @brief Non-blocking I3C interrupt.
* Since a payload is always retrieved with it, also update the no_os_i3c_ccc_info fields.
* @param desc - The I3C descriptor.
* @return 0 in case of success, error code otherwise.
*/
int no_os_i3c_call_irq(struct no_os_i3c_bus_desc* desc)
{
struct no_os_i3c_desc **it;
int ret;
if (!desc || !desc->platform_ops)
return -EINVAL;
if (!desc->platform_ops->i3c_ops_get_ccc_info)
return -ENOSYS;
ret = desc->platform_ops->i3c_ops_get_ccc_info(desc, desc->irq_events);
if (ret)
return ret;
it = desc->devs;
while (it < desc->devs + NO_OS_I3C_MAX_DEV_NUMBER) {
if (*it && (*it)->addr == desc->ccc_info.ibi_cr_addr) {
if ((*it)->event_callback) {
(*it)->event_callback((*it), desc->ccc_info.ibi_payload,
desc->ccc_info.ibi_payload_len);
}
break;
}
it++;
};
return ret;
}
/**
* @brief Get a free address.
* @param desc - The I3C bus descriptor.
* @param start_addr - Start address to search from.
* @return The free address or 0 if no address is available.
*/
uint8_t no_os_i3c_addr_get_free(struct no_os_i3c_bus_desc *desc,
uint8_t start_addr)
{
enum no_os_i3c_slot_status status;
uint8_t addr;
for (addr = start_addr; addr < NO_OS_I3C_MAX_ADDR; addr++) {
status = no_os_i3c_addr_get_status(desc, addr);
if (status == NO_OS_I3C_ADDR_SLOT_FREE)
return addr;
}
return 0;
}
/**
* @brief Set status of an address.
* @param desc - The I3C bus descriptor.
* @param addr - The address to set.
* @param status - The value to write.
*/
void no_os_i3c_addr_set_status(struct no_os_i3c_bus_desc *desc,
uint8_t addr, enum no_os_i3c_slot_status status)
{
unsigned int slot, bitpos;
unsigned int *ptr;
if (addr > NO_OS_I3C_I2C_MAX_ADDR)
return;
slot = NO_OS_I3C_ADDR_GET_SLOT(addr);
bitpos = NO_OS_I3C_ADDR_GET_POS(addr);
ptr = desc->addrslots + slot;
// Unset old value
*ptr &= ~(NO_OS_I3C_ADDR_SLOT_STATUS_MASK << bitpos);
// Set new value
*ptr |= (status & NO_OS_I3C_ADDR_SLOT_STATUS_MASK) << bitpos;
}
/**
* @brief Get status of an address.
* @param desc - The I3C bus descriptor.
* @param start_addr - Start address to search from.
* @return The free address or -ENOMEM if no available address.
*/
static enum no_os_i3c_slot_status no_os_i3c_addr_get_status(
struct no_os_i3c_bus_desc *desc, uint8_t addr)
{
unsigned int slot, bitpos;
enum no_os_i3c_slot_status status;
if (addr > NO_OS_I3C_I2C_MAX_ADDR)
return NO_OS_I3C_ADDR_SLOT_RSVD;
slot = NO_OS_I3C_ADDR_GET_SLOT(addr);
bitpos = NO_OS_I3C_ADDR_GET_POS(addr);
status = desc->addrslots[slot];
status >>= bitpos;
return status & NO_OS_I3C_ADDR_SLOT_STATUS_MASK;
}
/**
* @brief Check if address is available.
* @param desc - The I3C bus descriptor.
* @param addr - Address to check.
* @return 1 if available, 0 if not.
*/
static bool no_os_i3c_addr_is_avail(struct no_os_i3c_bus_desc *desc,
uint8_t addr)
{
enum no_os_i3c_slot_status status;
status = no_os_i3c_addr_get_status(desc, addr);
return status == NO_OS_I3C_ADDR_SLOT_FREE;
}
/**
* @brief Initialize address buffer, reserving reserved addresses.
* @param desc - The I3C bus descriptor.
*/
static void no_os_i3c_addr_init(struct no_os_i3c_bus_desc *desc)
{
/* Addresses 0 to 7 are reserved. */
for (int i = 0; i < 8; i++)
no_os_i3c_addr_set_status(desc, i, NO_OS_I3C_ADDR_SLOT_RSVD);
/*
* Reserve broadcast address and all addresses that might collide
* with the broadcast address when facing a single bit error.
*/
no_os_i3c_addr_set_status(desc, NO_OS_I3C_BCAST_ADDR,
NO_OS_I3C_ADDR_SLOT_RSVD);
for (int i = 0; i < 7; i++)
no_os_i3c_addr_set_status(desc, NO_OS_I3C_BCAST_ADDR ^ NO_OS_BIT(i),
NO_OS_I3C_ADDR_SLOT_RSVD);
}
/**
* @brief Attach event callback.
* @param desc - The I3C device descriptor.
* @param callback - Method to call on event.
*/
void no_os_i3c_attach_callback(struct no_os_i3c_desc *desc,
void (*callback)(struct no_os_i3c_desc*, uint32_t, uint32_t))
{
desc->event_callback = callback;
}
/**
* @brief Detach event callback.
* @param desc - The I3C device descriptor.
*/
void no_os_i3c_detach_callback(struct no_os_i3c_desc *desc)
{
no_os_i3c_attach_callback(desc, NULL);
}
@@ -0,0 +1,396 @@
/***************************************************************************//**
* @file no_os_i3c.h
* @brief Header file of I3C Interface
* @author Jorge Marques (jorge.marques@analog.com)
********************************************************************************
* Copyright 2024(c) Analog Devices, Inc.
*
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
* - Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* - Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in
* the documentation and/or other materials provided with the
* distribution.
* - Neither the name of Analog Devices, Inc. nor the names of its
* contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
* - The use of this software may or may not infringe the patent rights
* of one or more patent holders. This license does not release you
* from the requirement that you obtain separate licenses from these
* patent holders to use this software.
* - Use of the software either in source or binary form, must be run
* on or directly connected to an Analog Devices Inc. component.
*
* THIS SOFTWARE IS PROVIDED BY ANALOG DEVICES "AS IS" AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, NON-INFRINGEMENT,
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
* IN NO EVENT SHALL ANALOG DEVICES BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, INTELLECTUAL PROPERTY RIGHTS, PROCUREMENT OF SUBSTITUTE GOODS OR
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*******************************************************************************/
#ifndef _NO_OS_I3C_H_
#define _NO_OS_I3C_H_
#include <stdint.h>
#include "no_os_util.h"
#define NO_OS_I3C_MAX_BUS_NUMBER 3
#define NO_OS_I3C_MAX_DEV_NUMBER 15
/* I²C/I3C address are 7-bit (not considering extended 10-bit I²C) */
#define NO_OS_I3C_I2C_MAX_ADDR 0x7F
#define NO_OS_I3C_MAX_ADDR NO_OS_I3C_I2C_MAX_ADDR
#define NO_OS_I3C_BCAST_ADDR 0x7E
/* 2-bit flags packed in addrslots */
#define NO_OS_I3C_ADDR_FLAG_SIZE 2
#define NO_OS_I3C_ADDR_PER_SLOT ((unsigned int)(sizeof(unsigned int)*8 / NO_OS_I3C_ADDR_FLAG_SIZE))
#define NO_OS_I3C_ADDR_GET_SLOT(x) ((x) / NO_OS_I3C_ADDR_PER_SLOT)
#define NO_OS_I3C_ADDR_GET_POS(x) (((x) % NO_OS_I3C_ADDR_PER_SLOT) * NO_OS_I3C_ADDR_FLAG_SIZE)
#define NO_OS_I3C_ADDRSLOTS_SIZE \
(NO_OS_I3C_I2C_MAX_ADDR / NO_OS_I3C_ADDR_PER_SLOT) + !!(NO_OS_I3C_I2C_MAX_ADDR % NO_OS_I3C_ADDR_PER_SLOT)
/* I3C CCC (Common Command Codes) related definitions */
#define NO_OS_I3C_CCC_BCAST 0
#define NO_OS_I3C_CCC_DIRECT NO_OS_BIT(7)
#define NO_OS_I3C_CCC_ID(id, type) ((id) | (type))
#define NO_OS_I3C_CCC_ADDR(x) ((x) & 0xFF)
#define NO_OS_I3C_CCC_GET_LEN(x) (((x) >> 8) & 0x0000FF)
#define NO_OS_I3C_CCC_SET_LEN(x) (((x) << 8) & 0x00FF00)
#define NO_OS_I3C_CCC_GET_DEF(x) (((x) >> 17) & NO_OS_BIT(0))
#define NO_OS_I3C_CCC_SET_DEF NO_OS_BIT(17)
#define NO_OS_I3C_CCC_GET_RNW(x) (((x) >> 16) & NO_OS_BIT(0))
#define NO_OS_I3C_CCC_SET_RNW(x) (((x) << 16) & NO_OS_BIT(16))
/**
* Commands valid in both broadcast and direct modes
* type: NO_OS_I3C_CCC_DIRECT, NO_OS_I3C_CCC_BCAST
*/
#define NO_OS_I3C_CCC_ENEC_DIRECT 0x80 | NO_OS_I3C_CCC_SET_LEN(1)
#define NO_OS_I3C_CCC_DISEC_DIRECT 0x81 | NO_OS_I3C_CCC_SET_LEN(1)
#define NO_OS_I3C_CCC_ENEC_BCAST 0x00 | NO_OS_I3C_CCC_SET_DEF
#define NO_OS_I3C_CCC_DISEC_BCAST 0x01 | NO_OS_I3C_CCC_SET_DEF
#define NO_OS_I3C_CCC_ENTAS(as, type) NO_OS_I3C_CCC_ID((0x2 + (as)), (type))
#define NO_OS_I3C_CCC_RSTDAA(type) NO_OS_I3C_CCC_ID(0x6, (type))
#define NO_OS_I3C_CCC_SETMWL(type) NO_OS_I3C_CCC_ID(0x9, (type)) | NO_OS_I3C_CCC_SET_LEN(2)
#define NO_OS_I3C_CCC_SETMRL(type) NO_OS_I3C_CCC_ID(0xa, (type)) | NO_OS_I3C_CCC_SET_LEN(2)
#define NO_OS_I3C_CCC_SETXTIME_BCAST 0x28 | NO_OS_I3C_CCC_SET_DEF
#define NO_OS_I3C_CCC_SETXTIME_DIRECT 0x98 | NO_OS_I3C_CCC_SET_DEF
#define NO_OS_I3C_CCC_RSTACT_BCAST 0x2a | NO_OS_I3C_CCC_SET_DEF
#define NO_OS_I3C_CCC_RSTACT_DIRECT 0x9a | NO_OS_I3C_CCC_SET_DEF
#define NO_OS_I3C_CCC_RSTACT_I3C_ONLY 0x1
#define NO_OS_I3C_CCC_RSTACT_WHOLE_TARGET 0x2
/* Broadcast-only commands */
#define NO_OS_I3C_CCC_ENTDAA NO_OS_I3C_CCC_ID(0x7, NO_OS_I3C_CCC_BCAST)
#define NO_OS_I3C_CCC_DEFSLVS NO_OS_I3C_CCC_ID(0x8, NO_OS_I3C_CCC_BCAST)
#define NO_OS_I3C_CCC_ENTTM NO_OS_I3C_CCC_ID(0xb, NO_OS_I3C_CCC_BCAST)
#define NO_OS_I3C_CCC_ENTHDR(x) NO_OS_I3C_CCC_ID((0x20 + (x)), NO_OS_I3C_CCC_BCAST)
#define NO_OS_I3C_CCC_SETAASA NO_OS_I3C_CCC_ID(0x29, NO_OS_I3C_CCC_BCAST)
/* Unicast-only commands */
#define NO_OS_I3C_CCC_SETDASA NO_OS_I3C_CCC_ID(0x7, NO_OS_I3C_CCC_DIRECT)
#define NO_OS_I3C_CCC_SETNEWDA NO_OS_I3C_CCC_ID(0x8, NO_OS_I3C_CCC_DIRECT)
#define NO_OS_I3C_CCC_GETMWL NO_OS_I3C_CCC_ID(0xb, NO_OS_I3C_CCC_DIRECT)
#define NO_OS_I3C_CCC_GETMRL NO_OS_I3C_CCC_ID(0xc, NO_OS_I3C_CCC_DIRECT)
#define NO_OS_I3C_CCC_GETPID (NO_OS_I3C_CCC_ID(0xd, NO_OS_I3C_CCC_DIRECT) | NO_OS_I3C_CCC_SET_LEN(6) | NO_OS_I3C_CCC_SET_RNW(1))
#define NO_OS_I3C_CCC_GETBCR (NO_OS_I3C_CCC_ID(0xe, NO_OS_I3C_CCC_DIRECT) | NO_OS_I3C_CCC_SET_LEN(1) | NO_OS_I3C_CCC_SET_RNW(1))
#define NO_OS_I3C_CCC_GETDCR (NO_OS_I3C_CCC_ID(0xf, NO_OS_I3C_CCC_DIRECT) | NO_OS_I3C_CCC_SET_LEN(1) | NO_OS_I3C_CCC_SET_RNW(1))
#define NO_OS_I3C_CCC_GETSTATUS (NO_OS_I3C_CCC_ID(0x10, NO_OS_I3C_CCC_DIRECT) | NO_OS_I3C_CCC_SET_LEN(2) | NO_OS_I3C_CCC_SET_RNW(1))
#define NO_OS_I3C_CCC_GETACCMST NO_OS_I3C_CCC_ID(0x11, NO_OS_I3C_CCC_DIRECT)
#define NO_OS_I3C_CCC_SETBRGTGT NO_OS_I3C_CCC_ID(0x13, NO_OS_I3C_CCC_DIRECT)
#define NO_OS_I3C_CCC_GETMXDS NO_OS_I3C_CCC_ID(0x14, NO_OS_I3C_CCC_DIRECT)
#define NO_OS_I3C_CCC_GETHDRCAP NO_OS_I3C_CCC_ID(0x15, NO_OS_I3C_CCC_DIRECT)
#define NO_OS_I3C_CCC_GETXTIME NO_OS_I3C_CCC_ID(0x19, NO_OS_I3C_CCC_DIRECT)
#define NO_OS_I3C_CCC_EVENT_SIR NO_OS_BIT(0)
#define NO_OS_I3C_CCC_EVENT_MR NO_OS_BIT(1)
#define NO_OS_I3C_CCC_EVENT_HJ NO_OS_BIT(3)
/**
* List of possible IRQ events.
*/
#define NO_OS_I3C_IRQ_IBI 0x1
#define NO_OS_I3C_IRQ_HJ 0x2
#define NO_OS_I3C_IRQ_CR 0x4
/**
* Extract capabilities from BCR
*/
#define NO_OS_I3C_BCR_IBI_REQUEST_CAPABLE(bcr) !!((bcr) & (1 << 1))
#define NO_OS_I3C_BCR_IBI_PAYLOAD(bcr) !!((bcr) & (1 << 2))
#define NO_OS_I3C_BCR_DEVICE_ROLE(bcr) (((bcr) && NO_OS_GENMASK(7,6)) >> 6)
/**
* @enum no_os_i3c_slot_status - I3C address slot status
*
* @brief On an I3C bus, addresses are assigned dynamically, and we need to
* know which addresses are free to use and which ones are already assigned.
*
* Addresses marked as reserved are those reserved by the I3C protocol
* (broadcast address, ...).
*/
enum no_os_i3c_slot_status {
/** Address is free */
NO_OS_I3C_ADDR_SLOT_FREE,
/** Address is reserved */
NO_OS_I3C_ADDR_SLOT_RSVD,
/** Address is assigned to an I2C device */
NO_OS_I3C_ADDR_SLOT_I2C_DEV,
/** Address is assigned to an I3C device */
NO_OS_I3C_ADDR_SLOT_I3C_DEV,
/** Address slot mask */
NO_OS_I3C_ADDR_SLOT_STATUS_MASK = 3,
};
/**
* @union no_os_i3c_ccc_info
*/
struct no_os_i3c_ccc_info {
/** I3C bus receive Target Address during IBI or Bus Role Request event. */
uint32_t ibi_cr_addr;
/** I3C bus get Number of Data Payload after an IBI event. */
uint32_t ibi_payload_len;
/** I3C bus received IBI Payload. */
uint32_t ibi_payload;
};
/**
* @struct no_os_i3c_daa_lut
* @brief Stores the PID + DA information to look-up during the DAA.
* Should be used only for device initialization, since it may
* go outdated.
*/
struct no_os_i3c_daa_lut {
bool is_attached;
uint8_t addr;
uint64_t pid;
};
/**
* @struct no_os_i3c_platform_ops
* @brief Structure holding I3C function pointers that point to the platform
* specific function.
*/
struct no_os_i3c_platform_ops;
/**
* @struct no_os_i3c_bus_desc
* @brief Structure holding I3C bus descriptor.
*/
struct no_os_i3c_bus_desc {
/** I3C bus mutex(lock)*/
void* mutex;
/** Device ID*/
uint8_t device_id;
/** Non-Expected number of devices on bus */
uint8_t num_devs_unknown;
/** Expected number of devices on bus */
uint8_t num_devs;
/**
* A bitmap with 2-bits per-slot to encode the address status and
* ease the DAA (Dynamic Address Assignment) procedure (see
* enum ::no_os_i3c_slot_status).
*/
unsigned int addrslots[NO_OS_I3C_ADDRSLOTS_SIZE];
/** PID + DA LUT for DAA procedure */
struct no_os_i3c_daa_lut daa_candidates[NO_OS_I3C_MAX_DEV_NUMBER];
/** To store unknown devices assigned during DAA procedure */
struct no_os_i3c_daa_lut daa_unknown[NO_OS_I3C_MAX_DEV_NUMBER];
/** Devices descriptors */
struct no_os_i3c_desc *devs[NO_OS_I3C_MAX_DEV_NUMBER];
/** IRQ flags */
uint8_t irq_events;
/** CCC info obtained after an IRQ */
struct no_os_i3c_ccc_info ccc_info;
/** Trigger IRQ callback asyncronous (non-blocking) */
bool async_irq;
/** I3C platform specific functions */
const struct no_os_i3c_platform_ops *platform_ops;
/** I3C bus extra parameters */
void *extra;
};
/**
* @struct no_os_i3c_bus_init_param
* @brief Structure holding the parameters for I3C initialization.
*/
struct no_os_i3c_bus_init_param {
/** Device ID */
const uint32_t device_id;
/** I3C platform specific functions */
const struct no_os_i3c_platform_ops *platform_ops;
/** Expected number of devices on bus */
const uint8_t num_devs;
/** Expected devices on bus */
const struct no_os_i3c_init_param **devs;
/** I3C extra parameters (device specific) */
void *extra;
};
/**
* @struct no_os_i3c_init_param
* @brief Structure holding the parameters for I3C initialization.
* Works like a device tree, the values are copied to no_os_i3c_desc
* during I3C initialization.
* Set is_static to 1 if the device provides a Static Address and is
* desired to use it instead of assigning a Dynamic Address during the
* DAA.
* is_i3c has higher precedence than is_static, and therefore
* is_static does not matter when is_i3c is 0.
*/
struct no_os_i3c_init_param {
/** Pointer to bus init param */
struct no_os_i3c_bus_init_param *bus;
/** Provisioned ID */
uint64_t pid;
/** Dynamic or static address */
uint8_t addr;
/** Is the address static */
bool is_static;
/** Is I3C or I2C */
bool is_i3c;
};
/**
* @struct no_os_i3c_desc
* @brief Structure holding I3C device descriptor.
*/
struct no_os_i3c_desc {
/** Provisioned ID */
uint64_t pid;
/** Dynamic or static address*/
uint8_t addr;
/** Is I3C or I2C? */
bool is_i3c;
/** Is attached? */
bool is_attached;
/** Is the address static? */
bool is_static;
/** I3C extra parameters (device specific) */
void *extra;
/** Callback on event*/
void (*event_callback)(struct no_os_i3c_desc*, uint32_t, uint32_t);
/** I3C platform specific functions */
const struct no_os_i3c_platform_ops *platform_ops;
/** I3C bus */
struct no_os_i3c_bus_desc *bus;
};
/**
* @struct no_os_i3c_platform_ops
* @brief Structure holding I3C function pointers that point to the platform
* specific function.
*/
struct no_os_i3c_platform_ops {
/** I3C initialization function pointer */
int (*i3c_ops_init_bus)(struct no_os_i3c_bus_desc *,
const struct no_os_i3c_bus_init_param *);
/** I3C initialization function pointer */
int (*i3c_ops_init)(struct no_os_i3c_desc *,
const struct no_os_i3c_init_param *);
/** I3C do daa function pointer */
int (*i3c_ops_do_daa)(struct no_os_i3c_bus_desc *, bool);
/** I3C send ccc function pointer */
int (*i3c_ops_send_ccc)(struct no_os_i3c_bus_desc *, uint8_t, uint8_t,
bool, bool, uint8_t *, uint8_t);
/** I3C private write function pointer */
int (*i3c_ops_write)(struct no_os_i3c_desc *, uint8_t *, uint8_t);
/** I3C private read function pointer */
int (*i3c_ops_read)(struct no_os_i3c_desc *, uint8_t *, uint8_t);
/** I3C private write and read function pointer */
int (*i3c_ops_write_and_read)(struct no_os_i3c_desc *, uint8_t *, uint8_t,
uint8_t *, uint8_t);
/** I3C remove function pointer */
int (*i3c_ops_remove_bus)(struct no_os_i3c_bus_desc *);
/** I3C remove function pointer */
int (*i3c_ops_remove)(struct no_os_i3c_desc *);
/** I3C check is device on the bus is ready */
int (*i3c_ops_is_dev_ready)(struct no_os_i3c_desc *);
/** I3C configure the enabled irq */
int (*i3c_ops_conf_irq)(struct no_os_i3c_bus_desc *,
uint8_t, bool);
/** I3C fetch CCC info */
int (*i3c_ops_get_ccc_info)(struct no_os_i3c_bus_desc *,
uint8_t);
};
/* Initialize the I3C device. */
int no_os_i3c_init(struct no_os_i3c_desc **desc,
const struct no_os_i3c_init_param *param);
/* Initialize the I3C bus. */
int no_os_i3c_init_bus(struct no_os_i3c_bus_desc **desc,
const struct no_os_i3c_bus_init_param *param);
/* Free the resources allocated by no_os_i3c_init. */
int no_os_i3c_remove(struct no_os_i3c_desc *desc);
/* Free the resources allocated by no_os_i3c_init_bus + no_os_i3c_init. */
int no_os_i3c_remove_bus(struct no_os_i3c_bus_desc *desc);
/* Do I3C DAA to assign the dynamic addresses. */
int no_os_i3c_do_daa(struct no_os_i3c_bus_desc *desc, bool rstdaa);
/* Send CCC on the bus (direct or broadcast). */
int no_os_i3c_send_ccc(struct no_os_i3c_bus_desc *desc,
uint8_t addr, uint32_t ccc, uint8_t *data);
/* Send CCC to a device device. */
int no_os_i3c_send_direct_ccc(struct no_os_i3c_desc *desc,
uint32_t ccc, uint8_t *data);
/* Write data to a device device. */
int no_os_i3c_write(struct no_os_i3c_desc *desc,
uint8_t *data,
uint8_t size);
/* Read data from a device device. */
int no_os_i3c_read(struct no_os_i3c_desc *desc,
uint8_t *data,
uint8_t size);
/* Write and read data from a device device. */
int no_os_i3c_write_and_read(struct no_os_i3c_desc *desc,
uint8_t *tx_data,
uint8_t tx_data_len,
uint8_t *rx_data,
uint8_t rx_data_len);
/* Configure enabled interrupt. */
int no_os_i3c_conf_irq(struct no_os_i3c_bus_desc *desc,
uint8_t irq, bool en);
/* Wait I3C interrupt. */
int no_os_i3c_wait_irq(struct no_os_i3c_bus_desc* desc,
uint8_t irq);
/* Non-blocking I3C interrupt. */
int no_os_i3c_call_irq(struct no_os_i3c_bus_desc* desc);
/* Enable I3C non-blocking interrupts. */
int no_os_i3c_async_irq(struct no_os_i3c_bus_desc *desc, bool en);
/* Get a free address. */
uint8_t no_os_i3c_addr_get_free(struct no_os_i3c_bus_desc *desc,
uint8_t start_addr);
/* Set status of an address. */
void no_os_i3c_addr_set_status(struct no_os_i3c_bus_desc *desc,
uint8_t addr, enum no_os_i3c_slot_status status);
/* Attach event callback. */
void no_os_i3c_attach_callback(struct no_os_i3c_desc *desc,
void (*callback)(struct no_os_i3c_desc*, uint32_t, uint32_t));
/* Detach event callback. */
void no_os_i3c_detach_callback(struct no_os_i3c_desc *desc);
#endif // _NO_OS_I3C_H_
@@ -0,0 +1,38 @@
/*******************************************************************************
* @file no_os_init.h
* @brief Header file of platform initialization.
* @author GMois (george.mois@analog.com)
********************************************************************************
* Copyright 2022(c) Analog Devices, Inc.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* 3. Neither the name of Analog Devices, Inc. nor the names of its
* contributors may be used to endorse or promote products derived from this
* software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY ANALOG DEVICES, INC. “AS IS” AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
* EVENT SHALL ANALOG DEVICES, INC. BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
* OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
* EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*******************************************************************************/
#ifndef _NO_OS_INIT_H_
#define _NO_OS_INIT_H_
int no_os_init(void);
#endif // _NO_OS_INIT_H_
@@ -0,0 +1,265 @@
/***************************************************************************//**
* @file no_os_irq.c
* @brief Implementation of the IRQ Interface
* @author Andrei Porumb (andrei.porumb@analog.com)
********************************************************************************
* Copyright 2021(c) Analog Devices, Inc.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* 3. Neither the name of Analog Devices, Inc. nor the names of its
* contributors may be used to endorse or promote products derived from this
* software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY ANALOG DEVICES, INC. “AS IS” AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
* EVENT SHALL ANALOG DEVICES, INC. BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
* OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
* EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*******************************************************************************/
#include <inttypes.h>
#include <stdlib.h>
#include "no_os_irq.h"
#include "no_os_error.h"
/**
* @brief Initialize the IRQ interrupts.
* @param desc - The IRQ descriptor.
* @param param - The structure that contains the IRQ parameters.
* @return 0 in case of success, -1 otherwise.
*/
int no_os_irq_ctrl_init(struct no_os_irq_ctrl_desc **desc,
const struct no_os_irq_init_param *param)
{
int32_t ret;
if (!param || !param->platform_ops)
return -EINVAL;
if (!param->platform_ops->init)
return -ENOSYS;
ret = param->platform_ops->init(desc, param);
if (ret)
return ret;
(*desc)->ref++;
(*desc)->platform_ops = param->platform_ops;
return 0;
}
/**
* @brief Free the resources allocated by no_os_irq_ctrl_init().
* @param desc - The SPI descriptor.
* @return 0 in case of success, -1 otherwise.
*/
int no_os_irq_ctrl_remove(struct no_os_irq_ctrl_desc *desc)
{
if (!desc || !desc->platform_ops)
return -EINVAL;
if (!desc->platform_ops->remove)
return -ENOSYS;
if (--desc->ref)
return 0;
return desc->platform_ops->remove(desc);
}
/**
* @brief Register a callback to handle the irq events.
* @param desc - The IRQ controller descriptor.
* @param irq_id - Interrupt identifier.
* @param callback - Callback descriptor - platform specific type.
* @return SUCCESS in case of success, FAILURE otherwise.
*/
int no_os_irq_register_callback(struct no_os_irq_ctrl_desc *desc,
uint32_t irq_id,
struct no_os_callback_desc *callback)
{
if (!desc || !desc->platform_ops)
return -EINVAL;
if (!desc->platform_ops->register_callback)
return -ENOSYS;
return desc->platform_ops->register_callback(desc, irq_id, callback);
}
/**
* @brief Unregisters a generic IRQ handling function.
* @param desc - The IRQ controller descriptor.
* @param irq_id - Interrupt identifier.
* @param callback - Callback descriptor - platform specific type.
* @return SUCCESS in case of success, FAILURE otherwise.
*/
int no_os_irq_unregister_callback(struct no_os_irq_ctrl_desc *desc,
uint32_t irq_id,
struct no_os_callback_desc *callback)
{
if (!desc || !desc->platform_ops)
return -EINVAL;
if (!desc->platform_ops->unregister_callback)
return -ENOSYS;
return desc->platform_ops->unregister_callback(desc, irq_id, callback);
}
/**
* @brief Enable global interrupts.
* @return 0 in case of success, -1 otherwise.
*/
int no_os_irq_global_enable(struct no_os_irq_ctrl_desc *desc)
{
if (!desc || !desc->platform_ops)
return -EINVAL;
if (!desc->platform_ops->global_enable)
return -ENOSYS;
return desc->platform_ops->global_enable(desc);
}
/**
* @brief Disable global interrupts.
* @return 0 in case of success, -1 otherwise.
*/
int no_os_irq_global_disable(struct no_os_irq_ctrl_desc *desc)
{
if (!desc || !desc->platform_ops)
return -EINVAL;
if (!desc->platform_ops->global_disable)
return -ENOSYS;
return desc->platform_ops->global_disable(desc);
}
/**
* @brief Set interrupt trigger level.
* @param desc - The IRQ controller descriptor.
* @param irq_id - Interrupt identifier.
* @param trig - New trigger level for the interrupt.
* @return 0 in case of success, -1 otherwise.
*/
int no_os_irq_trigger_level_set(struct no_os_irq_ctrl_desc *desc,
uint32_t irq_id,
enum no_os_irq_trig_level trig)
{
if (!desc || !desc->platform_ops)
return -EINVAL;
if (!desc->platform_ops->trigger_level_set)
return -ENOSYS;
return desc->platform_ops->trigger_level_set(desc, irq_id, trig);
}
/**
* @brief Enable specific interrupt.
* @param desc - The IRQ controller descriptor.
* @param irq_id - Interrupt identifier.
* @return 0 in case of success, -1 otherwise.
*/
int no_os_irq_enable(struct no_os_irq_ctrl_desc *desc, uint32_t irq_id)
{
if (!desc || !desc->platform_ops)
return -EINVAL;
if (!desc->platform_ops->enable)
return -ENOSYS;
return desc->platform_ops->enable(desc, irq_id);
}
/**
* @brief Disable specific interrupt.
* @param desc - The IRQ controller descriptor.
* @param irq_id - Interrupt identifier.
* @return 0 in case of success, -1 otherwise.
*/
int no_os_irq_disable(struct no_os_irq_ctrl_desc *desc, uint32_t irq_id)
{
if (!desc || !desc->platform_ops)
return -EINVAL;
if (!desc->platform_ops->disable)
return -ENOSYS;
return desc->platform_ops->disable(desc, irq_id);
}
/**
* @brief Set the priority for an interrupt.
* @param desc - The IRQ controller descriptor.
* @param irq_id - Interrupt identifier.
* @param priority_level - The priority level of the interrupt.
* @return 0 in case of success, negative errno error codes.
*/
int no_os_irq_set_priority(struct no_os_irq_ctrl_desc *desc,
uint32_t irq_id,
uint32_t priority_level)
{
if (!desc || !desc->platform_ops)
return -EINVAL;
if (!desc->platform_ops->set_priority)
return -ENOSYS;
return desc->platform_ops->set_priority(desc, irq_id, priority_level);
}
/**
* @brief Get the priority for an interrupt.
* @param desc - The IRQ controller descriptor.
* @param irq_id - Interrupt identifier.
* @param priority_level - The priority level of the interrupt.
* @return 0 in case of success, negative errno error codes.
*/
int no_os_irq_get_priority(struct no_os_irq_ctrl_desc *desc,
uint32_t irq_id,
uint32_t *priority_level)
{
if (!desc || !desc->platform_ops)
return -EINVAL;
if (!desc->platform_ops->get_priority)
return -ENOSYS;
return desc->platform_ops->get_priority(desc, irq_id, priority_level);
}
/**
* @brief Clear the pending interrupt.
* @param desc - The IRQ controller descriptor.
* @param irq_id - Interrupt identifier.
* @return 0 in case of success, negative errno error codes.
*/
int no_os_irq_clear_pending(struct no_os_irq_ctrl_desc* desc,
uint32_t irq_id)
{
if (!desc || !desc->platform_ops)
return -EINVAL;
if (!desc->platform_ops->clear_pending)
return -ENOSYS;
return desc->platform_ops->clear_pending(desc, irq_id);
}
@@ -0,0 +1,235 @@
/***************************************************************************//**
* @file no_os_irq.h
* @brief Header file of IRQ interface.
* @author Cristian Pop (cristian.pop@analog.com)
********************************************************************************
* Copyright 2019(c) Analog Devices, Inc.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* 3. Neither the name of Analog Devices, Inc. nor the names of its
* contributors may be used to endorse or promote products derived from this
* software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY ANALOG DEVICES, INC. “AS IS” AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
* EVENT SHALL ANALOG DEVICES, INC. BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
* OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
* EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*******************************************************************************/
#ifndef _NO_OS_IRQ_H_
#define _NO_OS_IRQ_H_
#include <stdint.h>
/**
* @enum no_os_irq_uart_event_e
* @brief Possible events for uart interrupt
* @todo replace this with enum no_os_irq_event
*/
enum no_os_irq_uart_event_e {
/** Write operation finalized */
NO_OS_IRQ_WRITE_DONE,
/** Read operation finalized */
NO_OS_IRQ_READ_DONE,
/** An error occurred */
NO_OS_IRQ_ERROR
};
enum no_os_irq_event {
NO_OS_EVT_GPIO,
NO_OS_EVT_UART_TX_COMPLETE,
NO_OS_EVT_UART_RX_COMPLETE,
NO_OS_EVT_UART_ERROR,
NO_OS_EVT_RTC,
NO_OS_EVT_XINT,
NO_OS_EVT_TIM_ELAPSED,
NO_OS_EVT_TIM_PWM_PULSE_FINISHED,
NO_OS_EVT_LPTIM_PWM_PULSE_FINISHED,
NO_OS_EVT_DMA_RX_COMPLETE,
NO_OS_EVT_DMA_RX_HALF_COMPLETE,
NO_OS_EVT_DMA_TX_COMPLETE,
NO_OS_EVT_USB,
};
enum no_os_irq_trig_level {
NO_OS_IRQ_LEVEL_LOW,
NO_OS_IRQ_LEVEL_HIGH,
NO_OS_IRQ_EDGE_FALLING,
NO_OS_IRQ_EDGE_RISING,
NO_OS_IRQ_EDGE_BOTH
};
enum no_os_irq_peripheral {
NO_OS_GPIO_IRQ,
NO_OS_UART_IRQ,
NO_OS_RTC_IRQ,
NO_OS_TIM_IRQ,
NO_OS_LPTIM_IRQ,
NO_OS_TDM_DMA_IRQ,
NO_OS_TIM_DMA_IRQ,
NO_OS_SPI_DMA_IRQ,
NO_OS_DMA_IRQ,
NO_OS_USB_IRQ,
};
/**
* @struct no_os_irq_platform_ops
* @brief Structure holding IRQ function pointers that point to the platform
* specific function
*/
struct no_os_irq_platform_ops ;
/**
* @struct no_os_irq_init_param
* @brief Structure holding the initial parameters for Interrupt Request.
*/
struct no_os_irq_init_param {
/** Interrupt request controller ID. */
uint32_t irq_ctrl_id;
/** Platform specific IRQ platform ops structure. */
const struct no_os_irq_platform_ops *platform_ops;
/**
* This is intended to store irq controller specific configurations,
* it should not be a reference to any peripheral descriptor.
*/
void *extra;
};
/**
* @struct irq_desc
* @brief Structure for Interrupt Request descriptor.
*/
struct no_os_irq_ctrl_desc {
/** Interrupt request controller ID. */
uint32_t irq_ctrl_id;
/** Platform specific IRQ platform ops structure. */
const struct no_os_irq_platform_ops *platform_ops;
/* Reference counter */
uint32_t ref;
/**
* This is intended to store irq controller specific configurations,
* it should not be a reference to any peripheral descriptor.
*/
void *extra;
};
/**
* @struct no_os_callback_desc
* @brief Structure describing a callback to be registered
* @todo: remove this, use struct irq_callback instead.
*/
struct no_os_callback_desc {
/** Callback to be called when the event an event occurs. */
void (*callback)(void *context);
/** Parameter to be passed when the callback is called */
void *ctx;
/** Platform specific event that triggers the calling of the callback. */
enum no_os_irq_event event;
/** Interrupt source peripheral specifier. */
enum no_os_irq_peripheral peripheral;
/** This will be used to store HAL specific descriptors */
void *handle;
};
/**
* @struct no_os_irq_platform_ops
* @brief Structure holding IRQ function pointers that point to the platform
* specific function
*/
struct no_os_irq_platform_ops {
/** Initialize a interrupt controller peripheral. */
int (*init)(struct no_os_irq_ctrl_desc **desc,
const struct no_os_irq_init_param *param);
/** Register a callback to handle the irq events */
int (*register_callback)(struct no_os_irq_ctrl_desc *desc, uint32_t irq_id,
struct no_os_callback_desc *callback);
/** Unregisters a generic IRQ handling function */
int (*unregister_callback)(struct no_os_irq_ctrl_desc *desc,
uint32_t irq_id,
struct no_os_callback_desc *callback);
/** Global interrupt enable */
int (*global_enable)(struct no_os_irq_ctrl_desc *desc);
/** Global interrupt disable */
int (*global_disable)(struct no_os_irq_ctrl_desc *desc);
/** Set interrupt trigger level. */
int (*trigger_level_set)(struct no_os_irq_ctrl_desc *desc, uint32_t irq_id,
enum no_os_irq_trig_level trig);
/** Enable specific interrupt */
int (*enable)(struct no_os_irq_ctrl_desc *desc, uint32_t irq_id);
/** Disable specific interrupt */
int (*disable)(struct no_os_irq_ctrl_desc *desc, uint32_t irq_id);
/** Set the priority level for a specific interrupt */
int (*set_priority)(struct no_os_irq_ctrl_desc *desc, uint32_t irq_id,
uint32_t priority_level);
/** Get the priority level for a specific interrupt */
int (*get_priority)(struct no_os_irq_ctrl_desc *desc, uint32_t irq_id,
uint32_t *priority_level);
/** IRQ remove function pointer */
int (*remove)(struct no_os_irq_ctrl_desc *desc);
/** Clear pending interrupt */
int(*clear_pending)(struct no_os_irq_ctrl_desc* desc, uint32_t irq_id);
};
/* Initialize a interrupt controller peripheral. */
int no_os_irq_ctrl_init(struct no_os_irq_ctrl_desc **desc,
const struct no_os_irq_init_param *param);
/* Free the resources allocated by no_os_irq_ctrl_init(). */
int no_os_irq_ctrl_remove(struct no_os_irq_ctrl_desc *desc);
/* Register a callback to handle the irq events */
int no_os_irq_register_callback(struct no_os_irq_ctrl_desc *desc,
uint32_t irq_id,
struct no_os_callback_desc *callback_desc);
/* Unregisters a generic IRQ handling function */
int no_os_irq_unregister_callback(struct no_os_irq_ctrl_desc *desc,
uint32_t irq_id,
struct no_os_callback_desc *callback_desc);
/* Global interrupt enable */
int no_os_irq_global_enable(struct no_os_irq_ctrl_desc *desc);
/* Global interrupt disable */
int no_os_irq_global_disable(struct no_os_irq_ctrl_desc *desc);
/* Set interrupt trigger level. */
int no_os_irq_trigger_level_set(struct no_os_irq_ctrl_desc *desc,
uint32_t irq_id,
enum no_os_irq_trig_level trig);
/* Enable specific interrupt */
int no_os_irq_enable(struct no_os_irq_ctrl_desc *desc, uint32_t irq_id);
/* Disable specific interrupt */
int no_os_irq_disable(struct no_os_irq_ctrl_desc *desc, uint32_t irq_id);
/** Set the priority level for a specific interrupt */
int no_os_irq_set_priority(struct no_os_irq_ctrl_desc *desc,
uint32_t irq_id,
uint32_t priority_level);
/** Get the priority level for a specific interrupt */
int no_os_irq_get_priority(struct no_os_irq_ctrl_desc *desc,
uint32_t irq_id,
uint32_t *priority_level);
/* Clear the pending interrupts */
int no_os_irq_clear_pending(struct no_os_irq_ctrl_desc* desc,
uint32_t irq_id);
#endif // _NO_OS_IRQ_H_
@@ -0,0 +1,148 @@
/***************************************************************************//**
* @file no_os_lf256fifo.c
* @brief SPSC lock-free fifo of fixed size (256), specialized for UART.
* @author Darius Berghe (darius.berghe@analog.com)
********************************************************************************
* @copyright
* Copyright 2020(c) Analog Devices, Inc.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* 3. Neither the name of Analog Devices, Inc. nor the names of its
* contributors may be used to endorse or promote products derived from this
* software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY ANALOG DEVICES, INC. “AS IS” AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
* EVENT SHALL ANALOG DEVICES, INC. BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
* OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
* EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*******************************************************************************/
#include <errno.h>
#include "no_os_lf256fifo.h"
#include "no_os_alloc.h"
/**
* @struct lf256fifo
* @brief Structure holding the fifo element parameters.
*/
struct lf256fifo {
uint8_t * data; // pointer to memory area where the buffer will be allocated
uint8_t ffilled; // the index where the data starts
uint8_t fempty; // the index where empty/non-used area starts
};
/**
* @brief Initialize and allocate a lock-free 256 FIFO.
* @param fifo - pointer to a fifo descriptor pointer.
* @return 0 if successful, negative error code otherwise.
*/
int lf256fifo_init(struct lf256fifo **fifo)
{
if (fifo == NULL)
return -EINVAL;
struct lf256fifo *b = no_os_calloc(1, sizeof(struct lf256fifo));
if (b == NULL)
return -ENOMEM;
b->data = no_os_calloc(1, 256);
if (b->data == NULL) {
no_os_free(b);
return -ENOMEM;
}
*fifo = b;
return 0;
}
/**
* @brief Test whether fifo is full.
* @param fifo - pointer to fifo descriptor.
* @return true if fifo is full, false if not full.
*/
bool lf256fifo_is_full(struct lf256fifo *fifo)
{
return (fifo->fempty + 1) ==
fifo->ffilled; // intended overflow at 256 (data size is 256)
}
/**
* @brief Test whether fifo is empty.
* @param fifo - pointer to fifo descriptor.
* @return true if fifo is empty, false if not empty.
*/
bool lf256fifo_is_empty(struct lf256fifo *fifo)
{
return fifo->fempty == fifo->ffilled;
}
/**
* @brief Read char from fifo.
* @param fifo - pointer to fifo descriptor.
* @param c - pointer to memory where the char element is read.
* @return 0 if successful, -1 if buffer empty.
*/
int lf256fifo_read(struct lf256fifo * fifo, uint8_t *c)
{
if (lf256fifo_is_empty(fifo))
return -1; // buffer empty
*c = fifo->data[fifo->ffilled];
fifo->ffilled++; // intended overflow at 256 (data size is 256)
return 0;
}
/**
* @brief Write char to fifo.
* @param fifo - pointer to fifo descriptor.
* @param c - char element to write.
* @return 0 if successful, -1 if buffer full.
*/
int lf256fifo_write(struct lf256fifo *fifo, uint8_t c)
{
if (lf256fifo_is_full(fifo))
return -1; // buffer full
fifo->data[fifo->fempty] = c;
fifo->fempty++; // intended overflow at 256 (data size is 256)
return 0; // return success
}
/**
* @brief Flush the fifo.
* @param fifo - pointer to fifo descriptor.
* @return void
*/
void lf256fifo_flush(struct lf256fifo *fifo)
{
fifo->ffilled = fifo->fempty;
}
/**
* @brief Remove the fifo
* @param fifo - pointer to fifo descriptor.
* @return void
*/
void lf256fifo_remove(struct lf256fifo *fifo)
{
if (fifo && fifo->data)
no_os_free(fifo->data);
}
@@ -0,0 +1,53 @@
/***************************************************************************//**
* @file no_os_lf256fifo.h
* @brief SPSC lock-free fifo of fixed size (256), specialized for UART.
* @author Darius Berghe (darius.berghe@analog.com)
********************************************************************************
* @copyright
* Copyright 2020(c) Analog Devices, Inc.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* 3. Neither the name of Analog Devices, Inc. nor the names of its
* contributors may be used to endorse or promote products derived from this
* software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY ANALOG DEVICES, INC. “AS IS” AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
* EVENT SHALL ANALOG DEVICES, INC. BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
* OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
* EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*******************************************************************************/
#ifndef __LFFIFO_H
#define __LFFIFO_H
#include <stdlib.h>
#include <stdint.h>
#include <stdbool.h>
struct lf256fifo;
int lf256fifo_init(struct lf256fifo **);
bool lf256fifo_is_full(struct lf256fifo *);
bool lf256fifo_is_empty(struct lf256fifo *);
int lf256fifo_read(struct lf256fifo *, uint8_t *);
int lf256fifo_write(struct lf256fifo *, uint8_t);
void lf256fifo_flush(struct lf256fifo *);
void lf256fifo_remove(struct lf256fifo *fifo);
#endif
@@ -0,0 +1,871 @@
/***************************************************************************//**
* @file no_os_list.c
* @brief List library implementation
* @author Mihail Chindris (mihail.chindris@analog.com)
********************************************************************************
* Copyright 2020(c) Analog Devices, Inc.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* 3. Neither the name of Analog Devices, Inc. nor the names of its
* contributors may be used to endorse or promote products derived from this
* software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY ANALOG DEVICES, INC. “AS IS” AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
* EVENT SHALL ANALOG DEVICES, INC. BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
* OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
* EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*******************************************************************************/
#include "no_os_list.h"
#include "no_os_error.h"
#include "no_os_alloc.h"
#include <stdlib.h>
/**
* @struct no_os_list_elem
* @brief Format of each element of the list
*/
struct no_os_list_elem {
/** User data */
void *data;
/** Reference to previous element */
struct no_os_list_elem *prev;
/** Reference to next element */
struct no_os_list_elem *next;
};
/**
* @struct list_iterator
* @brief Structure used to iterate through the list
*/
struct no_os_iterator {
/** List reference */
struct _list_desc *list;
/** Current element reference */
struct no_os_list_elem *elem;
};
/**
* @struct _list_desc
* @brief List descriptor
*/
struct _list_desc {
/** Reference to first element in the list */
struct no_os_list_elem *first;
/** Reference to last element in the list*/
struct no_os_list_elem *last;
/** Number of elements in the list */
uint32_t nb_elements;
/** Function used to compare elements */
f_cmp comparator;
/** Number of current active iterators */
uint32_t nb_iterators;
/** Internal list iterator */
struct no_os_iterator l_it;
};
/** @brief Default function used to compare element in the list ( \ref f_cmp) */
static int32_t no_os_default_comparator(void *data1, void *data2)
{
return (int32_t)((int32_t *)data1 - (int32_t *)data2);
}
/**
* @brief Creates a new list elements an configure its value
* @param data - To set list_elem.data
* @param prev - To set list_elem.prev
* @param next - To set list_elem.next
* @return Address of the new element or NULL if allocation fails.
*/
static inline struct no_os_list_elem *create_element(void *data,
struct no_os_list_elem *prev,
struct no_os_list_elem *next)
{
struct no_os_list_elem *elem;
elem = (struct no_os_list_elem *)no_os_calloc(1, sizeof(*elem));
if (!elem)
return NULL;
elem->data = data;
elem->prev = prev;
elem->next = next;
return (elem);
}
/**
* @brief Updates the necesary link on the list elements to add or remove one
* @param prev - Low element
* @param elem - Middle element
* @param next - High element
*/
static inline void no_os_update_links(struct no_os_list_elem *prev,
struct no_os_list_elem *elem,
struct no_os_list_elem *next)
{
if (prev)
prev->next = elem ? elem : next;
if (elem) {
elem->prev = prev;
elem->next = next;
}
if (next)
next->prev = elem ? elem : prev;
}
/**
* @brief Update according to modification the list descriptor
* @param list - List reference
* @param new_first - New first element
* @param new_last - New last element
*/
static inline void no_os_update_desc(struct _list_desc *list,
struct no_os_list_elem *new_first,
struct no_os_list_elem *new_last)
{
if (new_first == list->first) {
list->last = new_last;
if (new_first == NULL || new_last == NULL)
list->first = new_last;
} else { /* if (new_last == list->last) */
list->first = new_first;
if (new_last == NULL || new_first == NULL)
list->last = new_first;
}
}
/**
* @brief Set the adapter functions acording to the adapter type
* @param ad - Reference of the adapter
* @param type - Type of the adapter
*/
static inline void no_os_set_adapter(struct no_os_list_desc *ad,
enum no_os_adapter_type type)
{
switch (type) {
case NO_OS_LIST_PRIORITY_LIST:
ad->push = no_os_list_add_find;
ad->pop = no_os_list_get_first;
ad->top_next = no_os_list_read_first;
ad->back = no_os_list_read_last;
ad->swap = no_os_list_edit_first;
break;
case NO_OS_LIST_QUEUE:
ad->push = no_os_list_add_last;
ad->pop = no_os_list_get_first;
ad->top_next = no_os_list_read_first;
ad->back = no_os_list_read_last;
ad->swap = no_os_list_edit_first;
break;
case NO_OS_LIST_DEFAULT:
case NO_OS_LIST_STACK:
default:
ad->push = no_os_list_add_last;
ad->pop = no_os_list_get_last;
ad->top_next = no_os_list_read_last;
ad->back = no_os_list_read_first;
ad->swap = no_os_list_edit_last;
break;
}
}
/**
* @brief Create a new empty list
* @param list_desc - Where to store the reference of the new created list
* @param type - Type of adapter to use.
* @param comparator - Used to compare item when using an ordered list or when
* using the \em find functions.
* @return
* - 0 : On success
* - -1 : Otherwise
*/
int32_t no_os_list_init(struct no_os_list_desc **list_desc,
enum no_os_adapter_type type,
f_cmp comparator)
{
struct no_os_list_desc *l_desc;
struct _list_desc *list;
if (!list_desc)
return -1;
l_desc = (struct no_os_list_desc *)no_os_calloc(1, sizeof(*l_desc));
if (!l_desc)
return -1;
list = (struct _list_desc *)no_os_calloc(1, sizeof(*list));
if (!list) {
no_os_free(l_desc);
return -1;
}
*list_desc = l_desc;
l_desc->priv_desc = list;
list->comparator = comparator ? comparator : no_os_default_comparator;
/* Configure wrapper */
no_os_set_adapter(l_desc, type);
list->l_it.list = list;
return 0;
}
/**
* @brief Remove the created list.
*
* All its elements will be cleared and the data inside each will be lost. If
* not all iterators have been removed, the list will not be removed.
* @param list_desc - Reference to the list
* @return
* - 0 : On success
* - -1 : Otherwise
*/
int32_t no_os_list_remove(struct no_os_list_desc *list_desc)
{
void *data;
struct _list_desc *list;
if (!list_desc)
return -1;
list = list_desc->priv_desc;
if (list->nb_iterators != 0)
return -1;
/* Remove all the elements */
while (0 == no_os_list_get_first(list_desc, &data))
;
no_os_free(list_desc->priv_desc);
no_os_free(list_desc);
return 0;
}
/**
* @brief Get the number of elements inside the list
* @param list_desc - List reference
* @param out_size - Where to store the number of elements
* @return
* - 0 : On success
* - -1 : Otherwise
*/
int32_t no_os_list_get_size(struct no_os_list_desc *list_desc,
uint32_t *out_size)
{
struct _list_desc *list;
if (!list_desc || !out_size)
return -1;
list = list_desc->priv_desc;
*out_size = list->nb_elements;
return 0;
}
/** @brief Add element at the begining of the list. Refer to \ref f_add */
int32_t no_os_list_add_first(struct no_os_list_desc *list_desc, void *data)
{
struct no_os_list_elem *prev;
struct no_os_list_elem *next;
struct no_os_list_elem *elem;
struct _list_desc *list;
if (!list_desc)
return -1;
list = list_desc->priv_desc;
prev = NULL;
next = list->first;
elem = create_element(data, prev, next);
if (!elem)
return -1;
no_os_update_links(prev, elem, next);
no_os_update_desc(list, elem, list->last);
list->nb_elements++;
return 0;
}
/** @brief Add element at the end of the list. Refer to \ref f_add */
int32_t no_os_list_add_last(struct no_os_list_desc *list_desc, void *data)
{
struct no_os_list_elem *prev;
struct no_os_list_elem *next;
struct no_os_list_elem *elem;
struct _list_desc *list;
if (!list_desc)
return -1;
list = list_desc->priv_desc;
prev = list->last;
next = NULL;
elem = create_element(data, prev, next);
if (!elem)
return -1;
no_os_update_links(prev, elem, next);
no_os_update_desc(list, list->first, elem);
list->nb_elements++;
return 0;
}
/** @brief Add element at the specified idx. Refer to \ref f_add */
int32_t no_os_list_add_idx(struct no_os_list_desc *list_desc, void *data,
uint32_t idx)
{
struct _list_desc *list;
if (!list_desc)
return -1;
list = list_desc->priv_desc;
/* If there are no elements the creation of an iterator will fail */
if (list->nb_elements == 0 || idx == 0)
return no_os_list_add_first(list_desc, data);
if (list->nb_elements == idx)
return no_os_list_add_last(list_desc, data);
list->l_it.elem = list->first;
if (0 != no_os_iterator_move(&(list->l_it), idx))
return -1;
return no_os_iterator_insert(&(list->l_it), data, 0);
}
/** @brief Add element in ascending order. Refer to \ref f_add */
int32_t no_os_list_add_find(struct no_os_list_desc *list_desc, void *data)
{
struct no_os_list_elem *elem;
struct _list_desc *list;
if (!list_desc)
return -1;
list = list_desc->priv_desc;
/* Based on place iterator */
elem = list->first;
while (elem) {
if (0 < list->comparator(elem->data, data))
break;
elem = elem->next;
}
if (elem == NULL) {
list->l_it.elem = list->last;
return no_os_iterator_insert(&(list->l_it), data, 1);
} else {
list->l_it.elem = elem;
return no_os_iterator_insert(&(list->l_it), data, 0);
}
}
/** @brief Edit the first element of the list. Refer to \ref f_edit */
int32_t no_os_list_edit_first(struct no_os_list_desc *list_desc, void *new_data)
{
struct _list_desc *list;
if (!list_desc)
return -1;
list = list_desc->priv_desc;
list->first->data = new_data;
return 0;
}
/** @brief Edit the last element of the list. Refer to \ref f_edit */
int32_t no_os_list_edit_last(struct no_os_list_desc *list_desc, void *new_data)
{
struct _list_desc *list;
if (!list_desc)
return -1;
list = list_desc->priv_desc;
list->last->data = new_data;
return 0;
}
/** @brief Edit the element at the specified idx. Refer to \ref f_edit */
int32_t no_os_list_edit_idx(struct no_os_list_desc *list_desc, void *new_data,
uint32_t idx)
{
struct _list_desc *list;
if (!list_desc)
return -1;
list = list_desc->priv_desc;
list->l_it.elem = list->first;
if (0 != no_os_iterator_move(&(list->l_it), idx))
return -1;
return no_os_iterator_edit(&(list->l_it), new_data);
}
/** @brief Edit the element which match with cmp_data. Refer to \ref f_edit */
int32_t no_os_list_edit_find(struct no_os_list_desc *list_desc, void *new_data,
void *cmp_data)
{
struct _list_desc *list;
if (!list_desc)
return -1;
list = list_desc->priv_desc;
list->l_it.elem = list->first;
if (0 != no_os_iterator_find(&(list->l_it), cmp_data))
return -1;
return no_os_iterator_edit(&(list->l_it), new_data);
}
/** @brief Read the first element of the list. Refer to \ref f_read */
int32_t no_os_list_read_first(struct no_os_list_desc *list_desc, void **data)
{
struct _list_desc *list;
if (!list_desc || !data)
return -1;
*data = NULL;
list = list_desc->priv_desc;
if (!list->first)
return -1;
*data = list->first->data;
return 0;
}
/** @brief Read the last element of the list. Refer to \ref f_read */
int32_t no_os_list_read_last(struct no_os_list_desc *list_desc, void **data)
{
struct _list_desc *list;
if (!list_desc || !data)
return -1;
*data = NULL;
list = list_desc->priv_desc;
if (!list->last)
return -1;
*data = list->last->data;
return 0;
}
/** @brief Read the element at the specified idx. Refer to \ref f_read */
int32_t no_os_list_read_idx(struct no_os_list_desc *list_desc, void **data,
uint32_t idx)
{
struct _list_desc *list;
if (!list_desc || !data)
return -1;
*data = NULL;
list = list_desc->priv_desc;
if (!list)
return -1;
if (idx >= list->nb_elements)
return -1;
list->l_it.elem = list->first;
if (0 != no_os_iterator_move(&(list->l_it), idx))
return -1;
return no_os_iterator_read(&(list->l_it), data);
}
/** @brief Read the element which match with cmp_data. Refer to \ref f_read */
int32_t no_os_list_read_find(struct no_os_list_desc *list_desc, void **data,
void *cmp_data)
{
struct _list_desc *list;
if (!list_desc || !data)
return -1;
*data = NULL;
list = list_desc->priv_desc;
if (!list)
return -1;
list = list_desc->priv_desc;
list->l_it.elem = list->first;
if (0 != no_os_iterator_find(&(list->l_it), cmp_data))
return -1;
return no_os_iterator_read(&(list->l_it), data);
}
/** @brief Read and delete the first element of the list. Refer to \ref f_get */
int32_t no_os_list_get_first(struct no_os_list_desc *list_desc, void **data)
{
struct no_os_list_elem *prev;
struct no_os_list_elem *next;
struct no_os_list_elem *elem;
struct _list_desc *list;
if (!list_desc || !data)
return -1;
*data = NULL;
list = list_desc->priv_desc;
if (!list->nb_elements)
return -1;
elem = list->first;
prev = elem->prev;
next = elem->next;
no_os_update_links(prev, NULL, next);
no_os_update_desc(list, next, list->last);
list->nb_elements--;
*data = elem->data;
no_os_free(elem);
return 0;
}
/** @brief Read and delete the last element of the list. Refer to \ref f_get */
int32_t no_os_list_get_last(struct no_os_list_desc *list_desc, void **data)
{
struct no_os_list_elem *prev;
struct no_os_list_elem *next;
struct no_os_list_elem *elem;
struct _list_desc *list;
if (!list_desc || !data)
return -1;
*data = NULL;
list = list_desc->priv_desc;
if (!list->nb_elements)
return -1;
elem = list->last;
prev = elem->prev;
next = elem->next;
no_os_update_links(prev, NULL, next);
no_os_update_desc(list, list->first, prev);
list->nb_elements--;
*data = elem->data;
no_os_free(elem);
return 0;
}
/** @brief Read and delete the element at idx. Refer to \ref f_get */
int32_t no_os_list_get_idx(struct no_os_list_desc *list_desc, void **data,
uint32_t idx)
{
struct _list_desc *list;
if (!list_desc || !data)
return -1;
*data = NULL;
list = list_desc->priv_desc;
list->l_it.elem = list->first;
if (0 != no_os_iterator_move(&(list->l_it), idx))
return -1;
return no_os_iterator_get(&(list->l_it), data);
}
/**
* @brief Read and delete the element which match with cmp_data.
* Refer to \ref f_get
*/
int32_t no_os_list_get_find(struct no_os_list_desc *list_desc, void **data,
void *cmp_data)
{
struct _list_desc *list;
if (!list_desc || !data)
return -1;
*data = NULL;
list = list_desc->priv_desc;
list->l_it.elem = list->first;
if (0 != no_os_iterator_find(&(list->l_it), cmp_data))
return -1;
return no_os_iterator_get(&(list->l_it), data);
}
/**
* @brief Create a new iterator
* @param iter - Where to store the reference for the new iterator
* @param list_desc - Reference of the list the iterator will be used for
* @param start - If it is true the iterator will be positioned at the first
* element of the list, else it will be positioned at the last.
* @return
* - 0 : On success
* - -1 : Otherwise
*/
int32_t no_os_iterator_init(struct no_os_iterator **iter,
struct no_os_list_desc *list_desc,
bool start)
{
struct no_os_iterator *it;
if (!list_desc)
return -1;
it = (struct no_os_iterator *)no_os_calloc(1, sizeof(*it));
if (!it)
return -1;
it->list = list_desc->priv_desc;
it->list->nb_iterators++;
it->elem = start ? it->list->first : it->list->last;
*iter = it;
return 0;
}
/**
* @brief Remove the created iterator
* @param iter - Reference of the iterator
* @return
* - 0 : On success
* - -1 : Otherwise
*/
int32_t no_os_iterator_remove(struct no_os_iterator *iter)
{
struct no_os_iterator *it = iter;
if (!it)
return -1;
it->list->nb_iterators--;
no_os_free(it);
return 0;
}
/**
* @brief Move the position of the iteration through the list.
*
* If the required position is outside the list, the call will fail and the
* iterator will keep its position.
* @param iter - Reference of the iterator
* @param steps - Number of positions to be move. If positive, it will be moved
* forward, otherwise backwords.
* @return
* - 0 : On success
* - -1 : Otherwise
*/
int32_t no_os_iterator_move(struct no_os_iterator *iter, int32_t steps)
{
struct no_os_iterator *it = iter;
struct no_os_list_elem *elem;
int32_t dir = (steps < 0) ? -1 : 1;
if (!it)
return -1;
steps = abs(steps);
elem = it->elem;
while (steps > 0 && elem) {
elem = dir > 0 ? elem->next : elem->prev;
steps--;
}
if (!elem)
return -1;
it->elem = elem;
return 0;
}
/**
* @brief Move the position of the iterator at the specified index of the list.
*
* @param iter - Reference of the iterator
* @param idx - Position in the list. If negative start counting backwords
* @return
* - 0 : On success
* - -1 : Otherwise
*/
int32_t no_os_iterator_move_to_idx(struct no_os_iterator *iter, int32_t idx)
{
struct no_os_list_elem *elem;
int32_t dir = (idx < 0) ? -1 : 1;
if (!iter)
return -1;
idx = abs(idx);
elem = dir > 0 ? iter->list->first : iter->list->last;
while (idx > 0 && elem) {
elem = dir > 0 ? elem->next : elem->prev;
idx--;
}
if (!elem)
return -1;
iter->elem = elem;
return 0;
}
/**
* @brief Place the iterator where cmp_data if found.
* @param iter - Reference to the iterator
* @param cmp_data - Data to be found
* @return
* - 0 : On success
* - -1 : Otherwise
*/
int32_t no_os_iterator_find(struct no_os_iterator *iter, void *cmp_data)
{
struct no_os_iterator *it = iter;
struct no_os_list_elem *elem;
if (!it)
return -1;
elem = it->list->first;
while (elem) {
if (0 == it->list->comparator(elem->data, cmp_data)) {
it->elem = elem;
return 0;
}
elem = elem->next;
}
return -1;
}
/**
* @brief Replace the data at the current position. Refer to \ref f_edit
*/
int32_t no_os_iterator_edit(struct no_os_iterator *iter, void *new_data)
{
struct no_os_iterator *it = iter;
if (!it)
return -1;
it->elem->data = new_data;
return 0;
}
/**
* @brief Read and remove the data at the current position. Refer to \ref f_get.
*
* If the current item is the last one, the iterator will be moved to the
* previous one.
*/
int32_t no_os_iterator_get(struct no_os_iterator *iter, void **data)
{
struct no_os_iterator *it = iter;
struct no_os_list_elem *next;
if (!it || !it->elem || !data)
return -1;
no_os_update_links(it->elem->prev, NULL, it->elem->next);
if (it->elem == it->list->first)
no_os_update_desc(it->list, it->elem->next, it->list->last);
else if (it->elem == it->list->last)
no_os_update_desc(it->list, it->list->first, it->elem->prev);
it->list->nb_elements--;
*data = it->elem->data;
if (it->elem == it->list->last)
next = it->elem->prev;
else
next = it->elem->next;
no_os_free(it->elem);
it->elem = next;
return 0;
}
/**
* @brief Read the data at the current position. Refer to \ref f_read
*/
int32_t no_os_iterator_read(struct no_os_iterator *iter, void **data)
{
struct no_os_iterator *it = iter;
if (!it || !it->elem || !data)
return -1;
*data = it->elem->data;
return 0;
}
/**
* @brief Insert an item in the list. Refer to \ref f_add
* @param iter
* @param data
* @param after - If true, the item will be inserted after the current position.
* Otherwise it will be inserted before.
*/
int32_t no_os_iterator_insert(struct no_os_iterator *iter, void *data,
bool after)
{
struct no_os_iterator *it = iter;
struct no_os_list_elem *elem;
struct no_os_list_desc list_desc;
if (!it)
return -1;
list_desc.priv_desc = iter->list;
if (after && it->elem == it->list->last)
return no_os_list_add_last(&list_desc, data);
if (!after && it->elem == it->list->first)
return no_os_list_add_first(&list_desc, data);
if (after)
elem = create_element(data, it->elem, it->elem->next);
else
elem = create_element(data, it->elem->prev, it->elem);
if (!elem)
return -1;
no_os_update_links(elem->prev, elem, elem->next);
it->list->nb_elements++;
return 0;
}
@@ -0,0 +1,309 @@
/***************************************************************************//**
* @file no_os_list.h
* @brief List library header
* @author Mihail Chindris (mihail.chindris@analog.com)
********************************************************************************
* @copyright
* Copyright 2020(c) Analog Devices, Inc.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* 3. Neither the name of Analog Devices, Inc. nor the names of its
* contributors may be used to endorse or promote products derived from this
* software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY ANALOG DEVICES, INC. “AS IS” AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
* EVENT SHALL ANALOG DEVICES, INC. BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
* OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
* EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
********************************************************************************
*
* @section list_details Library description
* This library handles double linked lists and it expose inseart,
* read, get and delete functions. \n
* It also can be accesed using it member functions which wrapp function for
* usual list types.\n
* @subsection example Sample code
* @code{.c}
* // -- Use a generic list
* struct no_os_list_desc *list1;
* struct no_os_iterator *it;
* uint32_t a;
* // Create list list1
* no_os_list_init(&list1, NO_OS_LIST_DEFAULT, NULL);
* // Add items to the list
* no_os_list_add_last(list1, 1);
* no_os_list_add_last(list1, 2);
* no_os_list_add_last(list1, 3);
* // Here the list will be: 1 -> 2 - > 3
*
* no_os_list_read_last(list1, &a);
* printf("Last: %d\n", a);
* // 3 will be printed
* // Create an iterator on the end of the list
* no_os_iterator_init(&it, list1, 0);
* // Move the iterator backword with one position
* no_os_iterator_move(it, -1);
* // Read the data at the current position
* no_os_iterator_read(it, &a);
* printf("Current: %d\n", a);
* // 2 will be printed
* no_os_iterator_remove(it);
* no_os_list_remove(list1);
*
* // -- Use a popular list
* struct no_os_list_desc *stack;
* // Create a FIFO list
* no_os_list_init(&stack, NO_OS_LIST_STACK, NULL);
* // Put elements in the list
* stack->push(stack, 1);
* stack->push(stack, 2);
* stack->push(stack, 3);
* // Read from the stack
* stack->pop(stack, &a);
* printf("Last: %d\n", a);
* // 3 will be printed
* no_os_list_remove(stack);
* @endcode
*******************************************************************************/
#ifndef _NO_OS_LIST_H_
#define _NO_OS_LIST_H_
#include <stdint.h>
#include <stdbool.h>
/**
* @struct no_os_list_desc
* @brief Structure storing the list and function wrapper for usual list types
*
* With this structure the funtionalities of usual list types
* ( \ref no_os_adapter_type ) can be accesed with the functions referenced in this
* structure.
* For example:
* @code{.c}
* my_queue->push(my_queue, my_data);
* @endcode
*/
struct no_os_list_desc;
/**
* @struct list_iterator
* @brief Structure used to iterate through the list using Iterator functions.
*/
struct no_os_iterator;
/**
* @brief Prototype of the compare function.
*
* The function used to compare the elements of the liste when doing
* operations on an ordered list.
* @param data1 - First element to be compared
* @param data2 - Second element to be compared
* @return
* - -1 - If data1 < data2
* - 0 - If data1 == data2
* - 1 - If data1 > data2
*/
typedef int32_t (*f_cmp)(void *data1, void *data2);
/**
* @name Generic functions
* Each function interacting with the list have one of the following formats.\n
* Aditionaly they may have one more parametere for specific functionalities.\n
* In the Iterator functions, the list reference is replaced by the iterator's
* one.
* @{
*/
/**
* @brief Add an element in the list.
*
* The element of the list is created and the data field is stored in it.
* @param list_desc - Reference to the list. Created by \ref no_os_list_init.
* @param data - Data to store in a list element
* @return
* - 0 : On success
* - -1 : Otherwise
*/
typedef int32_t (*f_add)(struct no_os_list_desc *list_desc, void *data);
/**
* @brief Edit an element in the list. The content is replaced by new_data.
* @param list_desc - Reference to the list. Created by \ref no_os_list_init.
* @param new_data - New data to replace the old one
* @return
* - 0 : On success
* - -1 : Otherwise
*/
typedef int32_t (*f_edit)(struct no_os_list_desc *list_desc, void *new_data);
/**
* @brief Read an element from the list.
* @param list_desc - Reference to the list. Created by \ref no_os_list_init.
* @param result - If not null, result is filled with:
* @param data - Content of the list element, NULL if some error occur.
* @return \n
* - 0 : On success
* - -1 : Otherwise
* @note If the content of an element can be 0 then the result must be checked
* to see if the functions has succeded
*/
typedef int32_t (*f_read)(struct no_os_list_desc *list_desc, void **data);
/**
* @brief Read and remove an element from the list.
* @param list_desc - Reference to the list. Created by \ref no_os_list_init.
* @param result - If not null, result is filled with:
* @param data - Content of the list element, NULL if some error occur.
* @return
* - 0 : On success
* - -1 : Otherwise
*/
typedef int32_t (*f_get)(struct no_os_list_desc *list_desc, void **data);
/** @} */
/**
* @enum no_os_adapter_type
* @brief Selects functionalities for functions in \ref no_os_list_desc
*/
enum no_os_adapter_type {
/** Default type is NO_OS_LIST_STACK */
NO_OS_LIST_DEFAULT,
/**
* Functions for a FIFO list (First-in first-out). Elements are inserted
* in one end and extracted from the other end.
* - \e Push: Insert element
* - \e Pop: Get next element (Read and remove)
* - \e Top_next: Read next element
* - \e Back: Read first element
* - \e Swap: Edit the content of the next element
*/
NO_OS_LIST_QUEUE,
/**
* Functions for a LIFO list (Last-in first-out). Elements are inserted
* and extracted only from the same end.
* - \e Push: Insert element
* - \e Pop: Get top element (Read and remove)
* - \e Top_next: Read top element
* - \e Back: Read bottom element
* - \e Swap: Edit the content of the top element
*/
NO_OS_LIST_STACK,
/**
* Functions for ordered list. The order of element is determinated
* usinge the \ref f_cmp.
* - \e Push: Insert element
* - \e Pop: Get lowest element (Read and remove)
* - \e Top_next: Read lowest element
* - \e Back: Read the biggest element
* - \e Swap: Edit the lowest element
*/
NO_OS_LIST_PRIORITY_LIST
};
struct no_os_list_desc {
/** Refer to \ref no_os_adapter_type */
f_add push;
/** Refer to \ref no_os_adapter_type */
f_get pop;
/** Refer to \ref no_os_adapter_type */
f_read top_next;
/** Refer to \ref no_os_adapter_type */
f_read back;
/** Refer to \ref no_os_adapter_type */
f_edit swap;
/** Structure storing the list internal parameters */
void *priv_desc;
};
int32_t no_os_list_init(struct no_os_list_desc **list_desc,
enum no_os_adapter_type type,
f_cmp comparator);
int32_t no_os_list_remove(struct no_os_list_desc *list_desc);
int32_t no_os_list_get_size(struct no_os_list_desc *list_desc,
uint32_t *out_size);
/**
* @name Iterator functions
* An iterator is used to iterate through the list. For a list, any number of
* iterators can be created. All must be removed before removing a list.
* @{
*/
int32_t no_os_iterator_init(struct no_os_iterator **iter,
struct no_os_list_desc *list_desc,
bool start);
int32_t no_os_iterator_remove(struct no_os_iterator *iter);
int32_t no_os_iterator_move(struct no_os_iterator *iter, int32_t steps);
int32_t no_os_iterator_move_to_idx(struct no_os_iterator *iter, int32_t idx);
int32_t no_os_iterator_find(struct no_os_iterator *iter, void *cmp_data);
int32_t no_os_iterator_insert(struct no_os_iterator *iter, void *data,
bool after);
int32_t no_os_iterator_edit(struct no_os_iterator *iter, void *new_data);
int32_t no_os_iterator_read(struct no_os_iterator *iter, void **data);
int32_t no_os_iterator_get(struct no_os_iterator *iter, void **data);
/** @}*/
/**
* @name Operations on the ends of the list
* These functions will operate on the first or last element of the list
* @{
*/
int32_t no_os_list_add_first(struct no_os_list_desc *list_desc, void *data);
int32_t no_os_list_edit_first(struct no_os_list_desc *list_desc,
void *new_data);
int32_t no_os_list_read_first(struct no_os_list_desc *list_desc, void **data);
int32_t no_os_list_get_first(struct no_os_list_desc *list_desc, void **data);
int32_t no_os_list_add_last(struct no_os_list_desc *list_desc, void *data);
int32_t no_os_list_edit_last(struct no_os_list_desc *list_desc, void *new_data);
int32_t no_os_list_read_last(struct no_os_list_desc *list_desc, void **data);
int32_t no_os_list_get_last(struct no_os_list_desc *list_desc, void **data);
/** @}*/
/**
* @name Operations by index
* These functions use an index to identify the element in the list.
* @{
*/
int32_t no_os_list_add_idx(struct no_os_list_desc *list_desc, void *data,
uint32_t idx);
int32_t no_os_list_edit_idx(struct no_os_list_desc *list_desc, void *new_data,
uint32_t idx);
int32_t no_os_list_read_idx(struct no_os_list_desc *list_desc, void **data,
uint32_t idx);
int32_t no_os_list_get_idx(struct no_os_list_desc *list_desc, void **data,
uint32_t idx);
/** @}*/
/**
* @name Operations by comparation
* These functions use the specified \ref f_cmp at \ref no_os_list_init to identify
* the element this will operate on.
* @{
*/
int32_t no_os_list_add_find(struct no_os_list_desc *list_desc, void *data);
int32_t no_os_list_edit_find(struct no_os_list_desc *list_desc, void *new_data,
void *cmp_data);
int32_t no_os_list_read_find(struct no_os_list_desc *list_desc, void **data,
void *cmp_data);
int32_t no_os_list_get_find(struct no_os_list_desc *list_desc, void **data,
void *cmp_data);
/** @}*/
#endif // _NO_OS_LIST_H_
@@ -0,0 +1,119 @@
/***************************************************************************//**
* @file no_os_mdio.c
* @brief Source file for MDIO interface driver.
* @author Darius Berghe (darius.berghe@analog.com)
********************************************************************************
* Copyright 2023(c) Analog Devices, Inc.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* 3. Neither the name of Analog Devices, Inc. nor the names of its
* contributors may be used to endorse or promote products derived from this
* software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY ANALOG DEVICES, INC. “AS IS” AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
* EVENT SHALL ANALOG DEVICES, INC. BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
* OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
* EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*******************************************************************************/
#include <errno.h>
#include "no_os_mdio.h"
/**
* @brief Initialize the MDIO interface.
* @param desc - The MDIO descriptor.
* @param param - MDIO parameters.
* @return 0 in case of success, error code otherwise.
*/
int no_os_mdio_init(struct no_os_mdio_desc **desc,
struct no_os_mdio_init_param *param)
{
int ret;
if (!param || !param->ops)
return -EINVAL;
if (!param->ops->init)
return -ENOSYS;
ret = param->ops->init(desc, param);
if (ret)
return ret;
(*desc)->id = param->id;
(*desc)->c45 = param->c45;
(*desc)->addr = param->addr;
(*desc)->ops = param->ops;
return 0;
}
/**
* @brief Free the resources allocated by no_os_mdio_init().
* @param desc - The MDIO descriptor.
* @return 0 in case of success, error code otherwise.
*/
int no_os_mdio_remove(struct no_os_mdio_desc *desc)
{
if (!desc || !desc->ops)
return -EINVAL;
if (!desc->ops->remove)
return -ENOSYS;
return desc->ops->remove(desc);
}
/**
* @brief Write a register using MDIO.
* @param desc - The MDIO descriptor.
* @param reg - Register address.
* For clause 45 reg is constructed using NO_OS_MDIO_C45_ADDR macro.
* It is otherwise the plain clause 22 address (0...31).
* @param val - Value to write into register.
* @return 0 in case of success, error code otherwise.
*/
int no_os_mdio_write(struct no_os_mdio_desc *desc, uint32_t reg, uint16_t val)
{
if (!desc || !desc->ops)
return -EINVAL;
if (!desc->ops->write)
return -ENOSYS;
return desc->ops->write(desc, reg, val);
}
/**
* @brief Read a register using MDIO.
* @param desc - The MDIO descriptor.
* @param reg - Register address.
* For clause 45 reg is constructed using NO_OS_MDIO_C45_ADDR macro.
* It is otherwise the plain clause 22 address (0...31).
* @param val - Value read from register.
* @return 0 in case of success, error code otherwise.
*/
int no_os_mdio_read(struct no_os_mdio_desc *desc, uint32_t reg, uint16_t *val)
{
if (!desc || !desc->ops)
return -EINVAL;
if (!desc->ops->read)
return -ENOSYS;
return desc->ops->read(desc, reg, val);
}
@@ -0,0 +1,107 @@
/***************************************************************************//**
* @file no_os_mdio.h
* @brief Header file for MDIO interface driver.
* @author Darius Berghe (darius.berghe@analog.com)
********************************************************************************
* Copyright 2023(c) Analog Devices, Inc.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* 3. Neither the name of Analog Devices, Inc. nor the names of its
* contributors may be used to endorse or promote products derived from this
* software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY ANALOG DEVICES, INC. “AS IS” AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
* EVENT SHALL ANALOG DEVICES, INC. BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
* OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
* EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*******************************************************************************/
#ifndef _NO_OS_MDIO_H_
#define _NO_OS_MDIO_H_
#include <stdbool.h>
#include <stdint.h>
#include "no_os_util.h"
#define NO_OS_MDIO_C22_REGS 32
#define NO_OS_MDIO_C45_START 0
#define NO_OS_MDIO_C22_START 1
#define NO_OS_MDIO_START_MASK NO_OS_GENMASK(31, 30)
#define NO_OS_MDIO_OP_ADDRESS 0
#define NO_OS_MDIO_OP_WRITE 1
#define NO_OS_MDIO_OP_READ 2
#define NO_OS_MDIO_OP_MASK NO_OS_GENMASK(29, 28)
#define NO_OS_MDIO_PHYADDR_MASK NO_OS_GENMASK(27, 23)
#define NO_OS_MDIO_REGADDR_MASK NO_OS_GENMASK(22, 18)
#define NO_OS_MDIO_TURNAROUND 2
#define NO_OS_MDIO_TURNAROUND_MASK NO_OS_GENMASK(17, 16)
#define NO_OS_MDIO_DATA_MASK NO_OS_GENMASK(15, 0)
#define NO_OS_MDIO_C45_DEVADDR_MASK NO_OS_GENMASK(20, 16)
#define NO_OS_MDIO_C45_ADDR(dev, reg) (NO_OS_BIT(31) | no_os_field_prep(NO_OS_MDIO_C45_DEVADDR_MASK, dev) | (uint16_t)reg)
/**
* @struct no_os_mdio_init_param
* @brief Parameters for an MDIO slave.
*/
struct no_os_mdio_init_param {
/** Device ID (when using MDIO peripheral), optional. */
int id;
/** Specifies if clause 45 frame format is supported by the slave,
* otherwise clause 22 frame format is used. */
bool c45;
/** MDIO slave address on the bus. */
uint8_t addr;
/** Specific implementations of the API. */
struct no_os_mdio_ops *ops;
/** Platform or implementation specific parameters. */
void *extra;
};
/**
* @struct no_os_mdio_desc
* @brief MDIO device descriptor created with no_os_mdio_init().
*/
struct no_os_mdio_desc {
int id;
bool c45;
uint8_t addr;
struct no_os_mdio_ops *ops;
void *extra;
};
/**
* @struct no_os_mdio_ops
* @brief Collection of MDIO ops that point to specific implementations.
*/
struct no_os_mdio_ops {
/** MDIO initialization op */
int (*init)(struct no_os_mdio_desc **, struct no_os_mdio_init_param *);
/** MDIO write register op */
int (*write)(struct no_os_mdio_desc *, uint32_t, uint16_t);
/** MDIO read register op */
int (*read)(struct no_os_mdio_desc *, uint32_t, uint16_t *);
/** MDIO remove op */
int (*remove)(struct no_os_mdio_desc *);
};
int no_os_mdio_init(struct no_os_mdio_desc **desc,
struct no_os_mdio_init_param *param);
int no_os_mdio_remove(struct no_os_mdio_desc *desc);
int no_os_mdio_write(struct no_os_mdio_desc *desc, uint32_t reg, uint16_t val);
int no_os_mdio_read(struct no_os_mdio_desc *desc, uint32_t reg, uint16_t *val);
#endif
@@ -0,0 +1,63 @@
/*******************************************************************************
* @file util/no_os_mutex.c
* @brief Implementation of no-OS mutex funtionality.
* @author Robert Budai (robert.budai@analog.com)
********************************************************************************
* Copyright 2023(c) Analog Devices, Inc.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* 3. Neither the name of Analog Devices, Inc. nor the names of its
* contributors may be used to endorse or promote products derived from this
* software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY ANALOG DEVICES, INC. “AS IS” AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
* EVENT SHALL ANALOG DEVICES, INC. BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
* OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
* EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*******************************************************************************/
#include "no_os_mutex.h"
/**
* @brief Initialize mutex.
* @param ptr - Pointer toward the mutex.
* @return None.
*/
__attribute__((weak)) void no_os_mutex_init(void **mutex) {}
/**
* @brief Lock mutex.
* @param ptr - Pointer toward the mutex.
* @return None.
*/
__attribute__((weak)) void no_os_mutex_lock(void *mutex) {}
/**
* @brief Unlock mutex.
* @param ptr - Pointer toward the mutex.
* @return None.
*/
__attribute((weak)) void no_os_mutex_unlock(void *mutex) {}
/**
* @brief Remove mutex.
* @param ptr - Pointer toward the mutex.
* @return None.
*/
__attribute__((weak)) void no_os_mutex_remove(void *mutex) {}
@@ -0,0 +1,78 @@
/*******************************************************************************
* @file no_os_mutex.h
* @brief Header file of mutex implementation.
* @author Robert Budai (robert.budai@analog.com)
********************************************************************************
* Copyright 2023(c) Analog Devices, Inc.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* 3. Neither the name of Analog Devices, Inc. nor the names of its
* contributors may be used to endorse or promote products derived from this
* software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY ANALOG DEVICES, INC. “AS IS” AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
* EVENT SHALL ANALOG DEVICES, INC. BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
* OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
* EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*******************************************************************************/
#ifndef _NO_OS_MUTEX_H_
#define _NO_OS_MUTEX_H_
/**
* @brief Function for no-os mutex initialization and thread safety.
* This function is implemented based on different platforms/OS libraries
* that NO-OS supports. These mutex functions are used for thread safety
* of peripherals. Since these functions don't return error values it is
* the developers responsibility to implement the safety checks in case
* new mutex implementation is being added, like the following:
*
* if ((*mutex) == NULL)
* {
* //code to initialize the mutex
* }
*
* Also these check are responsible not to allocate different mutexes
* for the same peripheral descriptor.
*/
void no_os_mutex_init(void **mutex);
/**
* @brief Function for locking mutex
*/
void no_os_mutex_lock(void *mutex);
/**
* @brief Function for unlocking mutex
*/
void no_os_mutex_unlock(void *mutex);
/**
* @brief Function for removing the initialized mutex.
* This function is responsible to remove the allocated mutex. This function is
* also used by the peripherals mutex thread safety feature and in case
* new mutex implementation is going to be added, it is the developers
* responsibility to add extra check inside the function while de-allocating the memory.
*
* if (mutex != NULL)
* {
* //code to de-allocate mutex
* }
*/
void no_os_mutex_remove(void *mutex);
#endif // _NO_OS_MUTEX_H_
@@ -0,0 +1,202 @@
/***************************************************************************//**
* @file no_os_pid.c
* @brief Source file for PID control utility.
* @author Darius Berghe (darius.berghe@analog.com)
********************************************************************************
* Copyright 2023(c) Analog Devices, Inc.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* 3. Neither the name of Analog Devices, Inc. nor the names of its
* contributors may be used to endorse or promote products derived from this
* software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY ANALOG DEVICES, INC. “AS IS” AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
* EVENT SHALL ANALOG DEVICES, INC. BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
* OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
* EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*******************************************************************************/
#include <errno.h>
#include "no_os_pid.h"
#include "no_os_alloc.h"
#include "no_os_print_log.h"
struct no_os_pid {
int iacc; // integral accumulator
int dacc; // derivative accumulator
int64_t output; // on 64-bits to avoid overflow
struct no_os_pid_config config; // copy of the user-provided configuration
};
/**
* @brief Initialize a PID controller with given configuration
* @param pid - Double pointer to a PID descriptor that the function allocates
* @param config - PID configuration structure
* @return
* - 0 : On success
* - -EINVAL : Invalid input
* - -ENOMEM : Memory allocation failure
*/
int no_os_pid_init(struct no_os_pid **pid, struct no_os_pid_config config)
{
if (!pid)
return -EINVAL;
if (config.output_clip.high < config.output_clip.low)
return -EINVAL;
*pid = no_os_calloc(1, sizeof(**pid));
if (!*pid)
return -ENOMEM;
(*pid)->config = config;
(*pid)->output = config.initial;
(*pid)->iacc = 0;
(*pid)->dacc = 0;
return 0;
}
/**
* @brief Perform PID control given a controller, a set-point and a process variable.
* @param pid - PID descriptor created with no_os_pid_init()
* @param SP - Set-point
* @param PV - Process variable
* @param output - The output of the PID control
* @return
* - 0 : On success
* - -EINVAL : Invalid input
*/
int no_os_pid_control(struct no_os_pid *pid, int SP, int PV, int *output)
{
int err; // error
int64_t p; // proportional component
int64_t i; // integral component
int64_t d; // derivative component
struct no_os_pid_range *i_clip;
struct no_os_pid_range *output_clip;
if (!pid || !output)
return -EINVAL;
i_clip = &pid->config.i_clip;
output_clip = &pid->config.output_clip;
// error is the difference between the set point and process variable
err = SP - PV;
// don't control (maintain output) if within hysteresis range
if (abs(err) < pid->config.hysteresis) {
pr_debug("SP: %d PV: %d --> output: %lu for err=%d\n", SP, PV, pid->output,
err);
goto end;
}
// compute proportional component
p = (int64_t)pid->config.Kp * err;
// clip integrator accumulator if enabled and if needed
if (i_clip->high > i_clip->low) {
if (pid->iacc > i_clip->high)
pid->iacc = i_clip->high;
else if (pid->iacc < i_clip->low)
pid->iacc = i_clip->low;
}
// compute integral component
i = (int64_t)pid->config.Ki * pid->iacc;
// compute the derivative component
d = (int64_t)pid->config.Kd * (pid->dacc - err);
// compute the output
pid->output = (pid->output * 1000000 - (p + i + d)) / 1000000;
pr_debug("SP: %d PV: %d --> output: %ld for p %ld i %ld d %ld err=%d\n", SP, PV,
pid->output, p, i, d, err);
// clip the output if enabled and if needed
if (output_clip->high > output_clip->low) {
if (pid->output > output_clip->high)
pid->output = output_clip->high;
else if (pid->output < output_clip->low)
pid->output = output_clip->low;
}
// keep track of error history in the integrator accumulator
pid->iacc += err;
// keep track of process variable change rate in the derivative accumulator
pid->dacc = err;
end:
*output = pid->output;
return 0;
}
/**
* @brief Change the hysteresis.
* @param pid - PID descriptor created with no_os_pid_init()
* @param hyst - The new hysteresis value
* @return
* - 0 : On success
* - -EINVAL : Invalid input
*/
int no_os_pid_hysteresis(struct no_os_pid *pid, unsigned int hyst)
{
if (!pid)
return -EINVAL;
pid->config.hysteresis = hyst;
return 0;
}
/**
* @brief Reset internal accumulators, useful when the same pid descriptor is used to start over.
* @param pid - PID descriptor created with no_os_pid_init()
* @return
* - 0 : On success
* - -EINVAL : Invalid input
*/
int no_os_pid_reset(struct no_os_pid *pid)
{
if (!pid)
return -EINVAL;
pid->iacc = 0;
pid->dacc = 0;
return 0;
}
/**
* @brief De-initialize a PID controller by freeing the allocated memory
* @param pid - PID descriptor created with no_os_pid_init()
* @return
* - 0 : On success
* - -EINVAL : Invalid input
*/
int no_os_pid_remove(struct no_os_pid *pid)
{
if (!pid)
return -EINVAL;
no_os_free(pid);
pid = NULL;
return 0;
}
@@ -0,0 +1,79 @@
/***************************************************************************//**
* @file no_os_pid.h
* @brief Header file for PID control utility.
* @author Darius Berghe (darius.berghe@analog.com)
********************************************************************************
* Copyright 2023(c) Analog Devices, Inc.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* 3. Neither the name of Analog Devices, Inc. nor the names of its
* contributors may be used to endorse or promote products derived from this
* software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY ANALOG DEVICES, INC. “AS IS” AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
* EVENT SHALL ANALOG DEVICES, INC. BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
* OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
* EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*******************************************************************************/
#ifndef _NO_OS_PID_H
#define _NO_OS_PID_H
#include <stdlib.h>
#include <stdio.h>
#include <stdint.h>
/**
* @struct no_os_pid_range
* @brief Range definition for limiting PID control output or internal integrator accumulator
*/
struct no_os_pid_range {
/* High limit of the range */
int high;
/** Low limit of the range */
int low;
};
/**
* @struct no_os_pid_config
* @brief Configuration of the PID
*/
struct no_os_pid_config {
/** Proportional gain (micro-units) */
unsigned int Kp;
/** Integral gain (micro-units) */
unsigned int Ki;
/** Derivative gain (micro-units) */
unsigned int Kd;
/** (Optional) Control supressed when process variable is within set point +/- hysteresis */
unsigned int hysteresis;
/** (Optional) Boundary limits for integral component */
struct no_os_pid_range i_clip;
/** (Optional) Boundary limits for the output (for example, for an 8-bit controlled PWM, one would clip the output to 0-255 range) */
struct no_os_pid_range output_clip;
/** (Optional) Initial output */
int initial;
};
struct no_os_pid;
int no_os_pid_init(struct no_os_pid **pid, struct no_os_pid_config config);
int no_os_pid_control(struct no_os_pid *pid, int SP, int PV, int *output);
int no_os_pid_hysteresis(struct no_os_pid *pid, unsigned int hyst);
int no_os_pid_reset(struct no_os_pid *pid);
int no_os_pid_remove(struct no_os_pid *pid);
#endif
@@ -0,0 +1,132 @@
/***************************************************************************//**
* @file no_os_print_log.h
* @brief Print messages helpers.
* @author Antoniu Miclaus (antoniu.miclaus@analog.com)
********************************************************************************
* Copyright 2020(c) Analog Devices, Inc.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* 3. Neither the name of Analog Devices, Inc. nor the names of its
* contributors may be used to endorse or promote products derived from this
* software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY ANALOG DEVICES, INC. “AS IS” AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
* EVENT SHALL ANALOG DEVICES, INC. BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
* OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
* EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*******************************************************************************/
#ifndef _NO_OS_PRINT_LOG_H_
#define _NO_OS_PRINT_LOG_H_
#include <stdio.h>
#define NO_OS_LOG_EMERG 0x0
#define NO_OS_LOG_ALERT 0x1
#define NO_OS_LOG_CRIT 0x2
#define NO_OS_LOG_ERR 0x3
#define NO_OS_LOG_WARNING 0x4
#define NO_OS_LOG_NOTICE 0x5
#define NO_OS_LOG_INFO 0x6
#define NO_OS_LOG_DEBUG 0x7
#ifndef NO_OS_LOG_LEVEL
#define NO_OS_LOG_LEVEL NO_OS_LOG_INFO
#endif
#if defined(PRINT_TIME)
#define pr_time { struct no_os_time _t = no_os_get_time(); \
printf("[%5d.%06d] ", _t.s, _t.us); \
}
#else
#define pr_time ;
#endif
#if defined(NO_OS_LOG_LEVEL) && NO_OS_LOG_LEVEL >= NO_OS_LOG_EMERG && NO_OS_LOG_LEVEL <= NO_OS_LOG_DEBUG
#define pr_emerg(fmt, args...) do { \
pr_time \
printf("EMERG: %s:%d:%s(): " fmt, __FILE__, __LINE__, __func__, ##args); \
} while (0)
#else
#define pr_emerg(fmt, args...)
#endif
#if defined(NO_OS_LOG_LEVEL) && NO_OS_LOG_LEVEL >= NO_OS_LOG_ALERT && NO_OS_LOG_LEVEL <= NO_OS_LOG_DEBUG
#define pr_alert(fmt, args...) do { \
pr_time \
printf("ALERT: %s:%d:%s(): " fmt, __FILE__, __LINE__, __func__, ##args); \
} while (0)
#else
#define pr_alert(fmt, args...)
#endif
#if defined(NO_OS_LOG_LEVEL) && NO_OS_LOG_LEVEL >= NO_OS_LOG_CRIT && NO_OS_LOG_LEVEL <= NO_OS_LOG_DEBUG
#define pr_crit(fmt, args...) do { \
pr_time \
printf("CRIT: %s:%d:%s(): " fmt, __FILE__, __LINE__, __func__, ##args); \
} while (0)
#else
#define pr_crit(fmt, args...)
#endif
#if defined(NO_OS_LOG_LEVEL) && NO_OS_LOG_LEVEL >= NO_OS_LOG_ERR && NO_OS_LOG_LEVEL <= NO_OS_LOG_DEBUG
#define pr_err(fmt, args...) do { \
pr_time \
printf("ERR: %s:%d:%s(): " fmt, __FILE__, __LINE__, __func__, ##args); \
} while (0)
#else
#define pr_err(fmt, args...)
#endif
#if defined(NO_OS_LOG_LEVEL) && NO_OS_LOG_LEVEL >= NO_OS_LOG_WARNING && NO_OS_LOG_LEVEL <= NO_OS_LOG_DEBUG
#define pr_warning(fmt, args...) do { \
pr_time \
printf("WARNING: " fmt, ##args); \
} while (0)
#else
#define pr_warning(fmt, args...)
#endif
#if defined(NO_OS_LOG_LEVEL) && NO_OS_LOG_LEVEL >= NO_OS_LOG_NOTICE && NO_OS_LOG_LEVEL <= NO_OS_LOG_DEBUG
#define pr_notice(fmt, args...) do { \
pr_time \
printf("NOTICE: " fmt, ##args); \
} while (0)
#else
#define pr_notice(fmt, args...)
#endif
#if defined(NO_OS_LOG_LEVEL) && NO_OS_LOG_LEVEL >= NO_OS_LOG_INFO && NO_OS_LOG_LEVEL <= NO_OS_LOG_DEBUG
#define pr_info(fmt, args...) do { \
pr_time \
printf(fmt, ##args); \
} while(0)
#else
#define pr_info(fmt, args...)
#endif
#if defined(NO_OS_LOG_LEVEL) && NO_OS_LOG_LEVEL == NO_OS_LOG_DEBUG
#define pr_debug(fmt, args...) do { \
pr_time \
printf("DEBUG: " fmt, ##args); \
} while(0)
#else
#define pr_debug(fmt, args...)
#endif
#endif // _NO_OS_PRINT_LOG_H_
@@ -0,0 +1,273 @@
/***************************************************************************//**
* @file no_os_pwm.c
* @brief Implementation of the PWM Interface
* @author Pratyush Mallick (pratyush.mallick@analog.com)
********************************************************************************
* Copyright 2023(c) Analog Devices, Inc.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* 3. Neither the name of Analog Devices, Inc. nor the names of its
* contributors may be used to endorse or promote products derived from this
* software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY ANALOG DEVICES, INC. “AS IS” AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
* EVENT SHALL ANALOG DEVICES, INC. BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
* OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
* EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*******************************************************************************/
#include <inttypes.h>
#include "no_os_pwm.h"
#include <stdlib.h>
#include "no_os_error.h"
#include "no_os_mutex.h"
/**
* @brief - PWM mutex
*/
static void *pwm_mutex_table[PWM_MAX_NUMBER + 1];
/**
* @brief Initialize the PWM peripheral.
* @param desc - The PWM descriptor.
* @param param - The structure that contains the PWM parameters.
* @return 0 in case of success, -1 otherwise.
*/
int32_t no_os_pwm_init(struct no_os_pwm_desc **desc,
const struct no_os_pwm_init_param *param)
{
int32_t ret;
if (!param || !param->platform_ops)
return -EINVAL;
if (!param->platform_ops->pwm_ops_init)
return -ENOSYS;
ret = param->platform_ops->pwm_ops_init(desc, param);
if (ret)
return ret;
(*desc)->platform_ops = param->platform_ops;
no_os_mutex_init(&pwm_mutex_table[param->id]);
(*desc)->mutex = pwm_mutex_table[param->id];
return 0;
}
/**
* @brief Free the resources allocated by no_os_pwm_init().
* @param desc - The PWM descriptor.
* @return 0 in case of success, -1 otherwise.
*/
int32_t no_os_pwm_remove(struct no_os_pwm_desc *desc)
{
if (!desc || !desc->platform_ops)
return -EINVAL;
if (!desc->platform_ops->pwm_ops_remove)
return -ENOSYS;
no_os_mutex_remove(desc->mutex);
pwm_mutex_table[desc->id] = NULL;
return desc->platform_ops->pwm_ops_remove(desc);
}
/**
* @brief Enable PWM signal generation.
* @param desc - The PWM descriptor.
* @return 0 in case of success, -1 otherwise.
*/
int32_t no_os_pwm_enable(struct no_os_pwm_desc *desc)
{
if (!desc || !desc->platform_ops)
return -EINVAL;
if (!desc->platform_ops->pwm_ops_enable)
return -ENOSYS;
no_os_mutex_lock(desc->mutex);
return desc->platform_ops->pwm_ops_enable(desc);
}
/**
* @brief Disable PWM signal generation.
* @param desc - The PWM descriptor.
* @return 0 in case of success, -1 otherwise.
*/
int32_t no_os_pwm_disable(struct no_os_pwm_desc *desc)
{
if (!desc || !desc->platform_ops)
return -EINVAL;
if (!desc->platform_ops->pwm_ops_disable)
return -ENOSYS;
no_os_mutex_unlock(desc->mutex);
return desc->platform_ops->pwm_ops_disable(desc);
}
/**
* @brief Set the PWM period value.
* @param desc - The PWM descriptor.
* @param period_ns - The period value in nanoseconds.
* @return 0 in case of success, -1 otherwise.
*/
int32_t no_os_pwm_set_period(struct no_os_pwm_desc *desc,
uint32_t period_ns)
{
if (!desc || !desc->platform_ops)
return -EINVAL;
if (!desc->platform_ops->pwm_ops_set_period)
return -ENOSYS;
return desc->platform_ops->pwm_ops_set_period(desc, period_ns);
}
/**
* @brief Get the PWM period value.
* @param desc - The PWM descriptor.
* @param period_ns - The period value in nanoseconds.
* @return 0 in case of success, -1 otherwise.
*/
int32_t no_os_pwm_get_period(struct no_os_pwm_desc *desc,
uint32_t *period_ns)
{
if (!desc || !desc->platform_ops)
return -EINVAL;
if (!desc->platform_ops->pwm_ops_get_period)
return -ENOSYS;
return desc->platform_ops->pwm_ops_get_period(desc, period_ns);
}
/**
* @brief Set the PWM duty cycle.
* @param desc - The PWM descriptor.
* @param duty_cycle_ns - Duty cycle in nanoseconds.
* @return 0 in case of success, -1 otherwise.
*/
int32_t no_os_pwm_set_duty_cycle(struct no_os_pwm_desc *desc,
uint32_t duty_cycle_ns)
{
if (!desc || !desc->platform_ops)
return -EINVAL;
if (!desc->platform_ops->pwm_ops_set_duty_cycle)
return -ENOSYS;
return desc->platform_ops->pwm_ops_set_duty_cycle(desc, duty_cycle_ns);
}
/**
* @brief Get the PWM duty cycle.
* @param desc - The PWM descriptor.
* @param duty_cycle_ns - Duty cycle in nanoseconds.
* @return 0 in case of success, -1 otherwise.
*/
int32_t no_os_pwm_get_duty_cycle(struct no_os_pwm_desc *desc,
uint32_t *duty_cycle_ns)
{
if (!desc || !desc->platform_ops)
return -EINVAL;
if (!desc->platform_ops->pwm_ops_get_duty_cycle)
return -ENOSYS;
return desc->platform_ops->pwm_ops_get_duty_cycle(desc, duty_cycle_ns);
}
/**
* @brief Set the PWM phase value.
* @param desc - The PWM descriptor.
* @param phase_ns - Phase value in nanoseconds.
* @return 0 in case of success, -1 otherwise.
*/
int32_t no_os_pwm_set_phase(struct no_os_pwm_desc *desc,
uint32_t phase_ns)
{
if (!desc || !desc->platform_ops)
return -EINVAL;
if (!desc->platform_ops->pwm_ops_set_phase)
return -ENOSYS;
return desc->platform_ops->pwm_ops_set_phase(desc, phase_ns);
}
/**
* @brief Get the PWM phase value.
* @param desc - The PWM descriptor.
* @param phase_ns - Phase value in nanoseconds.
* @return 0 in case of success, -1 otherwise.
*/
int32_t no_os_pwm_get_phase(struct no_os_pwm_desc *desc,
uint32_t *phase_ns)
{
if (!desc || !desc->platform_ops)
return -EINVAL;
if (!desc->platform_ops->pwm_ops_get_phase)
return -ENOSYS;
return desc->platform_ops->pwm_ops_get_phase(desc, phase_ns);
}
/**
* @brief Set the PWM polarity.
* @param desc - The PWM descriptor.
* @param polarity - Polarity value.
* Example: NO_OS_PWM_POLARITY_HIGH
* NO_OS_PWM_POLARITY_LOW
* @return 0 in case of success, -1 otherwise.
*/
int32_t no_os_pwm_set_polarity(struct no_os_pwm_desc *desc,
enum no_os_pwm_polarity polarity)
{
if (!desc || !desc->platform_ops)
return -EINVAL;
if (!desc->platform_ops->pwm_ops_set_polarity)
return -ENOSYS;
return desc->platform_ops->pwm_ops_set_polarity(desc, polarity);
}
/**
* @brief Get the PWM polarity.
* @param desc - The PWM descriptor.
* @param polarity - Polarity value.
* Example: NO_OS_PWM_POLARITY_HIGH
* NO_OS_PWM_POLARITY_LOW
* @return 0 in case of success, -1 otherwise.
*/
int32_t no_os_pwm_get_polarity(struct no_os_pwm_desc *desc,
enum no_os_pwm_polarity *polarity)
{
if (!desc || !desc->platform_ops)
return -EINVAL;
if (!desc->platform_ops->pwm_ops_get_polarity)
return -ENOSYS;
return desc->platform_ops->pwm_ops_get_polarity(desc, polarity);
}
@@ -0,0 +1,190 @@
/***************************************************************************//**
* @file no_os_pwm.h
* @brief Header file of PWM Interface
* @author Cristian Pop (cristian.pop@analog.com)
********************************************************************************
* Copyright 2020(c) Analog Devices, Inc.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* 3. Neither the name of Analog Devices, Inc. nor the names of its
* contributors may be used to endorse or promote products derived from this
* software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY ANALOG DEVICES, INC. “AS IS” AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
* EVENT SHALL ANALOG DEVICES, INC. BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
* OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
* EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*******************************************************************************/
#ifndef _NO_OS_PWM_H_
#define _NO_OS_PWM_H_
#include <stdint.h>
#include <stdbool.h>
#define PWM_MAX_NUMBER 4
/**
* @enum no_os_pwm_polarity
* @brief Possible polarities of the PWM signal
*/
enum no_os_pwm_polarity {
/** PWM duty cycle is high, idle low */
NO_OS_PWM_POLARITY_HIGH,
/** PWM duty cycle is low, idle high */
NO_OS_PWM_POLARITY_LOW,
};
/**
* @struct no_os_pwm_init_param
* @brief Structure containing the init parameters needed by the PWM generator
*/
struct no_os_pwm_init_param {
/** Pwm id (Ex. Pin number, timer_id) */
uint32_t id;
/** PWM generator period */
uint32_t period_ns;
/** PWM generator duty cycle */
uint32_t duty_cycle_ns;
/** PWM generator phase */
uint32_t phase_ns;
/** PWM generator polarity */
enum no_os_pwm_polarity polarity;
/** PWM gpio pin init param*/
struct no_os_gpio_init_param *pwm_gpio;
/* IRQ ID */
uint32_t irq_id;
/** PWM callback **/
void (*pwm_callback)(void *arg);
/** PWM platform specific functions */
const struct no_os_pwm_platform_ops *platform_ops;
/** PWM extra parameters (device specific) */
void *extra;
};
/**
* @struct no_os_pwm_desc
* @brief Structure representing an PWM generator device
*/
struct no_os_pwm_desc {
/** PWM mutex*/
void *mutex;
/** Pwm id */
uint32_t id;
/** PWM generator period */
uint32_t period_ns;
/** PWM generator duty cycle */
uint32_t duty_cycle_ns;
/** PWM generator phase */
uint32_t phase_ns;
/** PWM generator polarity */
enum no_os_pwm_polarity polarity;
/** PWM generator enabled */
bool enabled;
/** PWM gpio pin instance */
struct no_os_gpio_desc *pwm_gpio;
/* IRQ ID */
uint32_t irq_id;
/** PWM callback **/
void (*pwm_callback)(void* arg);
/** PWM platform specific functions */
const struct no_os_pwm_platform_ops *platform_ops;
/** PWM extra parameters (device specific) */
void *extra;
};
/**
* @struct no_os_pwm_platform_ops
* @brief Structure holding PWM function pointers that point to the platform
* specific function
*/
struct no_os_pwm_platform_ops {
/** pwm initialization function pointer */
int32_t (*pwm_ops_init)(struct no_os_pwm_desc **,
const struct no_os_pwm_init_param *);
/** pwm enable function pointer */
int32_t (*pwm_ops_enable)(struct no_os_pwm_desc *);
/** pwm disable function pointer */
int32_t (*pwm_ops_disable)(struct no_os_pwm_desc *);
/** pwm set period function pointer */
int32_t (*pwm_ops_set_period)(struct no_os_pwm_desc *, uint32_t);
/** pwm get period function pointer */
int32_t (*pwm_ops_get_period)(struct no_os_pwm_desc *, uint32_t *);
/** pwm set duty cycle function pointer */
int32_t (*pwm_ops_set_duty_cycle)(struct no_os_pwm_desc *, uint32_t);
/** pwm get duty cycle function pointer */
int32_t (*pwm_ops_get_duty_cycle)(struct no_os_pwm_desc *, uint32_t *);
/** pwm set phase function pointer */
int32_t (*pwm_ops_set_phase)(struct no_os_pwm_desc *, uint32_t);
/** pwm get phase function pointer */
int32_t (*pwm_ops_get_phase)(struct no_os_pwm_desc *, uint32_t *);
/** pwm set polarity function pointer */
int32_t (*pwm_ops_set_polarity)(struct no_os_pwm_desc *,
enum no_os_pwm_polarity);
/** pwm get polarity function pointer */
int32_t (*pwm_ops_get_polarity)(struct no_os_pwm_desc *,
enum no_os_pwm_polarity *);
/** pwm remove function pointer */
int32_t(*pwm_ops_remove)(struct no_os_pwm_desc *);
};
/* Initialize the PWM generator device */
int32_t no_os_pwm_init(struct no_os_pwm_desc **desc,
const struct no_os_pwm_init_param *param);
/* Free the resources used by the PWM generator device */
int32_t no_os_pwm_remove(struct no_os_pwm_desc *desc);
/* Enable PWM generator device */
int32_t no_os_pwm_enable(struct no_os_pwm_desc *desc);
/* Disable PWM generator device */
int32_t no_os_pwm_disable(struct no_os_pwm_desc *desc);
/* Set period of PWM generator device */
int32_t no_os_pwm_set_period(struct no_os_pwm_desc *desc,
uint32_t period_ns);
/* Get period of PWM generator device */
int32_t no_os_pwm_get_period(struct no_os_pwm_desc *desc,
uint32_t *period_ns);
/* Set duty cycle of PWM generator device */
int32_t no_os_pwm_set_duty_cycle(struct no_os_pwm_desc *desc,
uint32_t duty_cycle_ns);
/* Get period of PWM generator device */
int32_t no_os_pwm_get_duty_cycle(struct no_os_pwm_desc *desc,
uint32_t *duty_cycle_ns);
/* Set the phase of PWM generator channel */
int32_t no_os_pwm_set_phase(struct no_os_pwm_desc *desc,
uint32_t phase_ns);
/* Get the phase of PWM generator channel */
int32_t no_os_pwm_get_phase(struct no_os_pwm_desc *desc,
uint32_t *phase_ns);
/* Set polarity of PWM generator device */
int32_t no_os_pwm_set_polarity(struct no_os_pwm_desc *desc,
enum no_os_pwm_polarity polarity);
/* Set polarity of PWM generator device */
int32_t no_os_pwm_get_polarity(struct no_os_pwm_desc *desc,
enum no_os_pwm_polarity *polarity);
#endif // _NO_OS_PWM_H_
@@ -0,0 +1,91 @@
/***************************************************************************//**
* @file no_os_rtc.h
* @brief Header of the RTC interface
* @author Andrei Drimbarean (andrei.drimbarean@analog.com)
********************************************************************************
* Copyright 2020(c) Analog Devices, Inc.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* 3. Neither the name of Analog Devices, Inc. nor the names of its
* contributors may be used to endorse or promote products derived from this
* software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY ANALOG DEVICES, INC. “AS IS” AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
* EVENT SHALL ANALOG DEVICES, INC. BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
* OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
* EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*******************************************************************************/
#ifndef _NO_OS_RTC_H_
#define _NO_OS_RTC_H_
#include <stdint.h>
/**
* @struct no_os_rtc_desc
* @brief Structure holding RTC descriptor.
*/
struct no_os_rtc_desc {
/** ID of the real time clock core. */
uint8_t id;
/** Frequency of the RTC */
uint32_t freq;
/** Load value of the RTC */
uint32_t load;
/** Device specific RTC parameters. */
void *extra;
};
/**
* @struct no_os_rtc_init_param
* @brief Structure holding RTC initialization parameters.
*/
struct no_os_rtc_init_param {
/** ID of the real time clock core. */
uint8_t id;
/** Frequency of the RTC */
uint32_t freq;
/** Load value of the RTC */
uint32_t load;
/** Device specific RTC parameters. */
void *extra;
};
/** Initialize the RTC peripheral. */
int32_t no_os_rtc_init(struct no_os_rtc_desc **device,
struct no_os_rtc_init_param *init_param);
/** Free the resources allocated by no_os_rtc_init(). */
int32_t no_os_rtc_remove(struct no_os_rtc_desc *dev);
/** Start the real time clock. */
int32_t no_os_rtc_start(struct no_os_rtc_desc *dev);
/** Stop the real time clock. */
int32_t no_os_rtc_stop(struct no_os_rtc_desc *dev);
/** Get the current count for the real time clock. */
int32_t no_os_rtc_get_cnt(struct no_os_rtc_desc *dev, uint32_t *tmr_cnt);
/** Set the current count for the real time clock. */
int32_t no_os_rtc_set_cnt(struct no_os_rtc_desc *dev, uint32_t tmr_cnt);
/** Set the time at which an interrupt will occur */
int32_t no_os_rtc_set_irq_time(struct no_os_rtc_desc *dev, uint32_t irq_time);
#endif // _NO_OS_RTC_H_
@@ -0,0 +1,63 @@
/*******************************************************************************
* @file util/no_os_semaphore.c
* @brief Implementation of no-OS semaphore funtionality.
* @author Robert Budai (robert.budai@analog.com)
********************************************************************************
* Copyright 2023(c) Analog Devices, Inc.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* 3. Neither the name of Analog Devices, Inc. nor the names of its
* contributors may be used to endorse or promote products derived from this
* software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY ANALOG DEVICES, INC. “AS IS” AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
* EVENT SHALL ANALOG DEVICES, INC. BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
* OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
* EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*******************************************************************************/
#include "no_os_semaphore.h"
/**
* @brief Initialize semaphore.
* @param ptr - Pointer toward the semaphore.
* @return None.
*/
__attribute__((weak)) void no_os_semaphore_init(void **semaphore) {}
/**
* @brief Take token from semaphore.
* @param ptr - Pointer toward the semaphore.
* @return None.
*/
__attribute__((weak)) void no_os_semaphore_take(void *semaphore) {}
/**
* @brief Give token to semaphore
* @param ptr - Pointer toward the semaphore.
* @return None.
*/
__attribute((weak)) void no_os_semaphore_give(void *semaphore) {}
/**
* @brief Remove semaphore.
* @param ptr - Pointer toward the semaphore.
* @return None.
*/
__attribute__((weak)) void no_os_semaphore_remove(void *semaphore) {}
@@ -0,0 +1,48 @@
/*******************************************************************************
* @file no_os_semaphore.h
* @brief Header file of semaphore implementation.
* @author Robert Budai (robert.budai@analog.com)
********************************************************************************
* Copyright 2023(c) Analog Devices, Inc.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* 3. Neither the name of Analog Devices, Inc. nor the names of its
* contributors may be used to endorse or promote products derived from this
* software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY ANALOG DEVICES, INC. “AS IS” AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
* EVENT SHALL ANALOG DEVICES, INC. BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
* OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
* EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*******************************************************************************/
#ifndef _NO_OS_SEMAPHORE_H_
#define _NO_OS_SEMAPHORE_H_
/* Initialize semaphore */
void no_os_semaphore_init(void **semaphore);
/* Take token from semaphore */
void no_os_semaphore_take(void *semaphore);
/* Give token to semaphore */
void no_os_semaphore_give(void *semaphore);
/* Remove semaphore */
void no_os_semaphore_remove(void *semaphore);
#endif // _NO_OS_SEMAPHORE_H_
@@ -0,0 +1,68 @@
#include <stdint.h>
const uint16_t no_os_sine_lut_16[512] = {
0x8000, 0x8192, 0x8324, 0x84b6, 0x8647, 0x87d9, 0x896a, 0x8afb,
0x8c8b, 0x8e1b, 0x8fab, 0x9139, 0x92c7, 0x9455, 0x95e1, 0x976d,
0x98f8, 0x9a82, 0x9c0b, 0x9d93, 0x9f19, 0xa09f, 0xa223, 0xa3a6,
0xa527, 0xa6a7, 0xa826, 0xa9a3, 0xab1f, 0xac98, 0xae10, 0xaf87,
0xb0fb, 0xb26e, 0xb3de, 0xb54d, 0xb6b9, 0xb824, 0xb98c, 0xbaf2,
0xbc56, 0xbdb7, 0xbf17, 0xc073, 0xc1cd, 0xc325, 0xc47a, 0xc5cc,
0xc71c, 0xc869, 0xc9b3, 0xcafb, 0xcc3f, 0xcd81, 0xcebf, 0xcffb,
0xd133, 0xd268, 0xd39a, 0xd4c9, 0xd5f5, 0xd71d, 0xd842, 0xd964,
0xda82, 0xdb9c, 0xdcb3, 0xddc7, 0xded7, 0xdfe3, 0xe0eb, 0xe1f0,
0xe2f1, 0xe3ee, 0xe4e8, 0xe5dd, 0xe6cf, 0xe7bc, 0xe8a6, 0xe98b,
0xea6d, 0xeb4a, 0xec23, 0xecf8, 0xedc9, 0xee96, 0xef5e, 0xf022,
0xf0e2, 0xf19d, 0xf254, 0xf307, 0xf3b5, 0xf45f, 0xf504, 0xf5a5,
0xf641, 0xf6d8, 0xf76b, 0xf7fa, 0xf884, 0xf909, 0xf989, 0xfa05,
0xfa7c, 0xfaee, 0xfb5c, 0xfbc5, 0xfc29, 0xfc88, 0xfce3, 0xfd39,
0xfd89, 0xfdd5, 0xfe1d, 0xfe5f, 0xfe9c, 0xfed5, 0xff09, 0xff37,
0xff61, 0xff86, 0xffa6, 0xffc1, 0xffd8, 0xffe9, 0xfff5, 0xfffd,
0xffff, 0xfffd, 0xfff5, 0xffe9, 0xffd8, 0xffc1, 0xffa6, 0xff86,
0xff61, 0xff37, 0xff09, 0xfed5, 0xfe9c, 0xfe5f, 0xfe1d, 0xfdd5,
0xfd89, 0xfd39, 0xfce3, 0xfc88, 0xfc29, 0xfbc5, 0xfb5c, 0xfaee,
0xfa7c, 0xfa05, 0xf989, 0xf909, 0xf884, 0xf7fa, 0xf76b, 0xf6d8,
0xf641, 0xf5a5, 0xf504, 0xf45f, 0xf3b5, 0xf307, 0xf254, 0xf19d,
0xf0e2, 0xf022, 0xef5e, 0xee96, 0xedc9, 0xecf8, 0xec23, 0xeb4a,
0xea6d, 0xe98b, 0xe8a6, 0xe7bc, 0xe6cf, 0xe5dd, 0xe4e8, 0xe3ee,
0xe2f1, 0xe1f0, 0xe0eb, 0xdfe3, 0xded7, 0xddc7, 0xdcb3, 0xdb9c,
0xda82, 0xd964, 0xd842, 0xd71d, 0xd5f5, 0xd4c9, 0xd39a, 0xd268,
0xd133, 0xcffb, 0xcebf, 0xcd81, 0xcc3f, 0xcafb, 0xc9b3, 0xc869,
0xc71c, 0xc5cc, 0xc47a, 0xc325, 0xc1cd, 0xc073, 0xbf17, 0xbdb7,
0xbc56, 0xbaf2, 0xb98c, 0xb824, 0xb6b9, 0xb54d, 0xb3de, 0xb26e,
0xb0fb, 0xaf87, 0xae10, 0xac98, 0xab1f, 0xa9a3, 0xa826, 0xa6a7,
0xa527, 0xa3a6, 0xa223, 0xa09f, 0x9f19, 0x9d93, 0x9c0b, 0x9a82,
0x98f8, 0x976d, 0x95e1, 0x9455, 0x92c7, 0x9139, 0x8fab, 0x8e1b,
0x8c8b, 0x8afb, 0x896a, 0x87d9, 0x8647, 0x84b6, 0x8324, 0x8192,
0x8000, 0x7e6d, 0x7cdb, 0x7b49, 0x79b8, 0x7826, 0x7695, 0x7504,
0x7374, 0x71e4, 0x7054, 0x6ec6, 0x6d38, 0x6baa, 0x6a1e, 0x6892,
0x6707, 0x657d, 0x63f4, 0x626c, 0x60e6, 0x5f60, 0x5ddc, 0x5c59,
0x5ad8, 0x5958, 0x57d9, 0x565c, 0x54e0, 0x5367, 0x51ef, 0x5078,
0x4f04, 0x4d91, 0x4c21, 0x4ab2, 0x4946, 0x47db, 0x4673, 0x450d,
0x43a9, 0x4248, 0x40e8, 0x3f8c, 0x3e32, 0x3cda, 0x3b85, 0x3a33,
0x38e3, 0x3796, 0x364c, 0x3504, 0x33c0, 0x327e, 0x3140, 0x3004,
0x2ecc, 0x2d97, 0x2c65, 0x2b36, 0x2a0a, 0x28e2, 0x27bd, 0x269b,
0x257d, 0x2463, 0x234c, 0x2238, 0x2128, 0x201c, 0x1f14, 0x1e0f,
0x1d0e, 0x1c11, 0x1b17, 0x1a22, 0x1930, 0x1843, 0x1759, 0x1674,
0x1592, 0x14b5, 0x13dc, 0x1307, 0x1236, 0x1169, 0x10a1, 0xfdd,
0xf1d, 0xe62, 0xdab, 0xcf8, 0xc4a, 0xba0, 0xafb, 0xa5a,
0x9be, 0x927, 0x894, 0x805, 0x77b, 0x6f6, 0x676, 0x5fa,
0x583, 0x511, 0x4a3, 0x43a, 0x3d6, 0x377, 0x31c, 0x2c6,
0x276, 0x22a, 0x1e2, 0x1a0, 0x163, 0x12a, 0xf6, 0xc8,
0x9e, 0x79, 0x59, 0x3e, 0x27, 0x16, 0xa, 0x2,
0x0, 0x2, 0xa, 0x16, 0x27, 0x3e, 0x59, 0x79,
0x9e, 0xc8, 0xf6, 0x12a, 0x163, 0x1a0, 0x1e2, 0x22a,
0x276, 0x2c6, 0x31c, 0x377, 0x3d6, 0x43a, 0x4a3, 0x511,
0x583, 0x5fa, 0x676, 0x6f6, 0x77b, 0x805, 0x894, 0x927,
0x9be, 0xa5a, 0xafb, 0xba0, 0xc4a, 0xcf8, 0xdab, 0xe62,
0xf1d, 0xfdd, 0x10a1, 0x1169, 0x1236, 0x1307, 0x13dc, 0x14b5,
0x1592, 0x1674, 0x1759, 0x1843, 0x1930, 0x1a22, 0x1b17, 0x1c11,
0x1d0e, 0x1e0f, 0x1f14, 0x201c, 0x2128, 0x2238, 0x234c, 0x2463,
0x257d, 0x269b, 0x27bd, 0x28e2, 0x2a0a, 0x2b36, 0x2c65, 0x2d97,
0x2ecc, 0x3004, 0x3140, 0x327e, 0x33c0, 0x3504, 0x364c, 0x3796,
0x38e3, 0x3a33, 0x3b85, 0x3cda, 0x3e32, 0x3f8c, 0x40e8, 0x4248,
0x43a9, 0x450d, 0x4673, 0x47db, 0x4946, 0x4ab2, 0x4c21, 0x4d91,
0x4f04, 0x5078, 0x51ef, 0x5367, 0x54e0, 0x565c, 0x57d9, 0x5958,
0x5ad8, 0x5c59, 0x5ddc, 0x5f60, 0x60e6, 0x626c, 0x63f4, 0x657d,
0x6707, 0x6892, 0x6a1e, 0x6baa, 0x6d38, 0x6ec6, 0x7054, 0x71e4,
0x7374, 0x7504, 0x7695, 0x7826, 0x79b8, 0x7b49, 0x7cdb, 0x7e6d,
};
@@ -0,0 +1,278 @@
/***************************************************************************//**
* @file no_os_spi.c
* @brief Implementation of the SPI Interface
* @author Antoniu Miclaus (antoniu.miclaus@analog.com)
********************************************************************************
* Copyright 2020(c) Analog Devices, Inc.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* 3. Neither the name of Analog Devices, Inc. nor the names of its
* contributors may be used to endorse or promote products derived from this
* software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY ANALOG DEVICES, INC. “AS IS” AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
* EVENT SHALL ANALOG DEVICES, INC. BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
* OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
* EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*******************************************************************************/
#include <inttypes.h>
#include "no_os_spi.h"
#include <stdlib.h>
#include "no_os_error.h"
#include "no_os_mutex.h"
#include "no_os_alloc.h"
/**
* @brief spi_table contains the pointers towards the SPI buses
*/
static void *spi_table[SPI_MAX_BUS_NUMBER + 1];
/**
* @brief Initialize the SPI communication peripheral.
* @param desc - The SPI descriptor.
* @param param - The structure that contains the SPI parameters.
* @return 0 in case of success, -1 otherwise.
*/
int32_t no_os_spi_init(struct no_os_spi_desc **desc,
const struct no_os_spi_init_param *param)
{
int32_t ret;
if (!param || !param->platform_ops)
return -EINVAL;
if (!param->platform_ops->init)
return -ENOSYS;
if (param->device_id > SPI_MAX_BUS_NUMBER)
return -EINVAL;
// Initializing BUS descriptor
if (!spi_table[param->device_id]) {
ret = no_os_spibus_init(param);
if (ret)
return ret;
}
// Initilize SPI descriptor
ret = param->platform_ops->init(desc, param);
if (ret)
return ret;
(*desc)->bus = spi_table[param->device_id];
(*desc)->bus->slave_number++;
(*desc)->platform_ops = param->platform_ops;
(*desc)->parent = param->parent;
(*desc)->platform_delays = param->platform_delays;
return 0;
}
/**
* @brief Initialize the SPI bus communication peripheral.
* @param param - The structure that containes the SPI bus parameters
* @return 0 in case of success, error code otherwise
*/
int32_t no_os_spibus_init(const struct no_os_spi_init_param *param)
{
struct no_os_spibus_desc *bus = (struct no_os_spibus_desc *)no_os_calloc(1,
sizeof(struct no_os_spibus_desc));
if (!bus)
return -ENOMEM;
no_os_mutex_init(&(bus->mutex));
bus->slave_number = 0;
bus->device_id = param->device_id;
bus->max_speed_hz = param->max_speed_hz;
bus->mode = param->mode;
bus->bit_order = param->bit_order;
bus->platform_ops = param->platform_ops;
bus->extra = param->extra;
spi_table[param->device_id] = bus;
return 0;
}
/**
* @brief Free the resources allocated by no_os_spi_init().
* @param desc - The SPI descriptor.
* @return 0 in case of success, -1 otherwise.
*/
int32_t no_os_spi_remove(struct no_os_spi_desc *desc)
{
if (!desc || !desc->platform_ops)
return -EINVAL;
if (desc->bus)
no_os_spibus_remove(desc->bus->device_id);
if (!desc->platform_ops->remove)
return -ENOSYS;
return desc->platform_ops->remove(desc);
}
/**
* @brief Removes SPI bus instance
* @param bus_number - SPI bus number
*/
void no_os_spibus_remove(uint32_t bus_number)
{
struct no_os_spibus_desc *bus = (struct no_os_spibus_desc *)
spi_table[bus_number];
if (bus->slave_number > 0)
bus->slave_number--;
if (bus->slave_number == 0) {
no_os_mutex_remove(bus->mutex);
if (bus) {
no_os_free(bus);
bus = NULL;
spi_table[bus_number] = NULL;
}
}
}
/**
* @brief Write and read data to/from SPI.
* @param desc - The SPI descriptor.
* @param data - The buffer with the transmitted/received data.
* @param bytes_number - Number of bytes to write/read.
* @return 0 in case of success, -1 otherwise.
*/
int32_t no_os_spi_write_and_read(struct no_os_spi_desc *desc,
uint8_t *data,
uint16_t bytes_number)
{
int32_t ret;
if (!desc || !desc->platform_ops)
return -EINVAL;
if (!desc->platform_ops->write_and_read)
return -ENOSYS;
no_os_mutex_lock(desc->bus->mutex);
ret = desc->platform_ops->write_and_read(desc, data, bytes_number);
no_os_mutex_unlock(desc->bus->mutex);
return ret;
}
/**
* @brief Iterate over head list and send all spi messages
* @param desc - The SPI descriptor.
* @param msgs - Array of messages.
* @param len - Number of messages in the array.
* @return 0 in case of success, negativ error code otherwise.
*/
int32_t no_os_spi_transfer(struct no_os_spi_desc *desc,
struct no_os_spi_msg *msgs,
uint32_t len)
{
int32_t ret = 0;
uint32_t i;
if (!desc || !desc->platform_ops)
return -EINVAL;
if (desc->platform_ops->transfer)
return desc->platform_ops->transfer(desc, msgs, len);
no_os_mutex_lock(desc->bus->mutex);
for (i = 0; i < len; i++) {
if (msgs[i].rx_buff != msgs[i].tx_buff || !msgs[i].tx_buff) {
ret = -EINVAL;
goto out;
}
ret = no_os_spi_write_and_read(desc, msgs[i].rx_buff,
msgs[i].bytes_number);
if (NO_OS_IS_ERR_VALUE(ret)) {
goto out;
}
}
out:
no_os_mutex_unlock(desc->bus->mutex);
return ret;
}
/**
* @brief Transfer a list of messages using DMA and busy wait for the completion
* @param desc - The SPI descriptor.
* @param msgs - Array of messages.
* @param len - Number of messages in the array.
* @return 0 in case of success, negativ error code otherwise.
*/
int32_t no_os_spi_transfer_dma(struct no_os_spi_desc *desc,
struct no_os_spi_msg *msgs,
uint32_t len)
{
if (!desc || !desc->platform_ops || !msgs || !len)
return -EINVAL;
if (desc->platform_ops->transfer_dma)
return desc->platform_ops->transfer_dma(desc, msgs, len);
return -ENOSYS;
}
/**
* @brief Transfer a list of messages using DMA. The function will return after the
* first transfer is started. Once all the transfers are complete, a callback
* will be called.
* @param desc - The SPI descriptor.
* @param msgs - Array of messages.
* @param len - Number of messages in the array.
* @param callback - A function which will be called after all the transfers are done.
* @param ctx - User specific data which should be passed to the callback function.
* @return 0 in case of success, negativ error code otherwise.
*/
int32_t no_os_spi_transfer_dma_async(struct no_os_spi_desc *desc,
struct no_os_spi_msg *msgs,
uint32_t len,
void (*callback)(void *),
void *ctx)
{
if (!desc || !desc->platform_ops || !msgs || !len)
return -EINVAL;
if (desc->platform_ops->transfer_dma_async)
return desc->platform_ops->transfer_dma_async(desc, msgs, len,
callback, ctx);
return -ENOSYS;
}
/**
* @brief Abort SPI transfers.
* @param desc - The SPI descriptor.
* @return 0 in case of success, -1 otherwise.
*/
int32_t no_os_spi_transfer_abort(struct no_os_spi_desc *desc)
{
if (!desc || !desc->platform_ops)
return -EINVAL;
if (!desc->platform_ops->transfer_abort)
return -ENOSYS;
return desc->platform_ops->transfer_abort(desc);
}
@@ -0,0 +1,275 @@
/***************************************************************************//**
* @file no_os_spi.h
* @brief Header file of SPI Interface
* @author DBogdan (dragos.bogdan@analog.com)
********************************************************************************
* Copyright 2019(c) Analog Devices, Inc.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* 3. Neither the name of Analog Devices, Inc. nor the names of its
* contributors may be used to endorse or promote products derived from this
* software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY ANALOG DEVICES, INC. “AS IS” AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
* EVENT SHALL ANALOG DEVICES, INC. BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
* OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
* EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*******************************************************************************/
#ifndef _NO_OS_SPI_H_
#define _NO_OS_SPI_H_
#include <stdint.h>
#define NO_OS_SPI_CPHA 0x01
#define NO_OS_SPI_CPOL 0x02
#define SPI_MAX_BUS_NUMBER 8
/**
* @enum no_os_spi_mode
* @brief SPI configuration for clock phase and polarity.
*/
enum no_os_spi_mode {
/** Data on rising, shift out on falling */
NO_OS_SPI_MODE_0 = (0 | 0),
/** Data on falling, shift out on rising */
NO_OS_SPI_MODE_1 = (0 | NO_OS_SPI_CPHA),
/** Data on rising, shift out on falling */
NO_OS_SPI_MODE_2 = (NO_OS_SPI_CPOL | 0),
/** Data on falling, shift out on rising */
NO_OS_SPI_MODE_3 = (NO_OS_SPI_CPOL | NO_OS_SPI_CPHA)
};
/**
* @enum no_os_spi_bit_order
* @brief SPI configuration for bit order (MSB/LSB).
*/
enum no_os_spi_bit_order {
/** Most-significant bit (MSB) first */
NO_OS_SPI_BIT_ORDER_MSB_FIRST = 0,
/** Least-significant bit (LSB) first */
NO_OS_SPI_BIT_ORDER_LSB_FIRST = 1,
};
/**
* @enum no_os_spi_lanes
* @brief SPI configuration for number of lanes.
*/
enum no_os_spi_lanes {
/** Single Lane */
NO_OS_SPI_SINGLE_LANE,
/** Dual Lane */
NO_OS_SPI_DUAL_LANE,
/** Quad Lane */
NO_OS_SPI_QUAD_LANE,
/** Octo Lane */
NO_OS_SPI_OCTO_LANE,
};
/**
* @struct no_os_spi_msg_list
* @brief List item describing a SPI transfer
*/
struct no_os_spi_msg {
/** Buffer with data to send. If NULL, 0x00 will be sent */
uint8_t *tx_buff;
/** Buffer where to store data. If NULL, incoming data won't be saved */
uint8_t *rx_buff;
/** Length of buffers. Must have equal size. */
uint32_t bytes_number;
/** If set, CS will be deasserted after the transfer */
uint8_t cs_change;
/**
* Minimum delay (in us) between the CS de-assert event of the current message
* and the assert of the next one.
*/
uint32_t cs_change_delay;
/** Delay (in us) between the CS assert and the first SCLK edge. */
uint32_t cs_delay_first;
/** Delay (in us) between the last SCLK edge and the CS deassert */
uint32_t cs_delay_last;
};
/**
* @struct no_os_platform_spi_delays
* @brief Delays resulted from components in the SPI signal path. The values is ns.
*/
struct no_os_platform_spi_delays {
uint32_t cs_delay_first;
uint32_t cs_delay_last;
};
/**
* @struct no_os_spi_platform_ops
* @brief Structure holding SPI function pointers that point to the platform
* specific function
*/
struct no_os_spi_platform_ops ;
/**
* @struct no_os_spi_init_param
* @brief Structure holding the parameters for SPI initialization
*/
struct no_os_spi_init_param {
/** Device ID */
uint32_t device_id;
/** maximum transfer speed */
uint32_t max_speed_hz;
/** SPI chip select */
uint8_t chip_select;
/** SPI mode */
enum no_os_spi_mode mode;
/** SPI bit order */
enum no_os_spi_bit_order bit_order;
/** SPI Lanes */
enum no_os_spi_lanes lanes;
/** SPI bus platform ops */
const struct no_os_spi_platform_ops *platform_ops;
/** SPI delays */
struct no_os_platform_spi_delays platform_delays;
/** SPI extra parameters (device specific) */
void *extra;
/** Parent of the device */
struct no_os_spi_desc *parent;
};
/**
* @struct no_os_spibus_desc
* @brief SPI bus descriptor
*/
struct no_os_spibus_desc {
/** SPI bus mutex (lock) */
void *mutex;
/** SPI bus slave number*/
uint8_t slave_number;
/** SPI bus device id */
uint32_t device_id;
/** SPI bus max speed */
uint32_t max_speed_hz;
/** SPI bus mode */
enum no_os_spi_mode mode;
/** SPI bus bit order */
enum no_os_spi_bit_order bit_order;
/** SPI Lanes */
enum no_os_spi_lanes lanes;
/** SPI bus platform ops */
const struct no_os_spi_platform_ops *platform_ops;
/** SPI bus extra */
void *extra;
};
/**
* @struct no_os_spi_desc
* @brief Structure holding SPI descriptor.
*/
struct no_os_spi_desc {
/** SPI bus address */
struct no_os_spibus_desc *bus;
/** SPI bus number (0 for SPI0, 1 for SPI1, ...) */
uint32_t device_id;
/** maximum transfer speed */
uint32_t max_speed_hz;
/** SPI chip select */
uint8_t chip_select;
/** SPI mode */
enum no_os_spi_mode mode;
/** SPI bit order */
enum no_os_spi_bit_order bit_order;
/** SPI Lanes */
enum no_os_spi_lanes lanes;
/** SPI bus platform ops */
const struct no_os_spi_platform_ops *platform_ops;
/** SPI delays */
struct no_os_platform_spi_delays platform_delays;
/** SPI extra parameters (device specific) */
void *extra;
/** Parent of the device */
struct no_os_spi_desc *parent;
};
/**
* @struct no_os_spi_platform_ops
* @brief Structure holding SPI function pointers that point to the platform
* specific function
*/
struct no_os_spi_platform_ops {
/** SPI initialization function pointer */
int32_t (*init)(struct no_os_spi_desc **, const struct no_os_spi_init_param *);
/** SPI write/read function pointer */
int32_t (*write_and_read)(struct no_os_spi_desc *, uint8_t *, uint16_t);
/** Iterate over the spi_msg array and send all messages at once */
int32_t (*transfer)(struct no_os_spi_desc *, struct no_os_spi_msg *, uint32_t);
/** Iterate over the spi_msg array and send all messages using DMA.
* Blocks until the transfer is completed.
*/
int32_t (*transfer_dma)(struct no_os_spi_desc *, struct no_os_spi_msg *,
uint32_t);
/** Iterate over the spi_msg array and send all messages using DMA.
* Returns immediately after the transfer is started and invokes a
* callback once all the messages have been transfered.
*/
int32_t (*transfer_dma_async)(struct no_os_spi_desc *, struct no_os_spi_msg *,
uint32_t, void (*)(void *), void *);
/** SPI remove function pointer */
int32_t (*remove)(struct no_os_spi_desc *);
/** SPI abort function pointer */
int32_t (*transfer_abort)(struct no_os_spi_desc *);
};
/* Initialize the SPI communication peripheral. */
int32_t no_os_spi_init(struct no_os_spi_desc **desc,
const struct no_os_spi_init_param *param);
/* Free the resources allocated by no_os_spi_init(). */
int32_t no_os_spi_remove(struct no_os_spi_desc *desc);
/* Write and read data to/from SPI. */
int32_t no_os_spi_write_and_read(struct no_os_spi_desc *desc,
uint8_t *data,
uint16_t bytes_number);
/* Iterate over the spi_msg array and send all messages at once */
int32_t no_os_spi_transfer(struct no_os_spi_desc *desc,
struct no_os_spi_msg *msgs,
uint32_t len);
/* Transfer a list of messages using DMA. Wait until all transfers are done */
int32_t no_os_spi_transfer_dma(struct no_os_spi_desc *desc,
struct no_os_spi_msg *msgs,
uint32_t len);
/*
* Transfer a list of messages using DMA. Return once the first one started and
* invoke a callback when they are done.
*/
int32_t no_os_spi_transfer_dma_async(struct no_os_spi_desc *desc,
struct no_os_spi_msg *msgs,
uint32_t len,
void (*callback)(void *),
void *ctx);
/* Abort SPI transfers. */
int32_t no_os_spi_transfer_abort(struct no_os_spi_desc *desc);
/* Initialize SPI bus descriptor*/
int32_t no_os_spibus_init(const struct no_os_spi_init_param *param);
/* Free the resources allocated for SPI bus desc*/
void no_os_spibus_remove(uint32_t bus_number);
#endif // _NO_OS_SPI_H_
@@ -0,0 +1,125 @@
/***************************************************************************//**
* @file no_os_tdm.c
* @brief Implementation of the TDM interface
* @author Darius Berghe (darius.berghe@analog.com)
********************************************************************************
* Copyright 2020(c) Analog Devices, Inc.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* 3. Neither the name of Analog Devices, Inc. nor the names of its
* contributors may be used to endorse or promote products derived from this
* software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY ANALOG DEVICES, INC. “AS IS” AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
* EVENT SHALL ANALOG DEVICES, INC. BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
* OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
* EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*******************************************************************************/
#include <inttypes.h>
#include "no_os_tdm.h"
#include <stdlib.h>
#include "no_os_error.h"
/**
* @brief Initialize the TDM communication peripheral.
* @param desc - The TDM descriptor.
* @param param - The structure that contains the TDM parameters.
* @return 0 in case of success, negative error code otherwise.
*/
int32_t no_os_tdm_init(struct no_os_tdm_desc **desc,
const struct no_os_tdm_init_param *param)
{
if (!param)
return -1;
if ((param->platform_ops->tdm_ops_init(desc, param)))
return -1;
(*desc)->platform_ops = param->platform_ops;
return 0;
}
/**
* @brief Free the resources allocated by no_os_tdm_init().
* @param desc - The TDM descriptor.
* @return 0 in case of success, negative error code otherwise.
*/
int32_t no_os_tdm_remove(struct no_os_tdm_desc *desc)
{
return desc->platform_ops->tdm_ops_remove(desc);
}
/**
* @brief Read data using the TDM interface
* @param desc - The TDM descriptor.
* @param data - The buffer to store the received data.
* @param nb_samples - Number of samples to read.
* @return 0 in case of success, negative error code otherwise.
*/
int32_t no_os_tdm_read(struct no_os_tdm_desc *desc,
void *data,
uint16_t nb_samples)
{
return desc->platform_ops->tdm_ops_read(desc, data, nb_samples);
}
/**
* @brief Pause TDM DMA transfer
* @param desc - The TDM descriptor.
* @return 0 in case of success, negative error code otherwise.
*/
int32_t no_os_tdm_pause(struct no_os_tdm_desc *desc)
{
return desc->platform_ops->tdm_ops_pause(desc);
}
/**
* @brief Resume TDM DMA transfer
* @param desc - The TDM descriptor.
* @return 0 in case of success, negative error code otherwise.
*/
int32_t no_os_tdm_resume(struct no_os_tdm_desc *desc)
{
return desc->platform_ops->tdm_ops_resume(desc);
}
/**
* @brief Stop TDM DMA transfer
* @param desc - The TDM descriptor.
* @return 0 in case of success, negative error code otherwise.
*/
int32_t no_os_tdm_stop(struct no_os_tdm_desc *desc)
{
return desc->platform_ops->tdm_ops_stop(desc);
}
/**
* @brief Write data using the TDM interface
* @param desc - The TDM descriptor.
* @param data - The buffer with the data to be transmitted.
* @param nb_samples - Number of samples to write.
* @return 0 in case of success, negative error code otherwise.
*/
int32_t no_os_tdm_write(struct no_os_tdm_desc *desc,
void *data,
uint16_t nb_samples)
{
return desc->platform_ops->tdm_ops_write(desc, data, nb_samples);
}
@@ -0,0 +1,152 @@
/***************************************************************************//**
* @file no_os_tdm.h
* @brief Header file of TDM Interface
* @author Darius Berghe (darius.berghe@analog.com)
********************************************************************************
* Copyright 2020(c) Analog Devices, Inc.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* 3. Neither the name of Analog Devices, Inc. nor the names of its
* contributors may be used to endorse or promote products derived from this
* software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY ANALOG DEVICES, INC. “AS IS” AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
* EVENT SHALL ANALOG DEVICES, INC. BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
* OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
* EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*******************************************************************************/
#ifndef _NO_OS_TDM_H_
#define _NO_OS_TDM_H_
#include <stdint.h>
#include <stdbool.h>
/**
* @struct no_os_tdm_platform_ops
* @brief Structure holding TDM function pointers that point to the platform
* specific function
*/
struct no_os_tdm_platform_ops;
enum no_os_tdm_mode {
NO_OS_TDM_MASTER_TX,
NO_OS_TDM_MASTER_RX,
NO_OS_TDM_SLAVE_TX,
NO_OS_TDM_SLAVE_RX
};
/**
* @struct no_os_tdm_init_param
* @brief Structure holding the parameters for TDM initialization
*/
struct no_os_tdm_init_param {
/** TDM operating mode: master/slave, tx/rx */
enum no_os_tdm_mode mode;
/** Useful data size in a slot, specified in number of bits */
uint8_t data_size;
/** Data offset in a slot, specified in number of bits as offset from MSbit */
uint8_t data_offset;
/** Data ordering (default: msb first) */
bool data_lsb_first;
/** Number of slots in a frame */
uint8_t slots_per_frame;
/** Frame sync polarity specifier (default: FS active high) */
bool fs_active_low;
/** Frame sync active length specified in number of bits */
uint8_t fs_active_length;
/** Frame sync is normally asserted on first bit of slot 0 of a frame, this specifier allows assertion on last bit of the previous frame */
bool fs_lastbit;
/** Specify whether data sampling occurs on SCK rising edge (default: on SCK falling edge) */
bool rising_edge_sampling;
/* IRQ ID */
uint32_t irq_id;
/** DMA receive complete callback **/
void (*rx_complete_callback)(void *rx_arg);
/** DMA receive Half complete callback **/
void (*rx_half_complete_callback)(void *rx_arg);
/** Platform operation function pointers */
const struct no_os_tdm_platform_ops *platform_ops;
/** TDM extra parameters (platform specific) */
void *extra;
};
/**
* @struct no_os_tdm_desc
* @brief Structure holding TDM descriptor.
*/
struct no_os_tdm_desc {
/* IRQ ID */
uint32_t irq_id;
/** Platform operation function pointers */
const struct no_os_tdm_platform_ops *platform_ops;
/** Software FIFO. */
struct lf256fifo *rx_fifo;
/** TDM extra parameters (device specific) */
void *extra;
};
/**
* @struct no_os_tdm_platform_ops
* @brief Structure holding TDM function pointers that point to the platform
* specific function.
*/
struct no_os_tdm_platform_ops {
/** TDM initialization operation function pointer */
int32_t (*tdm_ops_init)(struct no_os_tdm_desc **,
const struct no_os_tdm_init_param *);
/** TDM read operation function pointer */
int32_t (*tdm_ops_read)(struct no_os_tdm_desc *, void *, uint16_t);
/** TDM write operation function pointer */
int32_t (*tdm_ops_write)(struct no_os_tdm_desc *, void *, uint16_t);
/** Pause TDM DMA transfer */
int32_t (*tdm_ops_pause)(struct no_os_tdm_desc *);
/** Resume TDM DMA transfer */
int32_t (*tdm_ops_resume)(struct no_os_tdm_desc *);
/** Stop TDM DMA transfer */
int32_t (*tdm_ops_stop)(struct no_os_tdm_desc *);
/** TDM remove operation function pointer */
int32_t (*tdm_ops_remove)(struct no_os_tdm_desc *);
};
/* Initialize the TDM communication peripheral. */
int32_t no_os_tdm_init(struct no_os_tdm_desc **desc,
const struct no_os_tdm_init_param *param);
/* Free the resources allocated by no_os_tdm_init(). */
int32_t no_os_tdm_remove(struct no_os_tdm_desc *desc);
/* Read data. */
int32_t no_os_tdm_read(struct no_os_tdm_desc *desc,
void *data,
uint16_t bytes_number);
/* Write data. */
int32_t no_os_tdm_write(struct no_os_tdm_desc *desc,
void *data,
uint16_t bytes_number);
/* Pause TDM DMA Transfer */
int32_t no_os_tdm_pause(struct no_os_tdm_desc *desc);
/* Resume TDM DMA Transfer */
int32_t no_os_tdm_resume(struct no_os_tdm_desc *desc);
/* Stop TDM DMA Transfer */
int32_t no_os_tdm_stop(struct no_os_tdm_desc *desc);
#endif // _NO_OS_TDM_H_
@@ -0,0 +1,213 @@
/***************************************************************************//**
* @file no_os_timer.c
* @brief Implementation of the timer Interface
* @author RBolboac (ramona.bolboaca@analog.com)
********************************************************************************
* Copyright 2022(c) Analog Devices, Inc.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* 3. Neither the name of Analog Devices, Inc. nor the names of its
* contributors may be used to endorse or promote products derived from this
* software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY ANALOG DEVICES, INC. “AS IS” AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
* EVENT SHALL ANALOG DEVICES, INC. BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
* OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
* EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*******************************************************************************/
#include <stddef.h>
#include "no_os_error.h"
#include "no_os_timer.h"
#include "no_os_mutex.h"
/**
* @brief - TIMER mutex
*/
static void *timer_mutex_table[TIMER_MAX_TABLE + 1];
/**
* @brief Initialize hardware timer and the handler structure associated with
* it.
* @param [out] desc - Pointer to the reference of the device handler.
* @param [in] param - Initialization structure.
* @return 0 in case of success, negative error code otherwise
*/
int32_t no_os_timer_init(struct no_os_timer_desc **desc,
const struct no_os_timer_init_param *param)
{
int32_t ret;
if (!param || !param->platform_ops)
return -EINVAL;
if (!param->platform_ops->init)
return -ENOSYS;
ret = param->platform_ops->init(desc, param);
if (ret)
return ret;
(*desc)->platform_ops = param->platform_ops;
no_os_mutex_init(&timer_mutex_table[param->id]);
(*desc)->mutex = timer_mutex_table[param->id];
return 0;
}
/**
* @brief Free the memory allocated by timer_init().
* @param [in] desc - Pointer to the device handler.
* @return 0 in case of success, negative error code otherwise
*/
int32_t no_os_timer_remove(struct no_os_timer_desc *desc)
{
if (!desc || !desc->platform_ops)
return -EINVAL;
if (!desc->platform_ops->remove)
return -ENOSYS;
no_os_mutex_remove(desc->mutex);
timer_mutex_table[desc->id] = NULL;
return desc->platform_ops->remove(desc);
}
/**
* @brief Start a timer.
* @param [in] desc - Pointer to the device handler.
* @return 0 in case of success, negative error code otherwise
*/
int32_t no_os_timer_start(struct no_os_timer_desc *desc)
{
if (!desc || !desc->platform_ops)
return -EINVAL;
if (!desc->platform_ops->start)
return -ENOSYS;
return desc->platform_ops->start(desc);
}
/**
* @brief Stop a timer from counting.
* @param [in] desc - Pointer to the device handler.
* @return 0 in case of success, negative error code otherwise
*/
int32_t no_os_timer_stop(struct no_os_timer_desc *desc)
{
if (!desc || !desc->platform_ops)
return -EINVAL;
if (!desc->platform_ops->stop)
return -ENOSYS;
no_os_mutex_unlock(desc->mutex);
return desc->platform_ops->stop(desc);
}
/**
* @brief Get the value of the counter register for the timer.
* @param [in] desc - Pointer to the device handler.
* @param [out] counter - Pointer to the counter value.
* @return 0 in case of success, error code otherwise.
*/
int32_t no_os_timer_counter_get(struct no_os_timer_desc *desc,
uint32_t *counter)
{
if (!desc || !desc->platform_ops || !counter)
return -EINVAL;
if (!desc->platform_ops->counter_get)
return -ENOSYS;
return desc->platform_ops->counter_get(desc, counter);
}
/**
* @brief Set the timer counter register value.
* @param [in] desc - Pointer to the device handler.
* @param [in] new_val - The new value of the counter register.
* @return 0 in case of success, error code otherwise.
*/
int32_t no_os_timer_counter_set(struct no_os_timer_desc *desc, uint32_t new_val)
{
if (!desc || !desc->platform_ops)
return -EINVAL;
if (!desc->platform_ops->counter_set)
return -ENOSYS;
return desc->platform_ops->counter_set(desc, new_val);
}
/**
* @brief Get the timer clock frequency.
* @param [in] desc - Pointer to the device handler.
* @param [out] freq_hz - The value in Hz of the timer clock.
* @return 0 in case of success, error code otherwise.
*/
int32_t no_os_timer_count_clk_get(struct no_os_timer_desc *desc,
uint32_t *freq_hz)
{
if (!desc || !desc->platform_ops || !freq_hz)
return -EINVAL;
if (!desc->platform_ops->count_clk_get)
return -ENOSYS;
return desc->platform_ops->count_clk_get(desc, freq_hz);
}
/**
* @brief Set the timer clock frequency.
* @param [in] desc - Pointer to the device handler.
* @param [in] freq_hz - The value in Hz of the new timer clock.
* @return 0 in case of success, error code otherwise.
*/
int32_t no_os_timer_count_clk_set(struct no_os_timer_desc *desc,
uint32_t freq_hz)
{
if (!desc || !desc->platform_ops)
return -EINVAL;
if (!desc->platform_ops->count_clk_set)
return -ENOSYS;
return desc->platform_ops->count_clk_set(desc, freq_hz);
}
/**
* @brief Get the elapsed time in nsec for the timer.
* @param [in] desc - Pointer to the device handler.
* @param [in] elapsed_time - The elapsed time in nsec.
* @return 0 in case of success, error code otherwise.
*/
int32_t no_os_timer_get_elapsed_time_nsec(struct no_os_timer_desc *desc,
uint64_t *elapsed_time)
{
if (!desc || !desc->platform_ops)
return -EINVAL;
if (!desc->platform_ops->get_elapsed_time_nsec)
return -ENOSYS;
return desc->platform_ops->get_elapsed_time_nsec(desc, elapsed_time);
}
@@ -0,0 +1,145 @@
/***************************************************************************//**
* @file no_os_timer.h
* @brief Timer control module header.
* @author Andrei Drimbarean (andrei.drimbarean@analog.com)
********************************************************************************
* Copyright 2019(c) Analog Devices, Inc.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* 3. Neither the name of Analog Devices, Inc. nor the names of its
* contributors may be used to endorse or promote products derived from this
* software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY ANALOG DEVICES, INC. “AS IS” AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
* EVENT SHALL ANALOG DEVICES, INC. BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
* OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
* EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*******************************************************************************/
#ifndef _NO_OS_SRC_TIMER_H_
#define _NO_OS_SRC_TIMER_H_
#include <stdint.h>
#define TIMER_MAX_TABLE 4
/**
* @struct no_os_timer_desc
* @brief Structure holding timer descriptor
*/
struct no_os_timer_desc {
/** Timer mutex*/
void *mutex;
/** timer ID */
uint16_t id;
/** timer count frequency (Hz) */
uint32_t freq_hz;
/** the number of ticks the timer counts until it resets */
uint32_t ticks_count;
/** Timer platform operations */
const struct no_os_timer_platform_ops *platform_ops;
/** timer extra parameters (device specific) */
void *extra;
};
/**
* @struct no_os_timer_platform_ops
* @brief Structure holding timer function pointers that point to the platform
* specific function
*/
struct no_os_timer_platform_ops ;
/**
* @struct no_os_timer_init_param
* @brief Structure holding the parameters for timer initialization
*/
struct no_os_timer_init_param {
/** timer ID */
uint16_t id;
/** timer count frequency (Hz) */
uint32_t freq_hz;
/** the number of ticks the timer counts until it resets */
uint32_t ticks_count;
/** Timer platform operations */
const struct no_os_timer_platform_ops *platform_ops;
/** timer extra parameters (device specific) */
void *extra;
};
/**
* @struct no_os_timer_platform_ops
* @brief Structure holding timer function pointers that point to the platform
* specific function
*/
struct no_os_timer_platform_ops {
/** timer initialization function pointer */
int32_t (*init)(struct no_os_timer_desc **,
const struct no_os_timer_init_param *);
/** timer start function pointer */
int32_t (*start)(struct no_os_timer_desc *);
/** timer stop function pointer */
int32_t (*stop)(struct no_os_timer_desc *);
/** timer get counter function pointer */
int32_t (*counter_get)(struct no_os_timer_desc *, uint32_t *counter);
/** timer set counter function pointer */
int32_t (*counter_set)(struct no_os_timer_desc *, uint32_t new_val);
/** timer get clock frequency function pointer */
int32_t (*count_clk_get)(struct no_os_timer_desc *, uint32_t *freq_hz);
/** timer set clock frequency function pointer */
int32_t (*count_clk_set)(struct no_os_timer_desc *, uint32_t freq_hz);
/** timer get elapsed time in nsec */
int32_t (*get_elapsed_time_nsec)(struct no_os_timer_desc *,
uint64_t *elapsed_time);
/** timer remove function pointer */
int32_t (*remove)(struct no_os_timer_desc *);
};
/* Initialize hardware timer and the handler structure associated with it. */
int32_t no_os_timer_init(struct no_os_timer_desc **desc,
const struct no_os_timer_init_param *param);
/* Free the memory allocated by timer_setup(). */
int32_t no_os_timer_remove(struct no_os_timer_desc *desc);
/* Start a timer. */
int32_t no_os_timer_start(struct no_os_timer_desc *desc);
/* Stop a timer from counting. */
int32_t no_os_timer_stop(struct no_os_timer_desc *desc);
/* Get the value of the counter register for the timer. */
int32_t no_os_timer_counter_get(struct no_os_timer_desc *desc,
uint32_t *counter);
/* Set the timer counter register value. */
int32_t no_os_timer_counter_set(struct no_os_timer_desc *desc,
uint32_t new_val);
/* Get the timer clock frequency. */
int32_t no_os_timer_count_clk_get(struct no_os_timer_desc *desc,
uint32_t *freq_hz);
/* Set the timer clock frequency. */
int32_t no_os_timer_count_clk_set(struct no_os_timer_desc *desc,
uint32_t freq_hz);
/* Get the elapsed time in nsec for the timer. */
int32_t no_os_timer_get_elapsed_time_nsec(struct no_os_timer_desc *desc,
uint64_t *elapsed_time);
#endif // _NO_OS_SRC_TIMER_H_
@@ -0,0 +1,98 @@
/***************************************************************************//**
* @file no_os_trng.c
* @brief Implementation of the TRNG Interface
* @author Antoniu Miclaus (antoniu.miclaus@analog.com)
********************************************************************************
* Copyright 2023(c) Analog Devices, Inc.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* 3. Neither the name of Analog Devices, Inc. nor the names of its
* contributors may be used to endorse or promote products derived from this
* software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY ANALOG DEVICES, INC. “AS IS” AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
* EVENT SHALL ANALOG DEVICES, INC. BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
* OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
* EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*******************************************************************************/
#include <inttypes.h>
#include "no_os_trng.h"
#include <stdlib.h>
#include "no_os_error.h"
/**
* @brief Initialize the TRNG.
* @param desc - The TRNG descriptor.
* @param param - The structure that contains the TRNG parameters.
* @return 0 in case of success, -1 otherwise.
*/
int no_os_trng_init(struct no_os_trng_desc **desc,
const struct no_os_trng_init_param *param)
{
int ret;
if (!param || !param->platform_ops)
return -EINVAL;
if (!param->platform_ops->init)
return -ENOSYS;
ret = param->platform_ops->init(desc, param);
if (ret)
return ret;
(*desc)->platform_ops = param->platform_ops;
return 0;
}
/**
* @brief Free the resources allocated by no_os_trng_init().
* @param desc - The TRNG descriptor.
* @return 0 in case of success, -1 otherwise.
*/
int no_os_trng_remove(struct no_os_trng_desc *desc)
{
if (!desc || !desc->platform_ops)
return -EINVAL;
if (!desc->platform_ops->remove)
return -ENOSYS;
return desc->platform_ops->remove(desc);
}
/**
* @brief Fill buffer with rng data.
* @param desc - The TRNG descriptor.
* @param buff - Buffer to be filled
* @param len - Size of the buffer
* @return 0 in case of success, -1 otherwise.
*/
int no_os_trng_fill_buffer(struct no_os_trng_desc *desc, uint8_t *buff,
uint32_t len)
{
if (!desc || !desc->platform_ops)
return -EINVAL;
if (!desc->platform_ops->fill_buffer)
return -ENOSYS;
return desc->platform_ops->fill_buffer(desc, buff, len);
}
@@ -0,0 +1,97 @@
/***************************************************************************//**
* @file no_os_trng.h
* @brief Header file of true random number generator
* @author Mihail Chindris (mihail.chindris@analog.com)
********************************************************************************
* @copyright
* Copyright 2020(c) Analog Devices, Inc.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* 3. Neither the name of Analog Devices, Inc. nor the names of its
* contributors may be used to endorse or promote products derived from this
* software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY ANALOG DEVICES, INC. “AS IS” AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
* EVENT SHALL ANALOG DEVICES, INC. BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
* OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
* EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*******************************************************************************/
#ifndef _NO_OS_TRNG_H_
#define _NO_OS_TRNG_H_
#include <stdint.h>
/**
* @struct no_os_trng_platform_ops
* @brief Structure holding TRNG function pointers that point to the platform
* specific function
*/
struct no_os_trng_platform_ops;
/**
* @struct no_os_trng_desc
* @brief TRNG Descriptor
*/
struct no_os_trng_desc {
/** Platform ops */
const struct no_os_trng_platform_ops *platform_ops;
/** Platform specific parameters */
void *extra;
};
/**
* @struct no_os_trng_init_param
* @brief Init parameter for TRNG
*/
struct no_os_trng_init_param {
/** Device id */
uint32_t dev_id;
/** Platform specific parameter */
void *extra;
/** Platform ops */
const struct no_os_trng_platform_ops *platform_ops;
};
/**
* @struct no_os_trng_platform_ops
* @brief Structure holding TRNG function pointers that point to the platform
* specific function
*/
struct no_os_trng_platform_ops {
/** TRNG initialization function pointer */
int (*init)(struct no_os_trng_desc **,
struct no_os_trng_init_param *);
/** Fill buffer with random numbers */
int (*fill_buffer)(struct no_os_trng_desc *, uint8_t *, uint32_t);
/** TRNG remove function pointer */
int (*remove)(struct no_os_trng_desc *);
};
/* Initialize descriptor */
int no_os_trng_init(struct no_os_trng_desc **desc,
const struct no_os_trng_init_param *param);
/* Free resources allocated in descriptor */
int no_os_trng_remove(struct no_os_trng_desc *desc);
/* Fill buffer with random numbers */
int no_os_trng_fill_buffer(struct no_os_trng_desc *desc, uint8_t *buff,
uint32_t len);
#endif // _NO_OS_TRNG_H_
@@ -0,0 +1,220 @@
/***************************************************************************//**
* @file no_os_uart.c
* @brief Implementation of the UART Interface
* @author Ramona Bolboaca (ramona.bolboaca@analog.com)
********************************************************************************
* Copyright 2022(c) Analog Devices, Inc.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* 3. Neither the name of Analog Devices, Inc. nor the names of its
* contributors may be used to endorse or promote products derived from this
* software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY ANALOG DEVICES, INC. “AS IS” AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
* EVENT SHALL ANALOG DEVICES, INC. BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
* OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
* EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*******************************************************************************/
#include <inttypes.h>
#include "no_os_uart.h"
#include <stdlib.h>
#include "no_os_error.h"
#include "no_os_mutex.h"
#include "no_os_util.h"
/**
* @brief - UART mutex
*/
static void *uart_mutex_table[UART_MAX_NUMBER + 1];
/**
* @brief Initialize the UART communication peripheral.
* @param desc - The UART descriptor.
* @param param - The structure that contains the UART parameters.
* @return 0 in case of success, error code otherwise.
*/
int32_t no_os_uart_init(struct no_os_uart_desc **desc,
struct no_os_uart_init_param *param)
{
int32_t ret;
if (!param || !param->platform_ops
|| param->device_id >= NO_OS_ARRAY_SIZE(uart_mutex_table))
return -EINVAL;
if (!param->platform_ops->init)
return -ENOSYS;
ret = param->platform_ops->init(desc, param);
if (ret)
return ret;
(*desc)->platform_ops = param->platform_ops;
no_os_mutex_init(&(uart_mutex_table[param->device_id]));
(*desc)-> mutex = uart_mutex_table[param->device_id];
return 0;
}
/**
* @brief Free the resources allocated by no_os_uart_init().
* @param desc - The UART descriptor.
* @return 0 in case of success, error code otherwise.
*/
int32_t no_os_uart_remove(struct no_os_uart_desc *desc)
{
if (!desc || !desc->platform_ops)
return -EINVAL;
if (!desc->platform_ops->remove)
return -ENOSYS;
no_os_mutex_remove(desc->mutex);
uart_mutex_table[desc->device_id] = NULL;
return desc->platform_ops->remove(desc);
}
/**
* @brief Check if errors occurred on UART.
* @param desc - The UART descriptor.
* @return number of errors in case of success, error code otherwise.
*/
uint32_t no_os_uart_get_errors(struct no_os_uart_desc *desc)
{
if (!desc || !desc->platform_ops)
return -EINVAL;
if (!desc->platform_ops->get_errors)
return -ENOSYS;
return desc->platform_ops->get_errors(desc);
}
/**
* @brief Read data from UART.
* @param desc - The UART descriptor.
* @param data - The buffer with the received data.
* @param bytes_number - Number of bytes to read.
* @return 0 in case of success, error code otherwise.
*/
int32_t no_os_uart_read(struct no_os_uart_desc *desc,
uint8_t *data,
uint32_t bytes_number)
{
int32_t ret;
if (!desc || !desc->platform_ops || !data)
return -EINVAL;
if (!desc->platform_ops->read)
return -ENOSYS;
no_os_mutex_lock(desc->mutex);
ret = desc->platform_ops->read(desc, data, bytes_number);
no_os_mutex_unlock(desc->mutex);
return ret;
}
/**
* @brief Write to UART.
* @param desc - The UART descriptor.
* @param data - The buffer with the transmitted data.
* @param bytes_number - Number of bytes to write.
* @return 0 in case of success, error code otherwise.
*/
int32_t no_os_uart_write(struct no_os_uart_desc *desc,
const uint8_t *data,
uint32_t bytes_number)
{
int32_t ret;
if (!desc || !desc->platform_ops || !data)
return -EINVAL;
if (!desc->platform_ops->write)
return -ENOSYS;
no_os_mutex_lock(desc->mutex);
ret = desc->platform_ops->write(desc, data, bytes_number);
no_os_mutex_unlock(desc->mutex);
return ret;
}
/**
* @brief Read data from UART non-blocking.
* @param desc - The UART descriptor.
* @param data - The buffer with the received data.
* @param bytes_number - Number of bytes to read.
* @return 0 in case of success, error code otherwise.
*/
int32_t no_os_uart_read_nonblocking(struct no_os_uart_desc *desc,
uint8_t *data,
uint32_t bytes_number)
{
int32_t ret;
if (!desc || !desc->platform_ops || !data)
return -EINVAL;
if (!desc->platform_ops->read_nonblocking)
return -ENOSYS;
no_os_mutex_lock(desc->mutex);
ret = desc->platform_ops->read_nonblocking(desc, data, bytes_number);
no_os_mutex_unlock(desc->mutex);
return ret;
}
/**
* @brief Write to UART non-blocking.
* @param desc - The UART descriptor.
* @param data - The buffer with the transmitted data.
* @param bytes_number - Number of bytes to write.
* @return 0 in case of success, error code otherwise.
*/
int32_t no_os_uart_write_nonblocking(struct no_os_uart_desc *desc,
const uint8_t *data,
uint32_t bytes_number)
{
int32_t ret;
if (!desc || !desc->platform_ops || !data)
return -EINVAL;
if (!desc->platform_ops->write_nonblocking)
return -ENOSYS;
no_os_mutex_lock(desc->mutex);
ret = desc->platform_ops->write_nonblocking(desc, data, bytes_number);
no_os_mutex_unlock(desc->mutex);
return ret;
}
void __attribute__((weak)) no_os_uart_stdio(struct no_os_uart_desc *desc)
{
/* This can optionally be implemented under drivers/platform.
* It does nothing if unimplemented. */
}
@@ -0,0 +1,191 @@
/***************************************************************************//**
* @file no_os_uart.h
* @brief Header file of UART interface.
* @author Cristian Pop (cristian.pop@analog.com)
********************************************************************************
* Copyright 2019(c) Analog Devices, Inc.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* 3. Neither the name of Analog Devices, Inc. nor the names of its
* contributors may be used to endorse or promote products derived from this
* software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY ANALOG DEVICES, INC. “AS IS” AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
* EVENT SHALL ANALOG DEVICES, INC. BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
* OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
* EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*******************************************************************************/
#ifndef _NO_OS_UART_H_
#define _NO_OS_UART_H_
#include <stdint.h>
#include <stdbool.h>
#include "no_os_lf256fifo.h"
#define UART_MAX_NUMBER 10
/**
* @enum no_os_uart_size
* @brief UART character size (number of data bits) options.
*/
enum no_os_uart_size {
/** 5 data bits */
NO_OS_UART_CS_5,
/** 6 data bits */
NO_OS_UART_CS_6,
/** 7 data bits */
NO_OS_UART_CS_7,
/** 8 data bits */
NO_OS_UART_CS_8,
/** 9 data bits */
NO_OS_UART_CS_9,
};
/**
* @enum no_os_uart_parity
* @brief UART parity options.
*/
enum no_os_uart_parity {
/** no parity */
NO_OS_UART_PAR_NO,
/** mark parity */
NO_OS_UART_PAR_MARK,
/** space parity */
NO_OS_UART_PAR_SPACE,
/** odd parity */
NO_OS_UART_PAR_ODD,
/** even parity */
NO_OS_UART_PAR_EVEN
};
/**
* @enum no_os_uart_stop
* @brief UART number of stop bits options.
*/
enum no_os_uart_stop {
/** one stop bit */
NO_OS_UART_STOP_1_BIT,
/** two stop bits */
NO_OS_UART_STOP_2_BIT
};
/**
* @struct no_os_uart_platform_ops
* @brief Structure holding UART function pointers that point to the platform
* specific function
*/
struct no_os_uart_platform_ops ;
/**
* @struct no_os_uart_init_param
* @brief Structure holding the parameters for UART initialization
*/
struct no_os_uart_init_param {
/** UART Device ID */
uint8_t device_id;
/** UART Interrupt ID */
uint32_t irq_id;
/** If set, the reception is interrupt driven. */
bool asynchronous_rx;
/** UART Baud Rate */
uint32_t baud_rate;
/** UART number of data bits */
enum no_os_uart_size size;
/** UART parity */
enum no_os_uart_parity parity;
/** UART number of stop bits */
enum no_os_uart_stop stop;
const struct no_os_uart_platform_ops *platform_ops;
/** UART extra parameters (device specific) */
void *extra;
};
/**
* @struct no_os_uart_desc
* @brief Stucture holding the UART descriptor.
*/
struct no_os_uart_desc {
/** UART mutex*/
void *mutex;
/** UART Device ID */
uint8_t device_id;
/** UART Interrupt ID */
uint32_t irq_id;
/** Software FIFO. */
struct lf256fifo *rx_fifo;
/** UART Baud Rate */
uint32_t baud_rate;
const struct no_os_uart_platform_ops *platform_ops;
/** UART extra parameters (device specific) */
void *extra;
};
/**
* @struct no_os_uart_platform_ops
* @brief Structure holding UART function pointers that point to the platform
* specific function
*/
struct no_os_uart_platform_ops {
/** UART initialization function pointer */
int32_t (*init)(struct no_os_uart_desc **, struct no_os_uart_init_param *);
/** UART read function pointer */
int32_t (*read)(struct no_os_uart_desc *, uint8_t *, uint32_t);
/** UART write function pointer */
int32_t (*write)(struct no_os_uart_desc *, const uint8_t *, uint32_t);
/** UART read non-blocking function pointer */
int32_t (*read_nonblocking)(struct no_os_uart_desc *, uint8_t *, uint32_t);
/** UART wrote non-blocking function pointer */
int32_t (*write_nonblocking)(struct no_os_uart_desc *, const uint8_t *,
uint32_t);
/** UART remove function pointer */
int32_t (*remove)(struct no_os_uart_desc *);
/** UART get errors function pointer */
uint32_t (*get_errors)(struct no_os_uart_desc *);
};
/* Read data from UART. Blocking function */
int32_t no_os_uart_read(struct no_os_uart_desc *desc, uint8_t *data,
uint32_t bytes_number);
/* Write data to UART. Blocking function */
int32_t no_os_uart_write(struct no_os_uart_desc *desc, const uint8_t *data,
uint32_t bytes_number);
/* Read data from UART. Non blocking function */
int32_t no_os_uart_read_nonblocking(struct no_os_uart_desc *desc, uint8_t *data,
uint32_t bytes_number);
/* Write data to UART. Non blocking function*/
int32_t no_os_uart_write_nonblocking(struct no_os_uart_desc *desc,
const uint8_t *data,
uint32_t bytes_number);
/* Initialize the UART communication peripheral. */
int32_t no_os_uart_init(struct no_os_uart_desc **desc,
struct no_os_uart_init_param *param);
/* Free the resources allocated by no_os_uart_init(). */
int32_t no_os_uart_remove(struct no_os_uart_desc *desc);
/* Check if UART errors occurred. */
uint32_t no_os_uart_get_errors(struct no_os_uart_desc *desc);
/* Make stdio to use this UART. */
void no_os_uart_stdio(struct no_os_uart_desc *desc);
#endif // _NO_OS_UART_H_
@@ -0,0 +1,83 @@
/***************************************************************************//**
* @file no_os_units.h
* @brief Header file of Units
* @author Antoniu Miclaus (antoniu.miclaus@analog.com)
********************************************************************************
* Copyright 2022(c) Analog Devices, Inc.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* 3. Neither the name of Analog Devices, Inc. nor the names of its
* contributors may be used to endorse or promote products derived from this
* software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY ANALOG DEVICES, INC. “AS IS” AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
* EVENT SHALL ANALOG DEVICES, INC. BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
* OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
* EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*******************************************************************************/
#ifndef _NO_OS_UNITS_H_
#define _NO_OS_UNITS_H_
#define PETA 1000000000000000ULL
#define TERA 1000000000000ULL
#define GIGA 1000000000UL
#define MEGA 1000000UL
#define KILO 1000UL
#define HECTO 100UL
#define DECA 10UL
#define DECI 10UL
#define CENTI 100UL
#define MILLI 1000UL
#define MICRO 1000000UL
#define NANO 1000000000UL
#define PICO 1000000000000ULL
#define FEMTO 1000000000000000ULL
#define HZ_PER_KHZ 1000UL
#define KHZ_PER_MHZ 1000UL
#define HZ_PER_MHZ 1000000UL
#define MILLIVOLT_PER_VOLT 1000UL
#define MICROVOLT_PER_VOLT 1000000UL
#define NANOVOLT_PER_VOLT 1000000000ULL
#define MILLIAMPER_PER_AMPER 1000UL
#define MICROAMPER_PER_MILLIAMPER 1000UL
#define MICROAMPER_PER_AMPER 1000000UL
#define NANOAMPER_PER_AMPER 1000000000ULL
#define MILLIWATT_PER_WATT 1000UL
#define MICROWATT_PER_MILLIWATT 1000UL
#define MICROWATT_PER_WATT 1000000UL
#define MILLIDEGREE_PER_DEGREE 1000UL
/* Returns the given value converted from degree to rad */
#define DEGREE_TO_RAD(deg) (((deg) * 314159ULL + 9000000ULL) / 18000000ULL)
/* Returns the given value converted from rad to degree */
#define RAD_TO_DEGREE(rad) \
(((rad) * 18000000ULL + 314159ULL / 2) / 314159ULL)
/* Returns the given value converted from g to meter / second**2 */
#define G_TO_M_S_2(g) ((g) * 980665ULL / 100000ULL)
/* Returns the given value converted from meter / second**2 to g */
#define M_S_2_TO_G(ms2) (((ms2) * 100000ULL + 980665ULL / 2) / 980665ULL)
#endif // _NO_OS_UNITS_H_
@@ -0,0 +1,568 @@
/***************************************************************************//**
* @file no_os_util.c
* @brief Implementation of utility functions.
* @author DBogdan (dragos.bogdan@analog.com)
********************************************************************************
* Copyright 2018(c) Analog Devices, Inc.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* 3. Neither the name of Analog Devices, Inc. nor the names of its
* contributors may be used to endorse or promote products derived from this
* software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY ANALOG DEVICES, INC. “AS IS” AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
* EVENT SHALL ANALOG DEVICES, INC. BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
* OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
* EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*******************************************************************************/
#include <string.h>
#include <stdlib.h>
#include "no_os_util.h"
#include "errno.h"
extern int no_os_test_bit(int pos, const volatile void * addr);
/**
* Find first set bit in word.
*/
uint32_t no_os_find_first_set_bit(uint32_t word)
{
uint32_t first_set_bit = 0;
while (word) {
if (word & 0x1)
return first_set_bit;
word >>= 1;
first_set_bit ++;
}
return 32;
}
/**
* Find first set bit in word.
*/
uint64_t no_os_find_first_set_bit_u64(uint64_t word)
{
uint64_t first_set_bit = 0;
while (word) {
if (word & 0x1)
return first_set_bit;
word >>= 1;
first_set_bit ++;
}
return 64;
}
/**
* Find last set bit in word.
*/
uint32_t no_os_find_last_set_bit(uint32_t word)
{
uint32_t bit = 0;
uint32_t last_set_bit = 32;
while (word) {
if (word & 0x1)
last_set_bit = bit;
word >>= 1;
bit ++;
}
return last_set_bit;
}
/**
* Locate the closest element in an array.
*/
uint32_t no_os_find_closest(int32_t val,
const int32_t *array,
uint32_t size)
{
int32_t diff = abs(array[0] - val);
uint32_t ret = 0;
uint32_t i;
for (i = 1; i < size; i++) {
if (abs(array[i] - val) < diff) {
diff = abs(array[i] - val);
ret = i;
}
}
return ret;
}
/**
* Shift the value and apply the specified mask.
*/
uint32_t no_os_field_prep(uint32_t mask, uint32_t val)
{
return (val << no_os_find_first_set_bit(mask)) & mask;
}
uint64_t no_os_field_prep_u64(uint64_t mask, uint64_t val)
{
return (val << no_os_find_first_set_bit_u64(mask)) & mask;
}
/**
* Get a field specified by a mask from a word.
*/
uint32_t no_os_field_get(uint32_t mask, uint32_t word)
{
return (word & mask) >> no_os_find_first_set_bit(mask);
}
/**
* Produce the maximum value representable by a field
*/
uint32_t no_os_field_max(uint32_t mask)
{
// Find the first set bit to determine the shift position
uint32_t first_set_bit = no_os_find_first_set_bit(mask);
// Shift the mask to the right by the position of the first set bit
uint32_t shifted_mask = mask >> first_set_bit;
return shifted_mask;
}
/**
* Produce the maximum value representable by a field
*/
uint64_t no_os_field_max_u64(uint64_t mask)
{
// Find the first set bit to determine the shift position
uint64_t first_set_bit = no_os_find_first_set_bit_u64(mask);
// Shift the mask to the right by the position of the first set bit
uint64_t shifted_mask = mask >> first_set_bit;
return shifted_mask;
}
/**
* Log base 2 of the given number.
*/
int32_t no_os_log_base_2(uint32_t x)
{
return no_os_find_last_set_bit(x);
}
/**
* Find greatest common divisor of the given two numbers.
*/
uint32_t no_os_greatest_common_divisor(uint32_t a,
uint32_t b)
{
uint32_t div;
if ((a == 0) || (b == 0))
return no_os_max(a, b);
while (b != 0) {
div = a % b;
a = b;
b = div;
}
return a;
}
uint64_t no_os_greatest_common_divisor_u64(uint64_t a,
uint64_t b)
{
uint64_t div;
if ((a == 0) || (b == 0))
return no_os_max(a, b);
while (b != 0) {
div = a % b;
a = b;
b = div;
}
return a;
}
/**
* Find lowest common multiple of the given two numbers.
*/
uint32_t no_os_lowest_common_multiple(uint32_t a, uint32_t b)
{
if (a && b)
return (a / no_os_greatest_common_divisor(a, b)) * b;
else
return 0;
}
/**
* Calculate best rational approximation for a given fraction.
*/
void no_os_rational_best_approximation(uint32_t given_numerator,
uint32_t given_denominator,
uint32_t max_numerator,
uint32_t max_denominator,
uint32_t *best_numerator,
uint32_t *best_denominator)
{
uint32_t gcd;
gcd = no_os_greatest_common_divisor(given_numerator, given_denominator);
*best_numerator = given_numerator / gcd;
*best_denominator = given_denominator / gcd;
if ((*best_numerator > max_numerator) ||
(*best_denominator > max_denominator)) {
*best_numerator = 0;
*best_denominator = 0;
}
}
void no_os_rational_best_approximation_u64(uint64_t given_numerator,
uint64_t given_denominator,
uint64_t max_numerator,
uint64_t max_denominator,
uint64_t *best_numerator,
uint64_t *best_denominator)
{
uint64_t gcd;
gcd = no_os_greatest_common_divisor_u64(given_numerator, given_denominator);
*best_numerator = given_numerator / gcd;
*best_denominator = given_denominator / gcd;
if ((*best_numerator > max_numerator) ||
(*best_denominator > max_denominator)) {
*best_numerator = 0;
*best_denominator = 0;
}
}
/**
* Calculate the number of set bits (8-bit size).
*/
unsigned int no_os_hweight8(uint8_t word)
{
uint32_t count = 0;
while (word) {
if (word & 0x1)
count++;
word >>= 1;
}
return count;
}
/**
* Calculate the number of set bits (16-bit size).
*/
unsigned int no_os_hweight16(uint16_t word)
{
return no_os_hweight8(word >> 8) +
no_os_hweight8(word);
}
/**
* Calculate the number of set bits (32-bit size).
*/
unsigned int no_os_hweight32(uint32_t word)
{
return no_os_hweight16(word >> 16) +
no_os_hweight16(word);
}
/**
* Calculate the quotient and the remainder of an integer division.
*/
uint64_t no_os_do_div(uint64_t* n,
uint64_t base)
{
uint64_t mod = 0;
mod = *n % base;
*n = *n / base;
return mod;
}
/**
* Unsigned 64bit divide with 64bit divisor and remainder
*/
uint64_t no_os_div64_u64_rem(uint64_t dividend, uint64_t divisor,
uint64_t *remainder)
{
*remainder = dividend % divisor;
return dividend / divisor;
}
/**
* Unsigned 64bit divide with 32bit divisor with remainder
*/
uint64_t no_os_div_u64_rem(uint64_t dividend, uint32_t divisor,
uint32_t *remainder)
{
*remainder = no_os_do_div(&dividend, divisor);
return dividend;
}
/**
* Signed 64bit divide with 32bit divisor with remainder
*/
int64_t no_os_div_s64_rem(int64_t dividend, int32_t divisor, int32_t *remainder)
{
*remainder = dividend % divisor;
return dividend / divisor;
}
/**
* Unsigned 64bit divide with 32bit divisor
*/
uint64_t no_os_div_u64(uint64_t dividend, uint32_t divisor)
{
uint32_t remainder;
return no_os_div_u64_rem(dividend, divisor, &remainder);
}
/**
* Signed 64bit divide with 32bit divisor
*/
int64_t no_os_div_s64(int64_t dividend, int32_t divisor)
{
int32_t remainder;
return no_os_div_s64_rem(dividend, divisor, &remainder);
}
/**
* Converts from string to int32_t
* @param *str
* @return int32_t
*/
int32_t no_os_str_to_int32(const char *str)
{
char *end;
int32_t value = strtol(str, &end, 0);
if (end == str)
return -EINVAL;
else
return value;
}
/**
* Converts from string to uint32_t
* @param *str
* @return uint32_t
*/
uint32_t no_os_str_to_uint32(const char *str)
{
char *end;
uint32_t value = strtoul(str, &end, 0);
if (end == str)
return -EINVAL;
else
return value;
}
void no_os_put_unaligned_be16(uint16_t val, uint8_t *buf)
{
buf[1] = val & 0xFF;
buf[0] = val >> 8;
}
uint16_t no_os_get_unaligned_be16(uint8_t *buf)
{
return buf[1] | ((uint16_t)buf[0] << 8);
}
void no_os_put_unaligned_le16(uint16_t val, uint8_t *buf)
{
buf[0] = val & 0xFF;
buf[1] = val >> 8;
}
uint16_t no_os_get_unaligned_le16(uint8_t *buf)
{
return buf[0] | ((uint16_t)buf[1] << 8);
}
void no_os_put_unaligned_be24(uint32_t val, uint8_t *buf)
{
buf[2] = val & 0xFF;
buf[1] = (val >> 8) & 0xFF;
buf[0] = val >> 16;
}
uint32_t no_os_get_unaligned_be24(uint8_t *buf)
{
return buf[2] | ((uint16_t)buf[1] << 8) | ((uint32_t)buf[0] << 16);
}
void no_os_put_unaligned_le24(uint32_t val, uint8_t *buf)
{
buf[0] = val & 0xFF;
buf[1] = (val >> 8) & 0xFF;
buf[2] = val >> 16;
}
uint32_t no_os_get_unaligned_le24(uint8_t *buf)
{
return buf[0] | ((uint16_t)buf[1] << 8) | ((uint32_t)buf[2] << 16);
}
void no_os_put_unaligned_be32(uint32_t val, uint8_t *buf)
{
buf[3] = val & 0xFF;
buf[2] = (val >> 8) & 0xFF;
buf[1] = (val >> 16) & 0xFF;
buf[0] = val >> 24;
}
uint32_t no_os_get_unaligned_be32(uint8_t *buf)
{
return buf[3] | ((uint16_t)buf[2] << 8) | ((uint32_t)buf[1] << 16)
| ((uint32_t)buf[0] << 24);
}
void no_os_put_unaligned_le32(uint32_t val, uint8_t *buf)
{
buf[0] = val & 0xFF;
buf[1] = (val >> 8) & 0xFF;
buf[2] = (val >> 16) & 0xFF;
buf[3] = val >> 24;
}
uint32_t no_os_get_unaligned_le32(uint8_t *buf)
{
return buf[0] | ((uint16_t)buf[1] << 8) | ((uint32_t)buf[2] << 16)
| ((uint32_t)buf[3] << 24);
}
int16_t no_os_sign_extend16(uint16_t value, int index)
{
uint8_t shift = 15 - index;
return (int16_t)(value << shift) >> shift;
}
int32_t no_os_sign_extend32(uint32_t value, int index)
{
uint8_t shift = 31 - index;
return (int32_t)(value << shift) >> shift;
}
uint64_t no_os_mul_u32_u32(uint32_t a, uint32_t b)
{
return (uint64_t)a * b;
}
uint64_t no_os_mul_u64_u32_shr(uint64_t a, uint32_t mul, unsigned int shift)
{
uint32_t ah, al;
uint64_t ret;
al = a;
ah = a >> 32;
ret = no_os_mul_u32_u32(al, mul) >> shift;
if (ah)
ret += no_os_mul_u32_u32(ah, mul) << (32 - shift);
return ret;
}
uint64_t no_os_mul_u64_u32_div(uint64_t a, uint32_t mul, uint32_t divisor)
{
int i;
uint64_t low, high, temp, rem;
uint32_t a_high = a >> 32;
uint32_t a_low = a & 0xFFFFFFFF;
uint64_t result = 0;
uint64_t low_low = no_os_mul_u32_u32(a_low, mul);
uint64_t high_low = no_os_mul_u32_u32(a_high, mul);
low = low_low + ((high_low & 0xFFFFFFFF) << 32);
high = (high_low >> 32) + (low_low >> 32);
rem = high;
for (i = 0; i < 64; i++) {
/* Shift remainder left and add the next bit from low */
rem = (rem << 1) | (low >> 63);
low <<= 1;
/* Compare the remainder with the divisor */
if (rem >= divisor) {
rem -= divisor;
temp = (uint64_t)1 << (63 - i);
result |= temp;
}
}
return result;
}
/**
* @brief Check big endianess of the host processor.
* @return Big endianess status (true/false)
*/
bool no_os_is_big_endian(void)
{
uint16_t a = 0x0100;
return (bool) * (uint8_t *)&a;
}
/* @brief Swap bytes in a buffer with a given step
* Swap with step of 2:
* AA BB CC DD EE FF 00 11 becomes
* BB AA DD CC FF EE 11 00
* Swap with step of 3:
* AA BB CC DD EE FF 00 11 22 becomes
* CC BB AA FF EE DD 22 11 00
* etc.
* @param buf - Input buffer to be swapped.
* @param bytes - Number of bytes.
* @param step - Number of steps.
* @return None
*/
void no_os_memswap64(void *buf, uint32_t bytes, uint32_t step)
{
uint8_t * p = buf;
uint32_t i, j;
uint8_t temp[8];
if (step < 2 || step > 8 || bytes < step || bytes % step != 0)
return;
for (i = 0; i < bytes; i += step) {
memcpy(temp, p, step);
for (j = step; j > 0; j--) {
*p++ = temp[j - 1];
}
}
}
@@ -0,0 +1,215 @@
/***************************************************************************//**
* @file no_os_util.h
* @brief Header file of utility functions.
* @author DBogdan (dragos.bogdan@analog.com)
********************************************************************************
* Copyright 2018(c) Analog Devices, Inc.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* 3. Neither the name of Analog Devices, Inc. nor the names of its
* contributors may be used to endorse or promote products derived from this
* software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY ANALOG DEVICES, INC. “AS IS” AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
* EVENT SHALL ANALOG DEVICES, INC. BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
* OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
* EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*******************************************************************************/
#ifndef _NO_OS_UTIL_H_
#define _NO_OS_UTIL_H_
#include <stdint.h>
#include <stdlib.h>
#include <stdbool.h>
#define NO_OS_BIT(x) (1 << (x))
#define NO_OS_BIT_ULL(x) ((uint64_t) 1 << (x))
#define NO_OS_ARRAY_SIZE(x) \
(sizeof(x) / sizeof((x)[0]))
#define NO_OS_DIV_ROUND_UP(x,y) \
(((x) + (y) - 1) / (y))
#define NO_OS_DIV_ROUND_CLOSEST(x, y) \
(((x) + (y) / 2) / (y))
#define NO_OS_DIV_ROUND_CLOSEST_ULL(x, y) \
NO_OS_DIV_ROUND_CLOSEST(x, y)
#define no_os_min(x, y) \
(((x) < (y)) ? (x) : (y))
#define no_os_min_t(type, x, y) \
(type)no_os_min((type)(x), (type)(y))
#define no_os_max(x, y) \
(((x) > (y)) ? (x) : (y))
#define no_os_max_t(type, x, y) \
(type)no_os_max((type)(x), (type)(y))
#define no_os_clamp(val, min_val, max_val) \
(no_os_max(no_os_min((val), (max_val)), (min_val)))
#define no_os_clamp_t(type, val, min_val, max_val) \
(type)no_os_clamp((type)(val), (type)(min_val), (type)(max_val))
#define no_os_swap(x, y) \
{typeof(x) _tmp_ = (x); (x) = (y); (y) = _tmp_;}
#define no_os_round_up(x,y) \
(((x)+(y)-1)/(y))
#define NO_OS_BITS_PER_LONG 32
#define NO_OS_GENMASK(h, l) ({ \
uint32_t t = (uint32_t)(~0UL); \
t = t << (NO_OS_BITS_PER_LONG - (h - l + 1)); \
t = t >> (NO_OS_BITS_PER_LONG - (h + 1)); \
t; \
})
#define NO_OS_GENMASK_ULL(h, l) ({ \
unsigned long long t = (unsigned long long)(~0ULL); \
t = t << (64 - (h - l + 1)); \
t = t >> (64 - (h + 1)); \
t; \
})
#define no_os_bswap_constant_32(x) \
((((x) & 0xff000000) >> 24) | (((x) & 0x00ff0000) >> 8) | \
(((x) & 0x0000ff00) << 8) | (((x) & 0x000000ff) << 24))
#define no_os_bswap_constant_16(x) ((((x) & (uint16_t)0xff00) >> 8) | \
(((x) & (uint16_t)0x00ff) << 8))
#define no_os_bit_swap_constant_8(x) \
((((x) & 0x80) >> 7) | \
(((x) & 0x40) >> 5) | \
(((x) & 0x20) >> 3) | \
(((x) & 0x10) >> 1) | \
(((x) & 0x08) << 1) | \
(((x) & 0x04) << 3) | \
(((x) & 0x02) << 5) | \
(((x) & 0x01) << 7))
#define NO_OS_U16_MAX ((uint16_t)~0U)
#define NO_OS_S16_MAX ((int16_t)(NO_OS_U16_MAX>>1))
#define NO_OS_DIV_U64(x, y) (x / y)
#define NO_OS_UNUSED_PARAM(x) ((void)x)
#define no_os_shift_right(x, s) ((x) < 0 ? -(-(x) >> (s)) : (x) >> (s))
#define no_os_align(x, align) (((x) + ((typeof(x))(align) - 1)) & ~((typeof(x))(align) - 1))
#define no_os_bcd2bin(x) (((x) & 0x0f) + ((x) >> 4) * 10)
#define no_os_bin2bcd(x) ((((x) / 10) << 4) + (x) % 10)
#define NO_OS_CONTAINER_OF(ptr, type, name) ((type *)((char *)(ptr) - offsetof(type, name)))
/* Check if bit set */
inline int no_os_test_bit(int pos, const volatile void * addr)
{
return (((const int *)addr)[pos / 32] >> pos) & 1UL;
}
/* Find first set bit in word. */
uint32_t no_os_find_first_set_bit(uint32_t word);
uint64_t no_os_find_first_set_bit_u64(uint64_t word);
/* Find last set bit in word. */
uint32_t no_os_find_last_set_bit(uint32_t word);
/* Locate the closest element in an array. */
uint32_t no_os_find_closest(int32_t val,
const int32_t *array,
uint32_t size);
/* Shift the value and apply the specified mask. */
uint32_t no_os_field_prep(uint32_t mask, uint32_t val);
uint64_t no_os_field_prep_u64(uint64_t mask, uint64_t val);
/* Get a field specified by a mask from a word. */
uint32_t no_os_field_get(uint32_t mask, uint32_t word);
/* Produce the maximum value representable by a field */
uint32_t no_os_field_max(uint32_t mask);
uint64_t no_os_field_max_u64(uint64_t mask);
/* Log base 2 of the given number. */
int32_t no_os_log_base_2(uint32_t x);
/* Find greatest common divisor of the given two numbers. */
uint32_t no_os_greatest_common_divisor(uint32_t a,
uint32_t b);
uint64_t no_os_greatest_common_divisor_u64(uint64_t a,
uint64_t b);
/* Find lowest common multiple of the given two numbers. */
uint32_t no_os_lowest_common_multiple(uint32_t a, uint32_t b);
/* Calculate best rational approximation for a given fraction. */
void no_os_rational_best_approximation(uint32_t given_numerator,
uint32_t given_denominator,
uint32_t max_numerator,
uint32_t max_denominator,
uint32_t *best_numerator,
uint32_t *best_denominator);
void no_os_rational_best_approximation_u64(uint64_t given_numerator,
uint64_t given_denominator,
uint64_t max_numerator,
uint64_t max_denominator,
uint64_t *best_numerator,
uint64_t *best_denominator);
/* Calculate the number of set bits (8-bit size). */
unsigned int no_os_hweight8(uint8_t word);
/* Calculate the number of set bits (16-bit size). */
unsigned int no_os_hweight16(uint16_t word);
/* Calculate the number of set bits (32-bit size). */
unsigned int no_os_hweight32(uint32_t word);
/* Calculate the quotient and the remainder of an integer division. */
uint64_t no_os_do_div(uint64_t* n,
uint64_t base);
/* Unsigned 64bit divide with 64bit divisor and remainder */
uint64_t no_os_div64_u64_rem(uint64_t dividend, uint64_t divisor,
uint64_t *remainder);
/* Unsigned 64bit divide with 32bit divisor with remainder */
uint64_t no_os_div_u64_rem(uint64_t dividend, uint32_t divisor,
uint32_t *remainder);
int64_t no_os_div_s64_rem(int64_t dividend, int32_t divisor,
int32_t *remainder);
/* Unsigned 64bit divide with 32bit divisor */
uint64_t no_os_div_u64(uint64_t dividend, uint32_t divisor);
int64_t no_os_div_s64(int64_t dividend, int32_t divisor);
/* Converts from string to int32_t */
int32_t no_os_str_to_int32(const char *str);
/* Converts from string to uint32_t */
uint32_t no_os_str_to_uint32(const char *str);
void no_os_put_unaligned_be16(uint16_t val, uint8_t *buf);
uint16_t no_os_get_unaligned_be16(uint8_t *buf);
void no_os_put_unaligned_le16(uint16_t val, uint8_t *buf);
uint16_t no_os_get_unaligned_le16(uint8_t *buf);
void no_os_put_unaligned_be24(uint32_t val, uint8_t *buf);
uint32_t no_os_get_unaligned_be24(uint8_t *buf);
void no_os_put_unaligned_le24(uint32_t val, uint8_t *buf);
uint32_t no_os_get_unaligned_le24(uint8_t *buf);
void no_os_put_unaligned_be32(uint32_t val, uint8_t *buf);
uint32_t no_os_get_unaligned_be32(uint8_t *buf);
void no_os_put_unaligned_le32(uint32_t val, uint8_t *buf);
uint32_t no_os_get_unaligned_le32(uint8_t *buf);
int16_t no_os_sign_extend16(uint16_t value, int index);
int32_t no_os_sign_extend32(uint32_t value, int index);
uint64_t no_os_mul_u32_u32(uint32_t a, uint32_t b);
uint64_t no_os_mul_u64_u32_shr(uint64_t a, uint32_t mul, unsigned int shift);
uint64_t no_os_mul_u64_u32_div(uint64_t a, uint32_t mul, uint32_t divisor);
bool no_os_is_big_endian(void);
void no_os_memswap64(void *buf, uint32_t bytes, uint32_t step);
#endif // _NO_OS_UTIL_H_
@@ -0,0 +1,42 @@
/***************************************************************************//**
* @file parameters.c
* @brief Definition of STM32 platform data used by adf4382 project.
* @author CHegbeli (ciprian.hegbeli@analog.com)
********************************************************************************
* Copyright 2023(c) Analog Devices, Inc.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* 3. Neither the name of Analog Devices, Inc. nor the names of its
* contributors may be used to endorse or promote products derived from this
* software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY ANALOG DEVICES, INC. “AS IS” AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
* EVENT SHALL ANALOG DEVICES, INC. BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
* OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
* EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*******************************************************************************/
#include "parameters.h"
struct stm32_uart_init_param adf4382_uart_extra_ip = {
.huart = &huart2,
};
struct stm32_spi_init_param adf4382_spi_extra_ip = {
.chip_select_port = SPI_CS_PORT,
};
@@ -0,0 +1,64 @@
/***************************************************************************//**
* @file parameters.h
* @brief Definition of STM32 platform data used by adf4382 project.
* @author CHegbeli (ciprian.hegbeli@analog.com))
********************************************************************************
* Copyright 2023(c) Analog Devices, Inc.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* 3. Neither the name of Analog Devices, Inc. nor the names of its
* contributors may be used to endorse or promote products derived from this
* software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY ANALOG DEVICES, INC. “AS IS” AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
* EVENT SHALL ANALOG DEVICES, INC. BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
* OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
* EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*******************************************************************************/
#ifndef __PARAMETERS_H__
#define __PARAMETERS_H__
#include "stm32_irq.h"
#include "stm32_spi.h"
#include "stm32_uart.h"
//#include "stm32_uart_stdio.h"
extern UART_HandleTypeDef huart2;
#ifdef IIO_SUPPORT
#define INTC_DEVICE_ID 0
#define IIO_APP_HUART (&huart2)
#endif
#define UART_IRQ_ID UART5_IRQn
#define UART_DEVICE_ID 2
#define UART_BAUDRATE 115200
#define UART_EXTRA &adf4382_uart_extra_ip
#define UART_OPS &stm32_uart_ops
#define SPI_DEVICE_ID 1
#define SPI_BAUDRATE 4000000
#define SPI_CS 0
#define SPI_CS_PORT 3
#define SPI_OPS &stm32_spi_ops
#define SPI_EXTRA &adf4382_spi_extra_ip
extern struct stm32_uart_init_param adf4382_uart_extra_ip;
extern struct stm32_spi_init_param adf4382_spi_extra_ip;
#endif /* __PARAMETERS_H__ */
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,336 @@
/*
* si5351.h - Si5351 library for Arduino
*
* Copyright (C) 2015 - 2019 Jason Milldrum <milldrum@gmail.com>
* Dana H. Myers <k6jq@comcast.net>
*
* Many defines derived from clk-si5351.h in the Linux kernel.
* Sebastian Hesselbarth <sebastian.hesselbarth@gmail.com>
* Rabeeh Khoury <rabeeh@solid-run.com>
*
* do_div() macro derived from /include/asm-generic/div64.h in
* the Linux kernel.
* Copyright (C) 2003 Bernardo Innocenti <bernie@develer.com>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef SI5351_H_
#define SI5351_H_
#include "main.h"
#include "stm32f7xx_hal.h"
#include "stm32f7xx_hal_i2c.h"
#include <stdint.h>
/* Define definitions */
#define SI5351_BUS_BASE_ADDR 0x60
#define SI5351_XTAL_FREQ 25000000
#define SI5351_PLL_FIXED 80000000000ULL
#define SI5351_FREQ_MULT 100ULL
#define SI5351_DEFAULT_CLK 1000000000ULL
#define SI5351_PLL_VCO_MIN 600000000
#define SI5351_PLL_VCO_MAX 900000000
#define SI5351_MULTISYNTH_MIN_FREQ 500000
#define SI5351_MULTISYNTH_DIVBY4_FREQ 150000000
#define SI5351_MULTISYNTH_MAX_FREQ 225000000
#define SI5351_MULTISYNTH_SHARE_MAX 100000000
#define SI5351_MULTISYNTH_SHARE_MIN 1024000
#define SI5351_MULTISYNTH67_MAX_FREQ SI5351_MULTISYNTH_DIVBY4_FREQ
#define SI5351_CLKOUT_MIN_FREQ 4000
#define SI5351_CLKOUT_MAX_FREQ SI5351_MULTISYNTH_MAX_FREQ
#define SI5351_CLKOUT67_MS_MIN SI5351_PLL_VCO_MIN / SI5351_MULTISYNTH67_A_MAX
#define SI5351_CLKOUT67_MIN_FREQ SI5351_CLKOUT67_MS_MIN / 128
#define SI5351_CLKOUT67_MAX_FREQ SI5351_MULTISYNTH67_MAX_FREQ
#define SI5351_PLL_A_MIN 15
#define SI5351_PLL_A_MAX 90
#define SI5351_PLL_B_MAX (SI5351_PLL_C_MAX-1)
#define SI5351_PLL_C_MAX 1048575
#define SI5351_MULTISYNTH_A_MIN 6
#define SI5351_MULTISYNTH_A_MAX 1800
#define SI5351_MULTISYNTH67_A_MAX 254
#define SI5351_MULTISYNTH_B_MAX (SI5351_MULTISYNTH_C_MAX-1)
#define SI5351_MULTISYNTH_C_MAX 1048575
#define SI5351_MULTISYNTH_P1_MAX ((1<<18)-1)
#define SI5351_MULTISYNTH_P2_MAX ((1<<20)-1)
#define SI5351_MULTISYNTH_P3_MAX ((1<<20)-1)
#define SI5351_VCXO_PULL_MIN 30
#define SI5351_VCXO_PULL_MAX 240
#define SI5351_VCXO_MARGIN 103
#define SI5351_DEVICE_STATUS 0
#define SI5351_INTERRUPT_STATUS 1
#define SI5351_INTERRUPT_MASK 2
#define SI5351_STATUS_SYS_INIT (1<<7)
#define SI5351_STATUS_LOL_B (1<<6)
#define SI5351_STATUS_LOL_A (1<<5)
#define SI5351_STATUS_LOS (1<<4)
#define SI5351_OUTPUT_ENABLE_CTRL 3
#define SI5351_OEB_PIN_ENABLE_CTRL 9
#define SI5351_PLL_INPUT_SOURCE 15
#define SI5351_CLKIN_DIV_MASK (3<<6)
#define SI5351_CLKIN_DIV_1 (0<<6)
#define SI5351_CLKIN_DIV_2 (1<<6)
#define SI5351_CLKIN_DIV_4 (2<<6)
#define SI5351_CLKIN_DIV_8 (3<<6)
#define SI5351_PLLB_SOURCE (1<<3)
#define SI5351_PLLA_SOURCE (1<<2)
#define SI5351_CLK0_CTRL 16
#define SI5351_CLK1_CTRL 17
#define SI5351_CLK2_CTRL 18
#define SI5351_CLK3_CTRL 19
#define SI5351_CLK4_CTRL 20
#define SI5351_CLK5_CTRL 21
#define SI5351_CLK6_CTRL 22
#define SI5351_CLK7_CTRL 23
#define SI5351_CLK_POWERDOWN (1<<7)
#define SI5351_CLK_INTEGER_MODE (1<<6)
#define SI5351_CLK_PLL_SELECT (1<<5)
#define SI5351_CLK_INVERT (1<<4)
#define SI5351_CLK_INPUT_MASK (3<<2)
#define SI5351_CLK_INPUT_XTAL (0<<2)
#define SI5351_CLK_INPUT_CLKIN (1<<2)
#define SI5351_CLK_INPUT_MULTISYNTH_0_4 (2<<2)
#define SI5351_CLK_INPUT_MULTISYNTH_N (3<<2)
#define SI5351_CLK_DRIVE_STRENGTH_MASK (3<<0)
#define SI5351_CLK_DRIVE_STRENGTH_2MA (0<<0)
#define SI5351_CLK_DRIVE_STRENGTH_4MA (1<<0)
#define SI5351_CLK_DRIVE_STRENGTH_6MA (2<<0)
#define SI5351_CLK_DRIVE_STRENGTH_8MA (3<<0)
#define SI5351_CLK3_0_DISABLE_STATE 24
#define SI5351_CLK7_4_DISABLE_STATE 25
#define SI5351_CLK_DISABLE_STATE_MASK 3
#define SI5351_CLK_DISABLE_STATE_LOW 0
#define SI5351_CLK_DISABLE_STATE_HIGH 1
#define SI5351_CLK_DISABLE_STATE_FLOAT 2
#define SI5351_CLK_DISABLE_STATE_NEVER 3
#define SI5351_PARAMETERS_LENGTH 8
#define SI5351_PLLA_PARAMETERS 26
#define SI5351_PLLB_PARAMETERS 34
#define SI5351_CLK0_PARAMETERS 42
#define SI5351_CLK1_PARAMETERS 50
#define SI5351_CLK2_PARAMETERS 58
#define SI5351_CLK3_PARAMETERS 66
#define SI5351_CLK4_PARAMETERS 74
#define SI5351_CLK5_PARAMETERS 82
#define SI5351_CLK6_PARAMETERS 90
#define SI5351_CLK7_PARAMETERS 91
#define SI5351_CLK6_7_OUTPUT_DIVIDER 92
#define SI5351_OUTPUT_CLK_DIV_MASK (7 << 4)
#define SI5351_OUTPUT_CLK6_DIV_MASK (7 << 0)
#define SI5351_OUTPUT_CLK_DIV_SHIFT 4
#define SI5351_OUTPUT_CLK_DIV6_SHIFT 0
#define SI5351_OUTPUT_CLK_DIV_1 0
#define SI5351_OUTPUT_CLK_DIV_2 1
#define SI5351_OUTPUT_CLK_DIV_4 2
#define SI5351_OUTPUT_CLK_DIV_8 3
#define SI5351_OUTPUT_CLK_DIV_16 4
#define SI5351_OUTPUT_CLK_DIV_32 5
#define SI5351_OUTPUT_CLK_DIV_64 6
#define SI5351_OUTPUT_CLK_DIV_128 7
#define SI5351_OUTPUT_CLK_DIVBY4 (3<<2)
#define SI5351_SSC_PARAM0 149
#define SI5351_SSC_PARAM1 150
#define SI5351_SSC_PARAM2 151
#define SI5351_SSC_PARAM3 152
#define SI5351_SSC_PARAM4 153
#define SI5351_SSC_PARAM5 154
#define SI5351_SSC_PARAM6 155
#define SI5351_SSC_PARAM7 156
#define SI5351_SSC_PARAM8 157
#define SI5351_SSC_PARAM9 158
#define SI5351_SSC_PARAM10 159
#define SI5351_SSC_PARAM11 160
#define SI5351_SSC_PARAM12 161
#define SI5351_VXCO_PARAMETERS_LOW 162
#define SI5351_VXCO_PARAMETERS_MID 163
#define SI5351_VXCO_PARAMETERS_HIGH 164
#define SI5351_CLK0_PHASE_OFFSET 165
#define SI5351_CLK1_PHASE_OFFSET 166
#define SI5351_CLK2_PHASE_OFFSET 167
#define SI5351_CLK3_PHASE_OFFSET 168
#define SI5351_CLK4_PHASE_OFFSET 169
#define SI5351_CLK5_PHASE_OFFSET 170
#define SI5351_PLL_RESET 177
#define SI5351_PLL_RESET_B (1<<7)
#define SI5351_PLL_RESET_A (1<<5)
#define SI5351_CRYSTAL_LOAD 183
#define SI5351_CRYSTAL_LOAD_MASK (3<<6)
#define SI5351_CRYSTAL_LOAD_0PF (0<<6)
#define SI5351_CRYSTAL_LOAD_6PF (1<<6)
#define SI5351_CRYSTAL_LOAD_8PF (2<<6)
#define SI5351_CRYSTAL_LOAD_10PF (3<<6)
#define SI5351_FANOUT_ENABLE 187
#define SI5351_CLKIN_ENABLE (1<<7)
#define SI5351_XTAL_ENABLE (1<<6)
#define SI5351_MULTISYNTH_ENABLE (1<<4)
/* Macro definitions */
//#define RFRAC_DENOM ((1L << 20) - 1)
#define RFRAC_DENOM 1000000ULL
/*
* Based on former asm-ppc/div64.h and asm-m68knommu/div64.h
*
* The semantics of do_div() are:
*
* uint32_t do_div(uint64_t *n, uint32_t base)
* {
* uint32_t remainder = *n % base;
* *n = *n / base;
* return remainder;
* }
*
* NOTE: macro parameter n is evaluated multiple times,
* beware of side effects!
*/
# define do_div(n,base) ({ \
uint64_t __base = (base); \
uint64_t __rem; \
__rem = ((uint64_t)(n)) % __base; \
(n) = ((uint64_t)(n)) / __base; \
__rem; \
})
/* Enum definitions */
/*
* enum si5351_variant - SiLabs Si5351 chip variant
* @SI5351_VARIANT_A: Si5351A (8 output clocks, XTAL input)
* @SI5351_VARIANT_A3: Si5351A MSOP10 (3 output clocks, XTAL input)
* @SI5351_VARIANT_B: Si5351B (8 output clocks, XTAL/VXCO input)
* @SI5351_VARIANT_C: Si5351C (8 output clocks, XTAL/CLKIN input)
*/
/*
enum si5351_variant {
SI5351_VARIANT_A = 1,
SI5351_VARIANT_A3 = 2,
SI5351_VARIANT_B = 3,
SI5351_VARIANT_C = 4,
};
*/
enum si5351_clock {SI5351_CLK0, SI5351_CLK1, SI5351_CLK2, SI5351_CLK3,
SI5351_CLK4, SI5351_CLK5, SI5351_CLK6, SI5351_CLK7};
enum si5351_pll {SI5351_PLLA, SI5351_PLLB};
enum si5351_drive {SI5351_DRIVE_2MA, SI5351_DRIVE_4MA, SI5351_DRIVE_6MA, SI5351_DRIVE_8MA};
enum si5351_clock_source {SI5351_CLK_SRC_XTAL, SI5351_CLK_SRC_CLKIN, SI5351_CLK_SRC_MS0, SI5351_CLK_SRC_MS};
enum si5351_clock_disable {SI5351_CLK_DISABLE_LOW, SI5351_CLK_DISABLE_HIGH, SI5351_CLK_DISABLE_HI_Z, SI5351_CLK_DISABLE_NEVER};
enum si5351_clock_fanout {SI5351_FANOUT_CLKIN, SI5351_FANOUT_XO, SI5351_FANOUT_MS};
enum si5351_pll_input {SI5351_PLL_INPUT_XO, SI5351_PLL_INPUT_CLKIN};
/* Struct definitions */
struct Si5351RegSet
{
uint32_t p1;
uint32_t p2;
uint32_t p3;
};
struct Si5351Status
{
uint8_t SYS_INIT;
uint8_t LOL_B;
uint8_t LOL_A;
uint8_t LOS;
uint8_t REVID;
};
struct Si5351IntStatus
{
uint8_t SYS_INIT_STKY;
uint8_t LOL_B_STKY;
uint8_t LOL_A_STKY;
uint8_t LOS_STKY;
};
class Si5351
{
public:
Si5351(uint8_t i2c_addr = SI5351_BUS_BASE_ADDR);
bool init(uint8_t, uint32_t, int32_t);
void reset(void);
uint8_t set_freq(uint64_t, enum si5351_clock);
uint8_t set_freq_manual(uint64_t, uint64_t, enum si5351_clock);
void set_pll(uint64_t, enum si5351_pll);
void set_ms(enum si5351_clock, struct Si5351RegSet, uint8_t, uint8_t, uint8_t);
void output_enable(enum si5351_clock, uint8_t);
void drive_strength(enum si5351_clock, enum si5351_drive);
void update_status(void);
void set_correction(int32_t, enum si5351_pll_input);
void set_phase(enum si5351_clock, uint8_t);
int32_t get_correction(enum si5351_pll_input);
void pll_reset(enum si5351_pll);
void set_ms_source(enum si5351_clock, enum si5351_pll);
void set_int(enum si5351_clock, uint8_t);
void set_clock_pwr(enum si5351_clock, uint8_t);
void set_clock_invert(enum si5351_clock, uint8_t);
void set_clock_source(enum si5351_clock, enum si5351_clock_source);
void set_clock_disable(enum si5351_clock, enum si5351_clock_disable);
void set_clock_fanout(enum si5351_clock_fanout, uint8_t);
void set_pll_input(enum si5351_pll, enum si5351_pll_input);
void set_vcxo(uint64_t, uint8_t);
void set_ref_freq(uint32_t, enum si5351_pll_input);
uint8_t si5351_write_bulk(uint8_t, uint8_t, uint8_t *);
uint8_t si5351_write(uint8_t, uint8_t);
uint8_t si5351_read(uint8_t);
struct Si5351Status dev_status = {.SYS_INIT = 0, .LOL_B = 0, .LOL_A = 0,
.LOS = 0, .REVID = 0};
struct Si5351IntStatus dev_int_status = {.SYS_INIT_STKY = 0, .LOL_B_STKY = 0,
.LOL_A_STKY = 0, .LOS_STKY = 0};
enum si5351_pll pll_assignment[8];
uint64_t clk_freq[8];
uint64_t plla_freq;
uint64_t pllb_freq;
enum si5351_pll_input plla_ref_osc;
enum si5351_pll_input pllb_ref_osc;
uint32_t xtal_freq[2];
private:
uint64_t pll_calc(enum si5351_pll, uint64_t, struct Si5351RegSet *, int32_t, uint8_t);
uint64_t multisynth_calc(uint64_t, uint64_t, struct Si5351RegSet *);
uint64_t multisynth67_calc(uint64_t, uint64_t, struct Si5351RegSet *);
void update_sys_status(struct Si5351Status *);
void update_int_status(struct Si5351IntStatus *);
void ms_div(enum si5351_clock, uint8_t, uint8_t);
uint8_t select_r_div(uint64_t *);
uint8_t select_r_div_ms67(uint64_t *);
int32_t ref_correction[2];
uint8_t clkin_div;
uint8_t i2c_bus_addr;
bool clk_first_set[8];
};
#endif /* SI5351_H_ */