From b17e29e8109ffb225a8ee361860bd17e0ab53789 Mon Sep 17 00:00:00 2001 From: NawfalMotii79 Date: Thu, 19 Mar 2026 01:21:46 +0000 Subject: [PATCH] Add files via upload --- .../Firmware/Microcontroller/RADAR_C_Cpp.ioc | 255 ++ .../Microcontroller/STM32F746ZGTX_FLASH.ld | 185 ++ .../Microcontroller/STM32F746ZGTX_RAM.ld | 185 ++ .../Firmware/Microcontroller/adar1000.c | 693 ++++++ .../Firmware/Microcontroller/adar1000.h | 296 +++ .../Firmware/Microcontroller/adf4382.c | 2205 +++++++++++++++++ .../Firmware/Microcontroller/adf4382.h | 803 ++++++ .../Microcontroller/hardware_config.h | 43 + .../Firmware/Microcontroller/iio.c | 2039 +++++++++++++++ .../Firmware/Microcontroller/iio.h | 143 ++ .../Firmware/Microcontroller/iio_adf4382.c | 733 ++++++ .../Firmware/Microcontroller/iio_adf4382.h | 76 + .../Firmware/Microcontroller/iio_app.c | 475 ++++ .../Firmware/Microcontroller/iio_app.h | 138 ++ .../Firmware/Microcontroller/iio_trigger.c | 227 ++ .../Firmware/Microcontroller/iio_trigger.h | 138 ++ .../Firmware/Microcontroller/iio_types.h | 280 +++ .../Firmware/Microcontroller/iiod.c | 927 +++++++ .../Firmware/Microcontroller/iiod.h | 192 ++ .../Firmware/Microcontroller/iiod_private.h | 178 ++ .../Firmware/Microcontroller/jesd204.h | 295 +++ .../Firmware/Microcontroller/main.cpp | 906 +++++++ .../Firmware/Microcontroller/main.h | 70 + .../Firmware/Microcontroller/no_os_ain.h | 70 + .../Firmware/Microcontroller/no_os_alloc.c | 67 + .../Firmware/Microcontroller/no_os_alloc.h | 49 + .../Firmware/Microcontroller/no_os_aout.h | 78 + .../Firmware/Microcontroller/no_os_axi_io.h | 45 + .../Microcontroller/no_os_circular_buffer.c | 390 +++ .../Microcontroller/no_os_circular_buffer.h | 94 + .../Firmware/Microcontroller/no_os_clk.c | 193 ++ .../Firmware/Microcontroller/no_os_clk.h | 128 + .../Firmware/Microcontroller/no_os_crc.h | 40 + .../Firmware/Microcontroller/no_os_crc16.c | 97 + .../Firmware/Microcontroller/no_os_crc16.h | 49 + .../Firmware/Microcontroller/no_os_crc24.c | 98 + .../Firmware/Microcontroller/no_os_crc24.h | 49 + .../Firmware/Microcontroller/no_os_crc8.c | 94 + .../Firmware/Microcontroller/no_os_crc8.h | 48 + .../Firmware/Microcontroller/no_os_delay.h | 56 + .../Firmware/Microcontroller/no_os_dma.c | 449 ++++ .../Firmware/Microcontroller/no_os_dma.h | 265 ++ .../Firmware/Microcontroller/no_os_eeprom.c | 119 + .../Firmware/Microcontroller/no_os_eeprom.h | 99 + .../Firmware/Microcontroller/no_os_error.h | 48 + .../Firmware/Microcontroller/no_os_fifo.c | 126 + .../Firmware/Microcontroller/no_os_fifo.h | 58 + .../Firmware/Microcontroller/no_os_flash.h | 96 + .../Firmware/Microcontroller/no_os_font_8x8.c | 166 ++ .../Firmware/Microcontroller/no_os_gpio.c | 231 ++ .../Firmware/Microcontroller/no_os_gpio.h | 166 ++ .../Firmware/Microcontroller/no_os_i2c.c | 209 ++ .../Firmware/Microcontroller/no_os_i2c.h | 146 ++ .../Firmware/Microcontroller/no_os_i3c.c | 698 ++++++ .../Firmware/Microcontroller/no_os_i3c.h | 396 +++ .../Firmware/Microcontroller/no_os_init.h | 38 + .../Firmware/Microcontroller/no_os_irq.c | 265 ++ .../Firmware/Microcontroller/no_os_irq.h | 235 ++ .../Microcontroller/no_os_lf256fifo.c | 148 ++ .../Microcontroller/no_os_lf256fifo.h | 53 + .../Firmware/Microcontroller/no_os_list.c | 871 +++++++ .../Firmware/Microcontroller/no_os_list.h | 309 +++ .../Firmware/Microcontroller/no_os_mdio.c | 119 + .../Firmware/Microcontroller/no_os_mdio.h | 107 + .../Firmware/Microcontroller/no_os_mutex.c | 63 + .../Firmware/Microcontroller/no_os_mutex.h | 78 + .../Firmware/Microcontroller/no_os_pid.c | 202 ++ .../Firmware/Microcontroller/no_os_pid.h | 79 + .../Microcontroller/no_os_print_log.h | 132 + .../Firmware/Microcontroller/no_os_pwm.c | 273 ++ .../Firmware/Microcontroller/no_os_pwm.h | 190 ++ .../Firmware/Microcontroller/no_os_rtc.h | 91 + .../Microcontroller/no_os_semaphore.c | 63 + .../Microcontroller/no_os_semaphore.h | 48 + .../Firmware/Microcontroller/no_os_sin_lut.c | 68 + .../Firmware/Microcontroller/no_os_spi.c | 278 +++ .../Firmware/Microcontroller/no_os_spi.h | 275 ++ .../Firmware/Microcontroller/no_os_tdm.c | 125 + .../Firmware/Microcontroller/no_os_tdm.h | 152 ++ .../Firmware/Microcontroller/no_os_timer.c | 213 ++ .../Firmware/Microcontroller/no_os_timer.h | 145 ++ .../Firmware/Microcontroller/no_os_trng.c | 98 + .../Firmware/Microcontroller/no_os_trng.h | 97 + .../Firmware/Microcontroller/no_os_uart.c | 220 ++ .../Firmware/Microcontroller/no_os_uart.h | 191 ++ .../Firmware/Microcontroller/no_os_units.h | 83 + .../Firmware/Microcontroller/no_os_util.c | 568 +++++ .../Firmware/Microcontroller/no_os_util.h | 215 ++ .../Firmware/Microcontroller/parameters.c | 42 + .../Firmware/Microcontroller/parameters.h | 64 + .../Firmware/Microcontroller/si5351.cpp | 1808 ++++++++++++++ .../Firmware/Microcontroller/si5351.h | 336 +++ 92 files changed, 24741 insertions(+) create mode 100644 14_RADAR_Old_version/Firmware/Microcontroller/RADAR_C_Cpp.ioc create mode 100644 14_RADAR_Old_version/Firmware/Microcontroller/STM32F746ZGTX_FLASH.ld create mode 100644 14_RADAR_Old_version/Firmware/Microcontroller/STM32F746ZGTX_RAM.ld create mode 100644 14_RADAR_Old_version/Firmware/Microcontroller/adar1000.c create mode 100644 14_RADAR_Old_version/Firmware/Microcontroller/adar1000.h create mode 100644 14_RADAR_Old_version/Firmware/Microcontroller/adf4382.c create mode 100644 14_RADAR_Old_version/Firmware/Microcontroller/adf4382.h create mode 100644 14_RADAR_Old_version/Firmware/Microcontroller/hardware_config.h create mode 100644 14_RADAR_Old_version/Firmware/Microcontroller/iio.c create mode 100644 14_RADAR_Old_version/Firmware/Microcontroller/iio.h create mode 100644 14_RADAR_Old_version/Firmware/Microcontroller/iio_adf4382.c create mode 100644 14_RADAR_Old_version/Firmware/Microcontroller/iio_adf4382.h create mode 100644 14_RADAR_Old_version/Firmware/Microcontroller/iio_app.c create mode 100644 14_RADAR_Old_version/Firmware/Microcontroller/iio_app.h create mode 100644 14_RADAR_Old_version/Firmware/Microcontroller/iio_trigger.c create mode 100644 14_RADAR_Old_version/Firmware/Microcontroller/iio_trigger.h create mode 100644 14_RADAR_Old_version/Firmware/Microcontroller/iio_types.h create mode 100644 14_RADAR_Old_version/Firmware/Microcontroller/iiod.c create mode 100644 14_RADAR_Old_version/Firmware/Microcontroller/iiod.h create mode 100644 14_RADAR_Old_version/Firmware/Microcontroller/iiod_private.h create mode 100644 14_RADAR_Old_version/Firmware/Microcontroller/jesd204.h create mode 100644 14_RADAR_Old_version/Firmware/Microcontroller/main.cpp create mode 100644 14_RADAR_Old_version/Firmware/Microcontroller/main.h create mode 100644 14_RADAR_Old_version/Firmware/Microcontroller/no_os_ain.h create mode 100644 14_RADAR_Old_version/Firmware/Microcontroller/no_os_alloc.c create mode 100644 14_RADAR_Old_version/Firmware/Microcontroller/no_os_alloc.h create mode 100644 14_RADAR_Old_version/Firmware/Microcontroller/no_os_aout.h create mode 100644 14_RADAR_Old_version/Firmware/Microcontroller/no_os_axi_io.h create mode 100644 14_RADAR_Old_version/Firmware/Microcontroller/no_os_circular_buffer.c create mode 100644 14_RADAR_Old_version/Firmware/Microcontroller/no_os_circular_buffer.h create mode 100644 14_RADAR_Old_version/Firmware/Microcontroller/no_os_clk.c create mode 100644 14_RADAR_Old_version/Firmware/Microcontroller/no_os_clk.h create mode 100644 14_RADAR_Old_version/Firmware/Microcontroller/no_os_crc.h create mode 100644 14_RADAR_Old_version/Firmware/Microcontroller/no_os_crc16.c create mode 100644 14_RADAR_Old_version/Firmware/Microcontroller/no_os_crc16.h create mode 100644 14_RADAR_Old_version/Firmware/Microcontroller/no_os_crc24.c create mode 100644 14_RADAR_Old_version/Firmware/Microcontroller/no_os_crc24.h create mode 100644 14_RADAR_Old_version/Firmware/Microcontroller/no_os_crc8.c create mode 100644 14_RADAR_Old_version/Firmware/Microcontroller/no_os_crc8.h create mode 100644 14_RADAR_Old_version/Firmware/Microcontroller/no_os_delay.h create mode 100644 14_RADAR_Old_version/Firmware/Microcontroller/no_os_dma.c create mode 100644 14_RADAR_Old_version/Firmware/Microcontroller/no_os_dma.h create mode 100644 14_RADAR_Old_version/Firmware/Microcontroller/no_os_eeprom.c create mode 100644 14_RADAR_Old_version/Firmware/Microcontroller/no_os_eeprom.h create mode 100644 14_RADAR_Old_version/Firmware/Microcontroller/no_os_error.h create mode 100644 14_RADAR_Old_version/Firmware/Microcontroller/no_os_fifo.c create mode 100644 14_RADAR_Old_version/Firmware/Microcontroller/no_os_fifo.h create mode 100644 14_RADAR_Old_version/Firmware/Microcontroller/no_os_flash.h create mode 100644 14_RADAR_Old_version/Firmware/Microcontroller/no_os_font_8x8.c create mode 100644 14_RADAR_Old_version/Firmware/Microcontroller/no_os_gpio.c create mode 100644 14_RADAR_Old_version/Firmware/Microcontroller/no_os_gpio.h create mode 100644 14_RADAR_Old_version/Firmware/Microcontroller/no_os_i2c.c create mode 100644 14_RADAR_Old_version/Firmware/Microcontroller/no_os_i2c.h create mode 100644 14_RADAR_Old_version/Firmware/Microcontroller/no_os_i3c.c create mode 100644 14_RADAR_Old_version/Firmware/Microcontroller/no_os_i3c.h create mode 100644 14_RADAR_Old_version/Firmware/Microcontroller/no_os_init.h create mode 100644 14_RADAR_Old_version/Firmware/Microcontroller/no_os_irq.c create mode 100644 14_RADAR_Old_version/Firmware/Microcontroller/no_os_irq.h create mode 100644 14_RADAR_Old_version/Firmware/Microcontroller/no_os_lf256fifo.c create mode 100644 14_RADAR_Old_version/Firmware/Microcontroller/no_os_lf256fifo.h create mode 100644 14_RADAR_Old_version/Firmware/Microcontroller/no_os_list.c create mode 100644 14_RADAR_Old_version/Firmware/Microcontroller/no_os_list.h create mode 100644 14_RADAR_Old_version/Firmware/Microcontroller/no_os_mdio.c create mode 100644 14_RADAR_Old_version/Firmware/Microcontroller/no_os_mdio.h create mode 100644 14_RADAR_Old_version/Firmware/Microcontroller/no_os_mutex.c create mode 100644 14_RADAR_Old_version/Firmware/Microcontroller/no_os_mutex.h create mode 100644 14_RADAR_Old_version/Firmware/Microcontroller/no_os_pid.c create mode 100644 14_RADAR_Old_version/Firmware/Microcontroller/no_os_pid.h create mode 100644 14_RADAR_Old_version/Firmware/Microcontroller/no_os_print_log.h create mode 100644 14_RADAR_Old_version/Firmware/Microcontroller/no_os_pwm.c create mode 100644 14_RADAR_Old_version/Firmware/Microcontroller/no_os_pwm.h create mode 100644 14_RADAR_Old_version/Firmware/Microcontroller/no_os_rtc.h create mode 100644 14_RADAR_Old_version/Firmware/Microcontroller/no_os_semaphore.c create mode 100644 14_RADAR_Old_version/Firmware/Microcontroller/no_os_semaphore.h create mode 100644 14_RADAR_Old_version/Firmware/Microcontroller/no_os_sin_lut.c create mode 100644 14_RADAR_Old_version/Firmware/Microcontroller/no_os_spi.c create mode 100644 14_RADAR_Old_version/Firmware/Microcontroller/no_os_spi.h create mode 100644 14_RADAR_Old_version/Firmware/Microcontroller/no_os_tdm.c create mode 100644 14_RADAR_Old_version/Firmware/Microcontroller/no_os_tdm.h create mode 100644 14_RADAR_Old_version/Firmware/Microcontroller/no_os_timer.c create mode 100644 14_RADAR_Old_version/Firmware/Microcontroller/no_os_timer.h create mode 100644 14_RADAR_Old_version/Firmware/Microcontroller/no_os_trng.c create mode 100644 14_RADAR_Old_version/Firmware/Microcontroller/no_os_trng.h create mode 100644 14_RADAR_Old_version/Firmware/Microcontroller/no_os_uart.c create mode 100644 14_RADAR_Old_version/Firmware/Microcontroller/no_os_uart.h create mode 100644 14_RADAR_Old_version/Firmware/Microcontroller/no_os_units.h create mode 100644 14_RADAR_Old_version/Firmware/Microcontroller/no_os_util.c create mode 100644 14_RADAR_Old_version/Firmware/Microcontroller/no_os_util.h create mode 100644 14_RADAR_Old_version/Firmware/Microcontroller/parameters.c create mode 100644 14_RADAR_Old_version/Firmware/Microcontroller/parameters.h create mode 100644 14_RADAR_Old_version/Firmware/Microcontroller/si5351.cpp create mode 100644 14_RADAR_Old_version/Firmware/Microcontroller/si5351.h diff --git a/14_RADAR_Old_version/Firmware/Microcontroller/RADAR_C_Cpp.ioc b/14_RADAR_Old_version/Firmware/Microcontroller/RADAR_C_Cpp.ioc new file mode 100644 index 0000000..9d82d93 --- /dev/null +++ b/14_RADAR_Old_version/Firmware/Microcontroller/RADAR_C_Cpp.ioc @@ -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 diff --git a/14_RADAR_Old_version/Firmware/Microcontroller/STM32F746ZGTX_FLASH.ld b/14_RADAR_Old_version/Firmware/Microcontroller/STM32F746ZGTX_FLASH.ld new file mode 100644 index 0000000..77fd4d6 --- /dev/null +++ b/14_RADAR_Old_version/Firmware/Microcontroller/STM32F746ZGTX_FLASH.ld @@ -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) } +} diff --git a/14_RADAR_Old_version/Firmware/Microcontroller/STM32F746ZGTX_RAM.ld b/14_RADAR_Old_version/Firmware/Microcontroller/STM32F746ZGTX_RAM.ld new file mode 100644 index 0000000..2c62b0d --- /dev/null +++ b/14_RADAR_Old_version/Firmware/Microcontroller/STM32F746ZGTX_RAM.ld @@ -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) } +} diff --git a/14_RADAR_Old_version/Firmware/Microcontroller/adar1000.c b/14_RADAR_Old_version/Firmware/Microcontroller/adar1000.c new file mode 100644 index 0000000..eeac0a4 --- /dev/null +++ b/14_RADAR_Old_version/Firmware/Microcontroller/adar1000.c @@ -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< +#include +#include + +#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_ */ + diff --git a/14_RADAR_Old_version/Firmware/Microcontroller/adf4382.c b/14_RADAR_Old_version/Firmware/Microcontroller/adf4382.c new file mode 100644 index 0000000..42d38c0 --- /dev/null +++ b/14_RADAR_Old_version/Firmware/Microcontroller/adf4382.c @@ -0,0 +1,2205 @@ +/***************************************************************************//** + * @file adf4382.c + * @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. +*******************************************************************************/ + +#include "adf4382.h" +#include "no_os_alloc.h" +#include "no_os_delay.h" +#include "no_os_error.h" +#include "no_os_print_log.h" +#include "no_os_util.h" + +/* Charge pump current values expressed in uA */ +static const int adf4382_ci_ua[] = { + 700, + 900, + 1100, + 1300, + 1400, + 1800, + 2200, + 2500, + 2900, + 3600, + 4300, + 5000, + 5800, + 7200, + 8600, + 11100 +}; + +/** + * @brief Writes data to ADF4382 over SPI. + * @param dev - The device structure. + * @param reg_addr - The register address. + * @param data - Data value to write. + * @return - 0 in case of success or negative error code otherwise. + */ +int adf4382_spi_write(struct adf4382_dev *dev, uint16_t reg_addr, uint8_t data) +{ + uint8_t buff[ADF4382_BUFF_SIZE_BYTES]; + uint16_t cmd; + + if (!dev) + return -EINVAL; + + cmd = ADF4382_SPI_WRITE_CMD | reg_addr; + if (dev->spi_desc->bit_order) { + buff[0] = no_os_bit_swap_constant_8(cmd & 0xFF); + buff[1] = no_os_bit_swap_constant_8(cmd >> 8); + buff[2] = no_os_bit_swap_constant_8(data); + } else { + buff[0] = cmd >> 8; + buff[1] = cmd & 0xFF; + buff[2] = data; + } + + return no_os_spi_write_and_read(dev->spi_desc, buff, + ADF4382_BUFF_SIZE_BYTES); +} + +/** + * @brief Reads data from ADF4382 over SPI. + * @param dev - The device structure. + * @param reg_addr - The register address. + * @param data - Data read from the device. + * @return - 0 in case of success or negative error code otherwise. + */ +int adf4382_spi_read(struct adf4382_dev *dev, uint16_t reg_addr, uint8_t *data) +{ + int ret; + uint8_t buff[ADF4382_BUFF_SIZE_BYTES]; + uint16_t cmd; + + if (!dev) + return -EINVAL; + + cmd = ADF4382_SPI_READ_CMD | reg_addr; + if (dev->spi_desc->bit_order) { + buff[0] = no_os_bit_swap_constant_8(cmd & 0xFF); + buff[1] = no_os_bit_swap_constant_8(cmd >> 8); + buff[2] = no_os_bit_swap_constant_8(ADF4382_SPI_DUMMY_DATA); + } else { + buff[0] = cmd >> 8; + buff[1] = cmd & 0xFF; + buff[2] = ADF4382_SPI_DUMMY_DATA; + } + + ret = no_os_spi_write_and_read(dev->spi_desc, buff, + ADF4382_BUFF_SIZE_BYTES); + if (ret) + return ret; + + *data = buff[2]; + + return 0; +} + +/** + * @brief Updates the values of the ADF4382 register. + * @param dev - The device structure. + * @param reg_addr - The register address. + * @param mask - Bits to be updated. + * @param data - Update value for the mask. + * @return - 0 in case of success or negative error code otherwise. + */ +int adf4382_spi_update_bits(struct adf4382_dev *dev, uint16_t reg_addr, + uint8_t mask, uint8_t data) +{ + uint8_t tmp, orig; + int ret; + + ret = adf4382_spi_read(dev, reg_addr, &orig); + if (ret) + return ret; + + tmp = orig & ~mask; + tmp |= data & mask; + + if (tmp != orig) + return adf4382_spi_write(dev, reg_addr, tmp); + + return 0; +} + +/** + * @brief Will output on the terminal the values of all the ADF4382 registers. + * @param dev - The device structure. + * @return - 0 in case of success or negative error code. + */ +int adf4382_reg_dump(struct adf4382_dev *dev) +{ + uint8_t val; + uint16_t i; + int ret; + + for (i = 0; i < 0x68; i++) { + ret = adf4382_spi_read(dev, i, &val); + if (ret) + return ret; + + pr_info("0x%X 0x%X\n", i, val); + } + + for (i = 0x100; i < 0x112; i++) { + ret = adf4382_spi_read(dev, i, &val); + if (ret) + return ret; + + pr_info("0x%X 0x%X\n", i, val); + } + + for (i = 0x200; i < 0x274; i++) { + ret = adf4382_spi_read(dev, i, &val); + if (ret) + return ret; + + pr_info("0x%X 0x%X\n", i, val); + } + + return ret; +} + +/** + * @brief Set the desired reference frequency and reset everything over to maximum + * supported value of 5GHz to the max. value and everything under the minimum + * supported value of 10MHz to the min. value. + * @param dev - The device structure. + * @param val - The desired reference frequency in Hz. + * @return - 0 in case of success or negative error code. + */ +int adf4382_set_ref_clk(struct adf4382_dev *dev, uint64_t val) +{ + if (!dev) + return -EINVAL; + + dev->ref_freq_hz = val; + + if (val > ADF4382_REF_CLK_MAX) + dev->ref_freq_hz = ADF4382_REF_CLK_MAX; + + if (val < ADF4382_REF_CLK_MIN) + dev->ref_freq_hz = ADF4382_REF_CLK_MIN; + + return adf4382_set_freq(dev); +} + +/** + * @brief Gets the user proposed reference frequency + * @param dev - The device structure. + * @param val - The set value of the reference frequency in Hz. + * @return - Reference frequency in KHz. + */ +int adf4382_get_ref_clk(struct adf4382_dev *dev, uint64_t *val) +{ + if (!dev) + return -EINVAL; + + *val = dev->ref_freq_hz; + + return 0; +} + +/** + * @brief Set the reference doubler to enable or disable based on the passed + * parameter. If the parameter is different then 0 it will set the doubler to + * enable. + * @param dev - The device structure. + * @param en - The enable or disable value of the reference doubler. + * @return - 0 in case of success or negative error code. + */ +int adf4382_set_en_ref_doubler(struct adf4382_dev *dev, bool en) +{ + if (!dev) + return -EINVAL; + + dev->ref_doubler_en = en; + + return adf4382_set_freq(dev); +} + +/** + * @brief Gets the value the doubler if it is enabled or disable and stores it + * it the dev structure. + * @param dev - The device structure. + * @param en - The read value of the reference doubler. + * @return - 0 in case of success or negative error code. + */ +int adf4382_get_en_ref_doubler(struct adf4382_dev *dev, bool *en) +{ + uint8_t tmp; + int ret; + + ret = adf4382_spi_read(dev, 0x20, &tmp); + if (ret) + return ret; + + dev->ref_doubler_en = no_os_field_get(tmp, ADF4382_EN_RDBLR_MSK); + *en = dev->ref_doubler_en; + + return 0; +} + +/** + * @brief Set the reference divider value and reset everything over to maximum + * supported value of 63 to the max. value + * @param dev - The device structure. + * @param div - The reference divider value. + * @return - 0 in case of success or negative error code. + */ +int adf4382_set_ref_div(struct adf4382_dev *dev, int32_t div) +{ + if (!dev) + return -EINVAL; + + dev->ref_div = div; + + if (div > ADF4382_REF_DIV_MAX) + dev->ref_div = ADF4382_REF_DIV_MAX; + + return adf4382_set_freq(dev); +} + +/** + * @brief Gets the value the reference divider. + * @param dev - The device structure. + * @param div - The read reference divider value. + * @return - Result of the reading procedure, error code otherwise. + */ +int adf4382_get_ref_div(struct adf4382_dev *dev, int32_t *div) +{ + uint8_t tmp; + int ret; + + ret = adf4382_spi_read(dev, 0x20, &tmp); + if (ret) + return ret; + + dev->ref_div = no_os_field_get(ADF4382_R_DIV_MSK, tmp); + *div = dev->ref_div; + + return 0; +} + +/** + * @brief Set the charge pump value which will be written to the register. The + * value will be between 0 and 15 on 8 bits. For more information please + * consult the Datasheet. + * @param dev - The device structure. + * @param reg_val - The desired charge pump register value. + * @return - 0 in case of success or negative error code. + */ +int adf4382_set_cp_i(struct adf4382_dev *dev, int32_t reg_val) +{ + if (!dev) + return -EINVAL; + + dev->cp_i = (uint8_t)reg_val; + + if (reg_val > ADF4382_CPI_VAL_MAX) + dev->cp_i = ADF4382_CPI_VAL_MAX; + + return adf4382_set_freq(dev); +} + +/** + * @brief Gets the charge pump value from the register. The value will be + * between 0 and 15 on 8 bits. For more information please consult the + * Datasheet. + * @param dev - The device structure. + * @param reg_val - The read charge pump register value. + * @return - 0 in case of success or negative error code. + */ +int adf4382_get_cp_i(struct adf4382_dev *dev, int32_t *reg_val) +{ + uint8_t tmp; + int ret; + + ret = adf4382_spi_read(dev, 0x1F, &tmp); + if (ret) + return ret; + + dev->cp_i = no_os_field_get(ADF4382_CP_I_MSK, tmp); + *reg_val = dev->cp_i; + + return 0; +} + +/** + * @brief Set the bleed word, which represents the value of the bleed current + * written to the register space. + * @param dev - The device structure. + * @param word - The bleed current register value. + * @return - 0 in case of success or negative error code. + */ +int adf4382_set_bleed_word(struct adf4382_dev *dev, int32_t word) +{ + if (!dev) + return -EINVAL; + + dev->bleed_word = (uint16_t)word; + + if (word > ADF4382_BLEED_WORD_MAX) + dev->bleed_word = ADF4382_BLEED_WORD_MAX; + + return adf4382_set_freq(dev); +} + +/** + * @brief Gets the value of the set bleed word. + * @param dev - The device structure. + * @param word - The read bleed current register value. + * @return - Result of the reading procedure, error code otherwise. + */ +int adf4382_get_bleed_word(struct adf4382_dev *dev, int32_t *word) +{ + uint8_t upper; + uint8_t lower; + int ret; + + ret = adf4382_spi_read(dev, 0x1E, &upper); + if (ret) + return ret; + + upper &= (ADF4382_COARSE_BLEED_MSK | ADF4382_FINE_BLEED_MSB_MSK); + + ret = adf4382_spi_read(dev, 0x1D, &lower); + if (ret) + return ret; + + dev->bleed_word = (upper << 8) | lower; + *word = dev->bleed_word; + + return 0; +} + +/** + * @brief Set the output power register value of a channel and reset everything + * over to maximum supported value of 15 to the max. value. + * @param dev - The device structure. + * @param ch - The channel to set the power off. + * @param pwr - The output power register value. + * @return - Result of the writing procedure, error code otherwise. + */ +int adf4382_set_out_power(struct adf4382_dev *dev, uint8_t ch, int32_t pwr) +{ + uint8_t tmp; + + if (pwr > ADF4382_OUT_PWR_MAX) + pwr = ADF4382_OUT_PWR_MAX; + + if (!ch) { + tmp = no_os_field_prep(ADF4382_CLK1_OPWR_MSK, pwr); + return adf4382_spi_update_bits(dev, 0x29, ADF4382_CLK1_OPWR_MSK, + tmp); + } + + tmp = no_os_field_prep(ADF4382_CLK2_OPWR_MSK, pwr); + return adf4382_spi_update_bits(dev, 0x29, ADF4382_CLK2_OPWR_MSK, tmp); +} + +/** + * @brief Gets the output power register value. + * @param dev - The device structure. + * @param ch - The channel to get the power off. + * @param pwr - The output power register value. + * @return - Result of the reading procedure, error code otherwise. + */ +int adf4382_get_out_power(struct adf4382_dev *dev, uint8_t ch, int32_t *pwr) +{ + + uint8_t tmp; + int ret; + + ret = adf4382_spi_read(dev, 0x29, &tmp); + if (ret) + return ret; + + if (!ch) + *pwr = no_os_field_get(ADF4382_CLK1_OPWR_MSK, tmp); + else + *pwr = no_os_field_get(ADF4382_CLK2_OPWR_MSK, tmp); + + return 0; +} + +/** + * @brief Set the output channel to enable or disable based on the passed + * parameter. If the parameter is different then 0 it will set the doubler to + * enable. + * @param dev - The device structure. + * @param ch - The channel to set state. + * @param en - The enable or disable value of the output channel. + * @return - Result of the writing procedure, error code otherwise. + */ +int adf4382_set_en_chan(struct adf4382_dev *dev, uint8_t ch, bool en) +{ + uint8_t enable; + + if (!ch) { + enable = no_os_field_prep(ADF4382_PD_CLKOUT1_MSK, !en); + return adf4382_spi_update_bits(dev, 0x2B, + ADF4382_PD_CLKOUT1_MSK, + enable); + } + + enable = no_os_field_prep(ADF4382_PD_CLKOUT2_MSK, !en); + return adf4382_spi_update_bits(dev, 0x2B, ADF4382_PD_CLKOUT2_MSK, + enable); +} + +/** + * @brief Gets the value the output channel if it is enabled or disable. + * @param dev - The device structure. + * @param ch - The channel to get state. + * @param en - The status of the output channel. + * @return - 0 in case of success or negative error code. + */ +int adf4382_get_en_chan(struct adf4382_dev *dev, uint8_t ch, bool *en) +{ + uint8_t tmp; + bool enable; + int ret; + + ret = adf4382_spi_read(dev, 0x2B, &tmp); + if (ret) + return ret; + + if (!ch) + enable = no_os_field_get(tmp, ADF4382_PD_CLKOUT1_MSK); + else + enable = no_os_field_get(tmp, ADF4382_PD_CLKOUT2_MSK); + + *en = !enable; + + return 0; +} + +/** + * @brief Set the desired output frequency and reset everything over to maximum + * supported value of 22GHz (21GHz for ADF4382A) to the max. value and + * everything under the minimum supported value of 687.5MHz (2.875GHz for + * ADF4382A) to the min. value. + * @param dev - The device structure. + * @param val - The desired output frequency in Hz. + * @return - 0 in case of success or negative error code. + */ +int adf4382_set_rfout(struct adf4382_dev *dev, uint64_t val) +{ + if (!dev) + return -EINVAL; + + dev->freq = val; + + if (val > dev->freq_max) + dev->freq = dev->freq_max; + + if (val < dev->freq_min) + dev->freq = dev->freq_min; + + return adf4382_set_freq(dev); +} + +/** + * @brief Computes the PFD frequency and returns the value in Hz. + * @param dev - The device structure. + * @return - PFD value in Hz. + */ +static uint64_t adf4382_pfd_compute(struct adf4382_dev *dev) +{ + uint64_t pfd_freq; + + pfd_freq = NO_OS_DIV_ROUND_CLOSEST(dev->ref_freq_hz, dev->ref_div); + if (dev->ref_doubler_en) + pfd_freq *= 2; + + return pfd_freq; +} + +/** + * @brief Gets the user proposed output frequency + * @param dev - The device structure. + * @param val - The set value of the output frequency in Hz. + * @return - 0 in case of success or negative error code. + */ +int adf4382_get_rfout(struct adf4382_dev *dev, uint64_t *val) +{ + uint32_t frac1 = 0; + uint32_t frac2 = 0; + uint32_t mod2 = 0; + uint64_t freq; + uint64_t pfd; + uint8_t tmp; + uint16_t n; + int ret; + + pfd = adf4382_pfd_compute(dev); + + ret = adf4382_spi_read(dev, 0x11, &tmp); + if (ret) + return ret; + n = tmp & ADF4382_N_INT_MSB_MSK; + n = n << 8; + + ret = adf4382_spi_read(dev, 0x10, &tmp); + if (ret) + return ret; + n |= tmp; + + ret = adf4382_spi_read(dev, 0x15, &tmp); + if (ret) + return ret; + frac1 = tmp & ADF4382_FRAC1WORD_MSB; + frac1 = frac1 << 8; + + ret = adf4382_spi_read(dev, 0x14, &tmp); + if (ret) + return ret; + frac1 |= tmp; + frac1 = frac1 << 8; + + ret = adf4382_spi_read(dev, 0x13, &tmp); + if (ret) + return ret; + frac1 |= tmp; + frac1 = frac1 << 8; + + ret = adf4382_spi_read(dev, 0x12, &tmp); + if (ret) + return ret; + frac1 |= tmp; + + ret = adf4382_spi_read(dev, 0x19, &tmp); + if (ret) + return ret; + frac2 = tmp; + frac2 = frac2 << 8; + + ret = adf4382_spi_read(dev, 0x18, &tmp); + if (ret) + return ret; + frac2 |= tmp; + frac2 = frac2 << 8; + + ret = adf4382_spi_read(dev, 0x17, &tmp); + if (ret) + return ret; + frac2 |= tmp; + + ret = adf4382_spi_read(dev, 0x1c, &tmp); + if (ret) + return ret; + mod2 = tmp; + mod2 = mod2 << 8; + + ret = adf4382_spi_read(dev, 0x1b, &tmp); + if (ret) + return ret; + mod2 |= tmp; + mod2 = mod2 << 8; + + ret = adf4382_spi_read(dev, 0x1a, &tmp); + if (ret) + return ret; + mod2 |= tmp; + + freq = frac2 * pfd; + freq = no_os_div_u64(freq, mod2); + freq = freq + (frac1 * pfd); + freq = no_os_div_u64(freq, ADF4382_MOD1WORD); + freq = freq + (n * pfd); + + *val = freq; + return 0; +} + +/** + * @brief Computes the second fractional part of the feedback divider if needed. + * @param dev - The device structure. + * @param res - Residue from the first fractional part. + * @param pfd_freq - Phase/frequency detector frequency. + * @param frac2_word - Second fractional part of the feedback divider, which + * will be returned. + * @param mod2_word - Modulo for the second fractional part of the feedback + * divider, which will be returned. + * @return - 0 in case of success, negative error code otherwise. + */ +static int adf4382_frac2_compute(struct adf4382_dev *dev, uint64_t res, + uint64_t pfd_freq, uint32_t *frac2_word, + uint32_t *mod2_word) +{ + uint32_t channel_spacing; + uint8_t en_phase_resync; + uint32_t chsp_freq; + uint32_t mod2_tmp; + uint32_t mod2_max; + uint32_t mod2_wd; + uint32_t gcd; + uint8_t tmp; + int ret; + + channel_spacing = 1; + mod2_wd = 1; + + ret = adf4382_spi_read(dev, 0x1E, &tmp); + if (ret) + return ret; + + en_phase_resync = no_os_field_get(tmp, ADF4382_EN_PHASE_RESYNC_MSK); + + if (en_phase_resync) + mod2_max = ADF4382_PHASE_RESYNC_MOD2WORD_MAX; + else + mod2_max = ADF4382_MOD2WORD_MAX; + + do { + + chsp_freq = channel_spacing * ADF4382_MOD1WORD; + gcd = no_os_greatest_common_divisor(chsp_freq, pfd_freq); + mod2_tmp = NO_OS_DIV_ROUND_UP(pfd_freq, gcd); + + if (mod2_tmp > mod2_max) { + channel_spacing *= 5; + } else { + mod2_wd = mod2_tmp; + break; + } + + } while (channel_spacing < ADF4382_CHANNEL_SPACING_MAX); + + if (!en_phase_resync) { + mod2_wd *= NO_OS_DIV_U64(mod2_max, mod2_wd); + } + + *frac2_word = NO_OS_DIV_ROUND_CLOSEST_ULL(res * mod2_wd, pfd_freq); + *mod2_word = mod2_wd; + + return 0; +} + +/** + * @brief Computes the feedback divider values for the PLL. + * @param dev - The device structure. + * @param freq - The output frequency. + * @param pfd_freq - Phase/frequency detector frequency. + * @param n_int - Integer part of the feedback divider, which will be + * returned. + * @param frac1_word - First fractional part of the feedback divider, which will + * be returned. + * @param frac2_word - Second fractional part of the feedback divider, which + * will be returned. + * @param mod2_word - Modulo for the second fractional part of the feedback + * divider, which will be returned. + * @return - 0 in case of success, negative error code otherwise. + */ +static int adf4382_pll_fract_n_compute(struct adf4382_dev *dev, uint64_t freq, + uint64_t pfd_freq, uint16_t *n_int, + uint32_t *frac1_word, uint32_t *frac2_word, + uint32_t *mod2_word) +{ + uint64_t rem; + uint64_t res; + + *n_int = no_os_div64_u64_rem(freq, pfd_freq, &rem); + + res = rem * ADF4382_MOD1WORD; + *frac1_word = (uint32_t)no_os_div64_u64_rem(res, pfd_freq, &rem); + + *frac2_word = 0; + *mod2_word = 0; + + if (rem > 0) + return adf4382_frac2_compute(dev, rem, pfd_freq, frac2_word, + mod2_word); + + return 0; +} + +/** + * @brief Fast calibration function. Computes Minimum VCO frequency (fmin), + * uses the minimum NDIV value to generate fastcal Lookup table (LUT), and + * finally enables LUT Calibration. + * @param dev - The device structure. + * @param en_fast_cal - Enables the fast calibration routine. + * @return - N_INT value corresponding to minimum VCO frequency for + * fast calibration LUT generation. + */ +int adf4382_set_en_fast_calibration(struct adf4382_dev *dev, bool en_fast_cal) +{ + uint64_t min_vco_frequency; + uint64_t compute_frequency; + uint32_t cntr_readback; + uint64_t fclk_max_hz = 11000000000; + uint32_t m_vco_band = 511; + uint64_t ref_freq_khz; + uint8_t t_measure = 9; + uint64_t pfd_freq; + uint32_t cal_div; + uint8_t r_mr_clk = 63; + uint32_t n_value; + uint8_t mr_clk = 8; + uint8_t n_int; + uint8_t fsm_busy; + uint8_t lut_scale = 8; + uint8_t timeout = 0; + uint32_t lut_data = 0; + uint8_t val; + uint8_t tmp; + int ret; + + if (!dev) + return -EINVAL; + if (!en_fast_cal) + return 0; + + n_value = NO_OS_DIV_ROUND_CLOSEST(fclk_max_hz, dev->ref_freq_hz); + + ref_freq_khz = NO_OS_DIV_U64(dev->ref_freq_hz, + KHZ_PER_MHZ); + cal_div = NO_OS_DIV_ROUND_CLOSEST(t_measure * ref_freq_khz, + (r_mr_clk * mr_clk)); + + ret = adf4382_spi_update_bits(dev, 0x11, ADF4382_CLKOUT_DIV_MSK, + no_os_field_prep + (ADF4382_CLKOUT_DIV_MSK, 0)); + if (ret) + return ret; + + val = no_os_field_prep(ADF4382_EN_AUTOCAL_MSK, 0) | + no_os_field_prep(ADF4382_EN_RDBLR_MSK, 0) | + no_os_field_prep(ADF4382_R_DIV_MSK, r_mr_clk); + ret = adf4382_spi_write(dev, 0x20, val); + if (ret) + return ret; + + val = cal_div & ADF4382_CNTR_DIV_WORD_MSK; + ret = adf4382_spi_write(dev, 0x3C, val); + if (ret) + return ret; + + val = (cal_div >> 8) & ADF4382_CNTR_DIV_WORD_MSB_MSK; + ret = adf4382_spi_write(dev, 0x3D, val); + if (ret) + return ret; + + val = no_os_field_prep(ADF4382_O_VCO_CORE_MSK, 1) | + no_os_field_prep(ADF4382_O_VCO_BAND_MSK, 1); + ret = adf4382_spi_update_bits(dev, 0x4D, ADF4382_O_VCO_CORE_MSK + | ADF4382_O_VCO_BAND_MSK, val); + if (ret) + return ret; + + ret = adf4382_spi_update_bits(dev, 0x15, ADF4382_M_VCO_CORE_MSK, + no_os_field_prep( + ADF4382_M_VCO_CORE_MSK, 1)); + if (ret) + return ret; + + val = m_vco_band & ADF4382_M_VCO_BAND_LSB_MSK; + ret = adf4382_spi_update_bits(dev, 0x15, ADF4382_M_VCO_BAND_LSB_MSK, + no_os_field_prep + (ADF4382_M_VCO_BAND_LSB_MSK, val)); + if (ret) + return ret; + + val = (m_vco_band >> 1) & ADF4382_M_VCO_BAND_MSB_MSK; + ret = adf4382_spi_write(dev, 0x16, val); + if (ret) + return ret; + + ret = adf4382_spi_update_bits(dev, 0x31, ADF4382_EN_VCAL_MSK, + no_os_field_prep + (ADF4382_EN_VCAL_MSK, 1)); + if (ret) + return ret; + + val = no_os_field_prep(ADF4382_EN_CPTEST_MSK, 1) | + no_os_field_prep(ADF4382_CP_UP_MSK, 0) | + no_os_field_prep(ADF4382_CP_DOWN_MSK, 0); + ret = adf4382_spi_update_bits(dev, 0x2E, ADF4382_EN_CPTEST_MSK + | ADF4382_CP_UP_MSK + | ADF4382_CP_DOWN_MSK, val); + if (ret) + return ret; + + ret = adf4382_spi_update_bits(dev, 0x1F, ADF4382_EN_BLEED_MSK, + no_os_field_prep + (ADF4382_EN_BLEED_MSK, 0)); + if (ret) + return ret; + + val = no_os_field_prep(ADF4382_DCLK_DIV_SEL_MSK, 1) | + no_os_field_prep(ADF4382_DNCLK_DIV1_MSK, 0) | + no_os_field_prep(ADF4382_DCLK_DIV1_MSK, 3); + ret = adf4382_spi_update_bits(dev, 0x24, ADF4382_DCLK_DIV_SEL_MSK + | ADF4382_DNCLK_DIV1_MSK + | ADF4382_DCLK_DIV1_MSK, val); + if (ret) + return ret; + + ret = adf4382_spi_update_bits(dev, 0x31, ADF4382_DCLK_MODE_MSK, + no_os_field_prep + (ADF4382_DCLK_MODE_MSK, 0)); + if (ret) + return ret; + + val = (n_value >> 8) & ADF4382_N_INT_MSB_MSK; + ret = adf4382_spi_update_bits(dev, 0x11, ADF4382_N_INT_MSB_MSK, + val); + if (ret) + return ret; + + val = n_value & ADF4382_N_INT_LSB_MSK; + ret = adf4382_spi_write(dev, 0x10, val); + if (ret) + return ret; + + ret = adf4382_spi_update_bits(dev, 0x3D, ADF4382_READ_MODE_MSK, + no_os_field_prep + (ADF4382_READ_MODE_MSK, 1)); + if (ret) + return ret; + + ret = adf4382_spi_update_bits(dev, 0x34, ADF4382_RST_CNTR_MSK, + no_os_field_prep + (ADF4382_RST_CNTR_MSK, 1)); + if (ret) + return ret; + + ret = adf4382_spi_update_bits(dev, 0x34, ADF4382_RST_CNTR_MSK, + no_os_field_prep + (ADF4382_RST_CNTR_MSK, 0)); + if (ret) + return ret; + + no_os_mdelay(t_measure + 1); + + ret = adf4382_spi_read(dev, 0x57, &tmp); + if (ret) + return ret; + cntr_readback = tmp; + cntr_readback = cntr_readback << 8; + + ret = adf4382_spi_read(dev, 0x56, &tmp); + if (ret) + return ret; + cntr_readback |= tmp; + cntr_readback = cntr_readback << 8; + + ret = adf4382_spi_read(dev, 0x55, &tmp); + if (ret) + return ret; + cntr_readback |= tmp; + + ret = adf4382_spi_update_bits(dev, 0x3D, ADF4382_READ_MODE_MSK, + no_os_field_prep + (ADF4382_READ_MODE_MSK, 0)); + if (ret) + return ret; + + compute_frequency = dev->ref_freq_hz * n_value * cntr_readback; + min_vco_frequency = NO_OS_DIV_U64(compute_frequency, (r_mr_clk + * 8 * cal_div)); + + min_vco_frequency /= 8; + + pfd_freq = adf4382_pfd_compute(dev); + n_int = NO_OS_DIV_ROUND_UP(min_vco_frequency, pfd_freq); + + // Reinitialize registers for accurate LUT generation + val = no_os_field_prep(ADF4382_EN_AUTOCAL_MSK, 1) | + no_os_field_prep(ADF4382_EN_RDBLR_MSK, + dev->ref_doubler_en) | + no_os_field_prep(ADF4382_R_DIV_MSK, dev->ref_div); + ret = adf4382_spi_write(dev, 0x20, val); + if (ret) + return ret; + + ret = adf4382_spi_update_bits(dev, 0x1F, ADF4382_EN_BLEED_MSK, + no_os_field_prep + (ADF4382_EN_BLEED_MSK, 1)); + if (ret) + return ret; + + ret = adf4382_spi_update_bits(dev, 0x31, ADF4382_EN_VCAL_MSK, + no_os_field_prep + (ADF4382_EN_VCAL_MSK, 0)); + if (ret) + return ret; + + val = no_os_field_prep(ADF4382_EN_CPTEST_MSK, 0) | + no_os_field_prep(ADF4382_CP_UP_MSK, 0) | + no_os_field_prep(ADF4382_CP_DOWN_MSK, 0); + ret = adf4382_spi_update_bits(dev, 0x2E, ADF4382_EN_CPTEST_MSK + | ADF4382_CP_UP_MSK | + ADF4382_CP_DOWN_MSK, val); + if (ret) + return ret; + + val = no_os_field_prep(ADF4382_DCLK_DIV_SEL_MSK, 0) | + no_os_field_prep(ADF4382_DNCLK_DIV1_MSK, 0) | + no_os_field_prep(ADF4382_DCLK_DIV1_MSK, 1); + ret = adf4382_spi_update_bits(dev, 0x24, ADF4382_DCLK_DIV_SEL_MSK + | ADF4382_DNCLK_DIV1_MSK + | ADF4382_DCLK_DIV1_MSK, val); + if (ret) + return ret; + + ret = adf4382_spi_update_bits(dev, 0x31, ADF4382_DCLK_MODE_MSK, + no_os_field_prep + (ADF4382_DCLK_MODE_MSK, 1)); + if (ret) + return ret; + + val = no_os_field_prep(ADF4382_O_VCO_CORE_MSK, 0) | + no_os_field_prep(ADF4382_O_VCO_BAND_MSK, 0); + ret = adf4382_spi_update_bits(dev, 0x4D, ADF4382_O_VCO_CORE_MSK + | ADF4382_O_VCO_BAND_MSK, val); + if (ret) + return ret; + + val = n_int & ADF4382_N_INT_LSB_MSK; + ret = adf4382_spi_write(dev, 0x10, val); + if (ret) + return ret; + + ret = adf4382_spi_update_bits(dev, 0x44, ADF4382_VPTAT_CALGEN_MSK, + no_os_field_prep + (ADF4382_VPTAT_CALGEN_MSK, + ADF4382_FASTCAL_VPTAT_CALGEN)); + if (ret) + return ret; + + ret = adf4382_spi_update_bits(dev, 0x45, ADF4382_VCTAT_CALGEN_MSK, + no_os_field_prep + (ADF4382_VCTAT_CALGEN_MSK, + ADF4382_FASTCAL_VCTAT_CALGEN)); + if (ret) + return ret; + + dev->en_lut_gen = en_fast_cal; + ret = adf4382_spi_update_bits(dev, 0x36, ADF4382_EN_LUT_GEN_MSK, + no_os_field_prep + (ADF4382_EN_LUT_GEN_MSK, + dev->en_lut_gen)); + if (ret) + return ret; + + val = n_int & ADF4382_N_INT_LSB_MSK; + ret = adf4382_spi_write(dev, 0x10, val); + if (ret) + return ret; + + ret = adf4382_spi_read(dev, 0x58, &val); + if (ret) + return ret; + + fsm_busy = no_os_field_get(val, ADF4382_FSM_BUSY_MSK); + + while (fsm_busy == 1) { + no_os_mdelay(10); + ret = adf4382_spi_read(dev, 0x58, &val); + if (ret) + return ret; + fsm_busy = no_os_field_get(val, ADF4382_FSM_BUSY_MSK); + if (timeout++ > 100) + break; + } + + val = lut_scale & ADF4382_LUT_SCALE_MSK; + ret = adf4382_spi_write(dev, 0x4F, val); + if (ret) + return ret; + + dev->en_lut_gen = 0; + ret = adf4382_spi_update_bits(dev, 0x36, ADF4382_EN_LUT_GEN_MSK, + no_os_field_prep + (ADF4382_EN_LUT_GEN_MSK, + dev->en_lut_gen)); + if (ret) + return ret; + + // Update LUT for 22GHz step. + dev->freq = 22000000000; + ret = adf4382_set_freq(dev); + if (ret) + return ret; + + ret = adf4382_spi_read(dev, 0x11, &tmp); + if (ret) + return ret; + + lut_data = no_os_field_get(tmp, ADF4382_N_INT_MSB_MSK); + lut_data = lut_data << 8; + + ret = adf4382_spi_read(dev, 0x10, &tmp); + if (ret) + return ret; + + lut_data |= tmp; + + val = (lut_data >> 6) & ADF4382_M_LUT_N_MSB_MSK; + ret = adf4382_spi_write(dev, 0x203, val); + if (ret) + return ret; + + val = lut_data & ADF4382_M_LUT_N_LSB_MSK; + ret = adf4382_spi_update_bits(dev, 0x202, ADF4382_M_LUT_N_LSB_MSK, + no_os_field_prep + (ADF4382_M_LUT_N_LSB_MSK, val)); + if (ret) + return ret; + + ret = adf4382_spi_read(dev, 0x5F, &tmp); + if (ret) + return ret; + val = no_os_field_get(tmp, ADF4382_VCO_CORE_MSK); + + ret = adf4382_spi_update_bits(dev, 0x202, ADF4382_M_LUT_CORE_MSK, + no_os_field_prep + (ADF4382_M_LUT_CORE_MSK, val)); + if (ret) + return ret; + + ret = adf4382_spi_read(dev, 0x5E, &tmp); + if (ret) + return ret; + val = no_os_field_get(tmp, ADF4382_VCO_BAND_LSB_MSK); + + ret = adf4382_spi_write(dev, 0x201, val); + if (ret) + return ret; + + ret = adf4382_spi_read(dev, 0x5F, &tmp); + if (ret) + return ret; + val = no_os_field_get(tmp, ADF4382_M_LUT_BAND_MSB_MSK); + ret = adf4382_spi_update_bits(dev, 0x202, + ADF4382_M_LUT_BAND_MSB_MSK, + no_os_field_prep + (ADF4382_M_LUT_BAND_MSB_MSK, val)); + if (ret) + return ret; + + val = no_os_field_prep(ADF4382_LUT_WR_ADDR_MSK, 31) | + no_os_field_prep(ADF4382_O_VCO_LUT_MSK, 1); + ret = adf4382_spi_write(dev, 0x200, val); + if (ret) + return ret; + dev->en_lut_cal = en_fast_cal; + adf4382_spi_update_bits(dev, 0x36, ADF4382_EN_LUT_CAL_MSK, + no_os_field_prep(ADF4382_EN_LUT_CAL_MSK, + dev->en_lut_cal)); + if (ret) + return ret; + return 0; +} + +/** + * @brief Gets Fast calibration LUT Calibration status. + * @param dev - The device structure. + * @param en - The set value of LUT Calibration. + * @return - 0 in case of success, negative error code otherwise. + */ +int adf4382_get_en_lut_calibration(struct adf4382_dev *dev, bool *en) +{ + uint8_t tmp; + int ret; + + ret = adf4382_spi_read(dev, 0x36, &tmp); + if (ret) + return ret; + + *en = no_os_field_get(tmp, ADF4382_EN_LUT_CAL_MSK); + return 0; +} + +/** + * @brief Sets Fast calibration LUT Calibration. Refer to en_fastcal function to + * first generate fastcal Lookup Table (LUT). + * @param dev - The device structure. + * @param en_lut_cal - Enable/Disable LUT Calibration. + * @return - 0 in case of success, negative error code otherwise. + */ +int adf4382_set_en_lut_calibration(struct adf4382_dev *dev, bool en_lut_cal) +{ + int ret; + dev->en_lut_cal = en_lut_cal; + + if (dev->en_lut_cal == 0) { + ret = adf4382_spi_update_bits(dev, 0x44, ADF4382_VPTAT_CALGEN_MSK, + no_os_field_prep + (ADF4382_VPTAT_CALGEN_MSK, + ADF4382_VPTAT_CALGEN)); + if (ret) + return ret; + + ret = adf4382_spi_update_bits(dev, 0x45, ADF4382_VCTAT_CALGEN_MSK, + no_os_field_prep + (ADF4382_VCTAT_CALGEN_MSK, + ADF4382_VCTAT_CALGEN)); + if (ret) + return ret; + } else { + ret = adf4382_spi_update_bits(dev, 0x44, ADF4382_VPTAT_CALGEN_MSK, + no_os_field_prep + (ADF4382_VPTAT_CALGEN_MSK, + ADF4382_FASTCAL_VPTAT_CALGEN)); + if (ret) + return ret; + + ret = adf4382_spi_update_bits(dev, 0x45, ADF4382_VCTAT_CALGEN_MSK, + no_os_field_prep + (ADF4382_VCTAT_CALGEN_MSK, + ADF4382_FASTCAL_VCTAT_CALGEN)); + if (ret) + return ret; + } + return adf4382_spi_update_bits(dev, 0x36, ADF4382_EN_LUT_CAL_MSK, + no_os_field_prep(ADF4382_EN_LUT_CAL_MSK, + dev->en_lut_cal)); +} + +/** + * @brief Gets the user proposed output frequency from the device tree without + * reading from the device. This is to enable and accurate reading of device + * lock-time. + * @param dev - The device structure. + * @param val - Holds the software value of RFOUT Frequency set. + * @return - Output frequency in KHz. + */ +int adf4382_get_change_rfout(struct adf4382_dev *dev, uint64_t *val) +{ + *val = dev->freq; + return 0; +} + +/** + * @brief Set the desired output frequency and reset everything over to maximum + * supported value of 22GHz (21GHz for ADF4382A) to the max without starting + * autocalibration. value and everything under the minimum supported value of + * 687.5MHz (2.875GHz for ADF4382A) to the min. value. + * @param dev - The device structure. + * @param val - The desired output frequency in Hz. + * @return - 0 in case of success or negative error code. + */ +int adf4382_set_change_rfout(struct adf4382_dev *dev, uint64_t val) +{ + if (!dev) + return -EINVAL; + + dev->freq = val; + + if (val > dev->freq_max) + dev->freq = dev->freq_max; + + if (val < dev->freq_min) + dev->freq = dev->freq_min; + + return adf4382_set_change_freq(dev); +} + +/** + * @brief Computes the optimized bleed word value for the PLL in fractional mode. + * @param dev - The device structure. + * @param pfd_freq - Phase detector frequency. + * @return - 0 in case of success or negative error code. + */ +static int adf4382_bleed_word_compute(struct adf4382_dev *dev, + uint64_t pfd_freq) +{ + uint32_t coars_bleed; + uint16_t bleed_delay = 0; + uint32_t fine_bleed; + uint16_t bleed_word_tmp; + uint64_t bleed_i; + uint64_t rem; + + if (!dev) + return -EINVAL; + + /* Computes the bleed delay based on rfout frequency in SDM MODE 0. + See Product DataSheet for more details. */ + if (dev->freq < 1800000000UL) + bleed_delay = 3600; + else if (dev->freq < 4000000000) + bleed_delay = 1000; + else if (dev->freq < 10000000000UL) + bleed_delay = 625; + else if (dev->freq >= 10000000000UL) + bleed_delay = 300; + + bleed_i = bleed_delay * pfd_freq * adf4382_ci_ua[dev->cp_i]; + bleed_i = NO_OS_DIV_ROUND_CLOSEST(bleed_i, PS_TO_S); + coars_bleed = no_os_div64_u64_rem(bleed_i, ADF4382_COARSE_BLEED_CONST, + &rem); + fine_bleed = rem * ADF4382_FINE_BLEED_CONST_1; + fine_bleed = NO_OS_DIV_ROUND_UP(fine_bleed, ADF4382_FINE_BLEED_CONST_2); + bleed_word_tmp = coars_bleed << 9 | fine_bleed; + bleed_word_tmp = no_os_clamp(bleed_word_tmp, 1, 8191); + dev->bleed_word = bleed_word_tmp; + return 0; +} + +/** + * @brief Set the output frequency. This will set the required registers to + * device but skip NDIV value, to be written separately. This Function will not + * start autocalibration until REG0010 is written. + * @param dev - The device structure. + * @return - 0 in case of success, negative error code otherwise. + */ +int adf4382_set_change_freq(struct adf4382_dev *dev) +{ + uint32_t frac2_word; + uint32_t frac1_word; + uint32_t mod2_word; + uint8_t clkout_div; + uint64_t pfd_freq; + uint8_t ldwin_pw = 0; + uint8_t en_bleed; + uint16_t n_int; + uint64_t tmp; + uint64_t vco = 0; + uint8_t val; + int ret; + + for (clkout_div = 0; clkout_div <= dev->clkout_div_reg_val_max; clkout_div++) { + tmp = (1 << clkout_div) * dev->freq; + if (tmp < dev->vco_min || tmp > dev->vco_max) + continue; + + vco = tmp; + break; + } + + if (!vco) { + pr_err("VCO is 0\n"); + return -EINVAL; + } + + //Calculates the PFD freq. the output will be in Hz + pfd_freq = adf4382_pfd_compute(dev); + + ret = adf4382_pll_fract_n_compute(dev, dev->freq, pfd_freq, &n_int, + &frac1_word, &frac2_word, &mod2_word); + if (ret) + return ret; + + if (frac1_word || frac2_word) { + en_bleed = 1; + if (pfd_freq <= 40 * MHZ) { + ldwin_pw = 7; + } else if (pfd_freq <= 50 * MHZ) { + ldwin_pw = 6; + } else if (pfd_freq <= 100 * MHZ) { + ldwin_pw = 5; + } else if (pfd_freq <= 200 * MHZ) { + ldwin_pw = 4; + } else if (pfd_freq <= 250 * MHZ) { + if (dev->freq >= 5000U * MHZ && + dev->freq < 6400U * MHZ) { + ldwin_pw = 3; + } else { + ldwin_pw = 2; + } + } + ret = adf4382_bleed_word_compute(dev, pfd_freq); + if (ret) + return ret; + } else { + en_bleed = 0; + + tmp = NO_OS_DIV_ROUND_UP(pfd_freq, MICROAMPER_PER_AMPER); + tmp *= adf4382_ci_ua[dev->cp_i]; + tmp = NO_OS_DIV_ROUND_UP(dev->bleed_word, tmp); + if (tmp <= 85) + ldwin_pw = 0; + else + ldwin_pw = 1; + } + + if (frac2_word) { + ret = adf4382_spi_update_bits(dev, 0x28, ADF4382_VAR_MOD_EN_MSK, + 0xff); + if (ret) + return ret; + } else { + ret = adf4382_spi_update_bits(dev, 0x28, ADF4382_VAR_MOD_EN_MSK, + 0x0); + if (ret) + return ret; + } + + val = dev->bleed_word & ADF4382_FINE_BLEED_LSB_MSK; + ret = adf4382_spi_write(dev, 0x1D, val); + if (ret) + return ret; + val = (dev->bleed_word >> 8) & ADF4382_BLEED_MSB_MSK; + ret = adf4382_spi_update_bits(dev, 0x1E, ADF4382_BLEED_MSB_MSK, + no_os_field_prep(ADF4382_BLEED_MSB_MSK, + val)); + if (ret) + return ret; + + ret = adf4382_spi_update_bits(dev, 0x1F, ADF4382_EN_BLEED_MSK, + no_os_field_prep(ADF4382_EN_BLEED_MSK, + en_bleed)); + if (ret) + return ret; + + val = mod2_word & ADF4382_MOD2WORD_LSB_MSK; + ret = adf4382_spi_write(dev, 0x1A, val); + if (ret) + return ret; + val = (mod2_word >> 8) & ADF4382_MOD2WORD_MID_MSK; + ret = adf4382_spi_write(dev, 0x1B, val); + if (ret) + return ret; + val = (mod2_word >> 16) & ADF4382_MOD2WORD_MSB_MSK; + ret = adf4382_spi_write(dev, 0x1C, val); + if (ret) + return ret; + + val = frac2_word & ADF4382_FRAC2WORD_LSB_MSK; + ret = adf4382_spi_write(dev, 0x17, val); + if (ret) + return ret; + val = (frac2_word >> 8) & ADF4382_FRAC2WORD_MID_MSK; + ret = adf4382_spi_write(dev, 0x18, val); + if (ret) + return ret; + val = (frac2_word >> 16) & ADF4382_FRAC2WORD_MSB_MSK; + ret = adf4382_spi_write(dev, 0x19, val); + if (ret) + return ret; + + val = frac1_word & ADF4382_FRAC1WORD_LSB_MSK; + ret = adf4382_spi_write(dev, 0x12, val); + if (ret) + return ret; + val = (frac1_word >> 8) & ADF4382_FRAC1WORD_MID_MSK; + ret = adf4382_spi_write(dev, 0x13, val); + if (ret) + return ret; + val = (frac1_word >> 16) & ADF4382_FRAC1WORD_MSB_MSK; + ret = adf4382_spi_write(dev, 0x14, val); + if (ret) + return ret; + + val = (frac1_word >> 24) & ADF4382_FRAC1WORD_MSB; + ret = adf4382_spi_update_bits(dev, 0x15, ADF4382_FRAC1WORD_MSB, val); + if (ret) + return ret; + + ret = adf4382_spi_update_bits(dev, 0x2C, ADF4382_LDWIN_PW_MSK, + no_os_field_prep(ADF4382_LDWIN_PW_MSK, + ldwin_pw)); + if (ret) + return ret; + + ret = adf4382_spi_update_bits(dev, 0x11, ADF4382_CLKOUT_DIV_MSK, + no_os_field_prep(ADF4382_CLKOUT_DIV_MSK, + clkout_div)); + if (ret) + return ret; + + val = (n_int >> 8) & ADF4382_N_INT_MSB_MSK; + ret = adf4382_spi_update_bits(dev, 0x11, ADF4382_N_INT_MSB_MSK, val); + if (ret) + return ret; + // Need to store N_INT to trigger an auto-calibration in another function + dev->n_int = n_int; + + return 0; +} + +/** + * @brief Get the status of start calibration. Will always return zero to allow + * users set it multiple times to trigger autocalibration. + * @param dev - The device structure. + * @param start_cal - Overwrites start calibration attribute to 0. + * @return - 0 in case of success, negative error code otherwise. + */ +int adf4382_get_start_calibration(struct adf4382_dev *dev, bool *start_cal) +{ + *start_cal = 0; + return 0; +} + +/** + * @brief Set REG0010 value in device structure to the device to start autocal. + * @param dev - The device structure. + * @return - 0 in case of success, negative error code otherwise. + */ +int adf4382_set_start_calibration(struct adf4382_dev *dev) +{ + uint8_t n_value; + n_value = dev->n_int & ADF4382_N_INT_LSB_MSK; + return adf4382_spi_write(dev, 0x10, n_value); +} + +/** + * @brief Set the output frequency. + * @param dev - The device structure. + * @return - 0 in case of success, negative error code otherwise. + */ +int adf4382_set_freq(struct adf4382_dev *dev) +{ + uint32_t frac2_word; + uint32_t frac1_word; + uint32_t mod2_word; + uint8_t clkout_div; + uint8_t dclk_div1; + uint64_t pfd_freq; + uint8_t ldwin_pw = 0; + uint8_t int_mode; + uint8_t en_bleed; + uint8_t locked; + uint16_t n_int; + uint8_t div1; + uint64_t tmp; + uint64_t vco = 0; + uint8_t val; + int ret; + + val = no_os_field_prep(ADF4382_EN_RDBLR_MSK, dev->ref_doubler_en) | + no_os_field_prep(ADF4382_R_DIV_MSK, dev->ref_div); + ret = adf4382_spi_update_bits(dev, 0x20, + ADF4382_EN_RDBLR_MSK | ADF4382_R_DIV_MSK, + val); + if (ret) + return ret; + + for (clkout_div = 0; clkout_div <= dev->clkout_div_reg_val_max; clkout_div++) { + tmp = (1 << clkout_div) * dev->freq; + if (tmp < dev->vco_min || tmp > dev->vco_max) + continue; + + vco = tmp; + break; + } + + if (!vco) { + pr_err("VCO is 0\n"); + return -EINVAL; + } + + //Calculates the PFD freq. the output will be in Hz + pfd_freq = adf4382_pfd_compute(dev); + + ret = adf4382_spi_update_bits(dev, 0x1F, ADF4382_CP_I_MSK, + no_os_field_prep(ADF4382_CP_I_MSK, + dev->cp_i)); + if (ret) + return ret; + + ret = adf4382_pll_fract_n_compute(dev, dev->freq, pfd_freq, &n_int, + &frac1_word, &frac2_word, &mod2_word); + if (ret) + return ret; + + if (frac1_word || frac2_word) { + int_mode = 0; + en_bleed = 1; + + /*The lock detector pulse window is determined based on the + PFD frequency as described in the datasheet*/ + if (pfd_freq <= 40 * MHZ) { + ldwin_pw = 7; + } else if (pfd_freq <= 50 * MHZ) { + ldwin_pw = 6; + } else if (pfd_freq <= 100 * MHZ) { + ldwin_pw = 5; + } else if (pfd_freq <= 200 * MHZ) { + ldwin_pw = 4; + } else if (pfd_freq <= 250 * MHZ) { + if (dev->freq >= 5000U * MHZ && + dev->freq < 6400U * MHZ) { + ldwin_pw = 3; + } else { + ldwin_pw = 2; + } + } + + ret = adf4382_bleed_word_compute(dev, pfd_freq); + if (ret) + return ret; + + } else { + int_mode = 1; + en_bleed = 0; + + tmp = NO_OS_DIV_ROUND_UP(pfd_freq, MICROAMPER_PER_AMPER); + tmp *= adf4382_ci_ua[dev->cp_i]; + tmp = NO_OS_DIV_ROUND_UP(dev->bleed_word, tmp); + if (tmp <= 85) + ldwin_pw = 0; + else + ldwin_pw = 1; + } + + if (frac2_word) { + ret = adf4382_spi_update_bits(dev, 0x28, ADF4382_VAR_MOD_EN_MSK, + 0xff); + if (ret) + return ret; + } else { + ret = adf4382_spi_update_bits(dev, 0x28, ADF4382_VAR_MOD_EN_MSK, + 0x0); + if (ret) + return ret; + } + + ret = adf4382_spi_update_bits(dev, 0x15, ADF4382_INT_MODE_MSK, + no_os_field_prep(ADF4382_INT_MODE_MSK, + int_mode)); + if (ret) + return ret; + + val = dev->bleed_word & ADF4382_FINE_BLEED_LSB_MSK; + ret = adf4382_spi_write(dev, 0x1D, val); + if (ret) + return ret; + val = (dev->bleed_word >> 8) & ADF4382_BLEED_MSB_MSK; + ret = adf4382_spi_update_bits(dev, 0x1E, ADF4382_BLEED_MSB_MSK, + no_os_field_prep(ADF4382_BLEED_MSB_MSK, + val)); + if (ret) + return ret; + + ret = adf4382_spi_update_bits(dev, 0x1F, ADF4382_EN_BLEED_MSK, + no_os_field_prep(ADF4382_EN_BLEED_MSK, + en_bleed)); + if (ret) + return ret; + + val = mod2_word & ADF4382_MOD2WORD_LSB_MSK; + ret = adf4382_spi_write(dev, 0x1A, val); + if (ret) + return ret; + val = (mod2_word >> 8) & ADF4382_MOD2WORD_MID_MSK; + ret = adf4382_spi_write(dev, 0x1B, val); + if (ret) + return ret; + val = (mod2_word >> 16) & ADF4382_MOD2WORD_MSB_MSK; + ret = adf4382_spi_write(dev, 0x1C, val); + if (ret) + return ret; + + val = frac2_word & ADF4382_FRAC2WORD_LSB_MSK; + ret = adf4382_spi_write(dev, 0x17, val); + if (ret) + return ret; + val = (frac2_word >> 8) & ADF4382_FRAC2WORD_MID_MSK; + ret = adf4382_spi_write(dev, 0x18, val); + if (ret) + return ret; + val = (frac2_word >> 16) & ADF4382_FRAC2WORD_MSB_MSK; + ret = adf4382_spi_write(dev, 0x19, val); + if (ret) + return ret; + + val = frac1_word & ADF4382_FRAC1WORD_LSB_MSK; + ret = adf4382_spi_write(dev, 0x12, val); + if (ret) + return ret; + val = (frac1_word >> 8) & ADF4382_FRAC1WORD_MID_MSK; + ret = adf4382_spi_write(dev, 0x13, val); + if (ret) + return ret; + val = (frac1_word >> 16) & ADF4382_FRAC1WORD_MSB_MSK; + ret = adf4382_spi_write(dev, 0x14, val); + if (ret) + return ret; + + val = (frac1_word >> 24) & ADF4382_FRAC1WORD_MSB; + ret = adf4382_spi_update_bits(dev, 0x15, ADF4382_FRAC1WORD_MSB, val); + if (ret) + return ret; + + dclk_div1 = 2; + div1 = 8; + if (pfd_freq <= ADF4382_DCLK_DIV1_0_MAX) { + dclk_div1 = 0; + div1 = 1; + } else if (pfd_freq <= ADF4382_DCLK_DIV1_1_MAX) { + dclk_div1 = 1; + div1 = 2; + } + + ret = adf4382_spi_update_bits(dev, 0x24, ADF4382_DCLK_DIV1_MSK, + no_os_field_prep(ADF4382_DCLK_DIV1_MSK, + dclk_div1)); + if (ret) + return ret; + + ret = adf4382_spi_update_bits(dev, 0x31, ADF4382_DCLK_MODE_MSK, 0xff); + if (ret) + return ret; + + ret = adf4382_spi_update_bits(dev, 0x31, ADF4382_CAL_CT_SEL_MSK, 0xff); + if (ret) + return ret; + + ret = adf4382_spi_update_bits(dev, 0x31, ADF4382_EN_ADC_CLK_MSK, 0xff); + if (ret) + return ret; + + //Time for VCO calibration based on Vtune + val = ADF4382_VCO_CAL_VTUNE & ADF4382_CAL_VTUNE_TO_LSB_MSK; + ret = adf4382_spi_write(dev, 0x38, val); + if (ret) + return ret; + + val = (ADF4382_VCO_CAL_VTUNE >> 8) & ADF4382_CAL_VTUNE_TO_MSB_MSK; + ret = adf4382_spi_update_bits(dev, 0x39, ADF4382_CAL_VTUNE_TO_MSB_MSK, + no_os_field_prep + (ADF4382_CAL_VTUNE_TO_MSB_MSK, val)); + if (ret) + return ret; + + //VCO automatic level calibration time + ret = adf4382_spi_write(dev, 0x3A, ADF4382_VCO_CAL_ALC); + if (ret) + return ret; + + tmp = NO_OS_DIV_ROUND_UP(no_os_div_u64(pfd_freq, div1 * 400000) - 2, 4); + tmp = no_os_clamp(tmp, 0U, 255U); + ret = adf4382_spi_write(dev, 0x3E, tmp); + if (ret) + return ret; + + // Set LD COUNT + ret = adf4382_spi_update_bits(dev, 0x2C, ADF4382_LD_COUNT_OPWR_MSK, + dev->ld_count); + if (ret) + return ret; + + ret = adf4382_spi_update_bits(dev, 0x2C, ADF4382_LDWIN_PW_MSK, + no_os_field_prep(ADF4382_LDWIN_PW_MSK, + ldwin_pw)); + if (ret) + return ret; + + ret = adf4382_spi_update_bits(dev, 0x11, ADF4382_CLKOUT_DIV_MSK, + no_os_field_prep(ADF4382_CLKOUT_DIV_MSK, + clkout_div)); + if (ret) + return ret; + + val = (n_int >> 8) & ADF4382_N_INT_MSB_MSK; + ret = adf4382_spi_update_bits(dev, 0x11, ADF4382_N_INT_MSB_MSK, val); + if (ret) + return ret; + + // Need to set N_INT last to trigger an auto-calibration + val = n_int & ADF4382_N_INT_LSB_MSK; + ret = adf4382_spi_write(dev, 0x10, val); + if (ret) + return ret; + + no_os_udelay(ADF4382_LKD_DELAY_US); + ret = adf4382_spi_read(dev, 0x58, &val); + if (ret) + return ret; + + locked = no_os_field_get(val, ADF4382_LOCKED_MSK); + if (!locked) + return -EIO; + + return 0; +} + +/** + * @brief Set the phase adjustment in pico-seconds. The phase adjust will + * enable the Bleed current option as well as delay mode to 0. + * @param dev - The device structure. + * @param phase_ps - The phase adjustment in pico-seconds. + * @return - 0 in case of success, negative error code otherwise. + */ +int adf4382_set_phase_adjust(struct adf4382_dev *dev, uint32_t phase_ps) +{ + uint64_t phase_reg_value; + uint32_t rfout_deg_ns; + uint32_t phase_deg_ns; + uint64_t rfout_deg_s; + uint64_t phase_bleed; + uint16_t phase_deg; + uint64_t phase_ci; + uint64_t pfd_freq; + int ret; + + ret = adf4382_spi_update_bits(dev, 0x1E, ADF4382_EN_PHASE_RESYNC_MSK, 0xff); + if (ret) + return ret; + + ret = adf4382_spi_update_bits(dev, 0x1F, ADF4382_EN_BLEED_MSK, 0xff); + if (ret) + return ret; + + ret = adf4382_spi_update_bits(dev, 0x32, ADF4382_DEL_MODE_MSK, 0x0); + if (ret) + return ret; + + dev->phase_adj = phase_ps; + + //Determine the output freq. in degrees/s + rfout_deg_s = 360 * dev->freq; + //Convert it to degrees/ns + rfout_deg_ns = no_os_div_u64(rfout_deg_s, S_TO_NS); + //Determine the phase adjustment in degrees relative the output freq. + phase_deg_ns = rfout_deg_ns * phase_ps; + //Convert it to degrees/ps + phase_deg = no_os_div_u64(phase_deg_ns, NS_TO_PS); + + if (phase_deg > 360) { + pr_err("Phase Adjustment cannot exceed 360deg per Clock Period\n"); + return EINVAL; + } + + //Phase adjustment can only be done if bleed is active, and a bleed + //constant needs to be added + phase_bleed = phase_deg * ADF4382_PHASE_BLEED_CNST; + //The charge pump current will also need to be taken in to account + phase_ci = phase_bleed * adf4382_ci_ua[dev->cp_i]; + phase_ci = no_os_div_u64(phase_ci, MICROAMPER_PER_AMPER); + + //Computation of the register value for the phase adjust + pfd_freq = adf4382_pfd_compute(dev); + phase_reg_value = no_os_div_u64((phase_ci * pfd_freq), (360 * dev->freq)); + + if (phase_reg_value > 255) + phase_reg_value -= 255; + + ret = adf4382_spi_write(dev, 0x33, phase_reg_value); + if (ret) + return ret; + + return adf4382_spi_update_bits(dev, 0x34, ADF4382_PHASE_ADJ_MSK, 0xff); +} + +/** + * @brief Set the phase polarity. If pol = 0 then it will add the phase value + * otherwise it will subtract the phase value. + * @param dev - The device structure. + * @param polarity - The polarity to be set. + * @return - Result of the writing procedure, error code otherwise. + */ +int adf4382_set_phase_pol(struct adf4382_dev *dev, bool polarity) +{ + uint8_t pol; + + pol = no_os_field_prep(ADF4382_PHASE_ADJ_POL_MSK, polarity); + return adf4382_spi_update_bits(dev, 0x32, ADF4382_PHASE_ADJ_POL_MSK, pol); +} + +/** + uint8_t pol; + * @brief Gets the polarity of the phase adjust. + * @param dev - The device structure. + * @param polarity - The read polarity of the phase. + * @return - Result of the tesint procedure, negative error code + * otherwise. + */ +int adf4382_get_phase_pol(struct adf4382_dev *dev, bool *polarity) +{ + uint8_t tmp; + int ret; + + ret = adf4382_spi_read(dev, 0x32, &tmp); + if (ret) + return ret; + + *polarity = no_os_field_get(tmp, ADF4382_PHASE_ADJ_POL_MSK); + return 0; +} + +/** + * @brief Set the EZSYNC features' initial state. Awaits the SW_SYNC toggle. + * @param dev - The device structure. + * @param sync - The enable or disable sync. + * @return - Result of the writing procedure, error code otherwise. + */ +int adf4382_set_ezsync_setup(struct adf4382_dev *dev, bool sync) +{ + int ret; + + if (!dev) + return -EINVAL; + + if (sync == 1) { + ret = adf4382_spi_update_bits(dev, 0x2A, ADF4382_PD_SYNC_MSK, 0); + if (ret) + return ret; + + ret = adf4382_spi_update_bits(dev, 0x53, + ADF4382_SYNC_SEL_MSK, 0xff); + if (ret) + return ret; + + ret = adf4382_spi_update_bits(dev, 0x1E, + ADF4382_TIMED_SYNC_MSK, 0); + if (ret) + return ret; + + ret = adf4382_spi_update_bits(dev, 0x1E, + (ADF4382_EN_REF_RST_MSK | + ADF4382_EN_PHASE_RESYNC_MSK), 0xff); + if (ret) + return ret; + + } else { + ret = adf4382_spi_update_bits(dev, 0x2A, ADF4382_PD_SYNC_MSK, + 0xff); + if (ret) + return ret; + } + return 0; +} + +/** + * @brief Set Timed SYNC features' initial state. Uses SYNC pin. + * @param dev - The device structure. + * @param sync - The enable or disable sync. + * @return - Result of the writing procedure, error code otherwise. + */ +int adf4382_set_timed_sync_setup(struct adf4382_dev *dev, bool sync) +{ + uint64_t pfd_freq; + uint8_t delay; + uint8_t val; + int ret; + + if (!dev) + return -EINVAL; + + if (sync == 1) { + // Timed Sync + ret = adf4382_spi_update_bits(dev, 0x2A, ADF4382_PD_SYNC_MSK, 0); + if (ret) + return ret; + + ret = adf4382_spi_update_bits(dev, 0x53, + ADF4382_SYNC_SEL_MSK, 0); + if (ret) + return ret; + + ret = adf4382_spi_update_bits(dev, 0x1E, (ADF4382_EN_REF_RST_MSK + | ADF4382_TIMED_SYNC_MSK + | ADF4382_EN_PHASE_RESYNC_MSK), + 0xff); + if (ret) + return ret; + + pfd_freq = adf4382_pfd_compute(dev); + if (pfd_freq >= 225 * MHZ) { + delay = 3; + } else if (pfd_freq >= 200 * MHZ) { + delay = 4; + } else if (pfd_freq >= 148 * MHZ) { + delay = 1; + } else if (pfd_freq >= 130 * MHZ) { + delay = 3; + } else if (pfd_freq >= 85 * MHZ) { + delay = 4; + } else if (pfd_freq < 85 * MHZ) { + delay = 0; + } + ret = adf4382_spi_update_bits(dev, 0x31, ADF4382_SYNC_DEL_MSK, + no_os_field_prep + (ADF4382_SYNC_DEL_MSK, delay)); + if (ret) + return ret; + + val = no_os_field_prep(ADF4382_DRCLK_DEL_MSK, delay) | + no_os_field_prep(ADF4382_DNCLK_DEL_MSK, delay); + ret = adf4382_spi_update_bits(dev, 0x34, + ADF4382_DRCLK_DEL_MSK + | ADF4382_DNCLK_DEL_MSK, val); + + if (ret) + return ret; + } else { + ret = adf4382_spi_update_bits(dev, 0x2A, ADF4382_PD_SYNC_MSK, + 0xff); + if (ret) + return ret; + } + return 0; +} + + +/** + * @brief Gets the value of the SYNC powerdown bit. + * @param dev - The device structure. + * @param en - The read status of the sync enable. + * @return - 0 in case of success or negative error code. + */ +int adf4382_get_phase_sync_setup(struct adf4382_dev *dev, bool *en) +{ + uint8_t tmp; + int ret; + + ret = adf4382_spi_read(dev, 0x2A, &tmp); + if (ret) + return ret; + + *en = no_os_field_get(tmp, ADF4382_PD_SYNC_MSK); + return 0; +} + +/** + * @brief Set Software SYNC Request. Setting SW_SYNC resets the RF block. + * Clearing SW_SYNC makes ready for a new reference clock. + * @param dev - The device structure. + * @param sw_sync - Set send SW_SYNC request + * @return - 0 in case of success or negative error code. + */ +int adf4382_set_sw_sync(struct adf4382_dev *dev, bool sw_sync) +{ + uint8_t tmp; + + if (!dev) + return -EINVAL; + + tmp = no_os_field_prep(ADF4382_SW_SYNC_MSK, sw_sync); + return adf4382_spi_update_bits(dev, 0x1F, ADF4382_SW_SYNC_MSK, tmp); +} + +/** + * @brief Gets the value of the SW_SYNC bit. + * @param dev - The device structure. + * @param sw_sync - The read value of the SW_SYNC. + * @return - 0 in case of success or negative error code. + */ +int adf4382_get_sw_sync(struct adf4382_dev *dev, bool *sw_sync) +{ + uint8_t tmp; + int ret; + + if (!dev) + return -EINVAL; + + ret = adf4382_spi_read(dev, 0x1F, &tmp); + if (ret) + return ret; + *sw_sync = no_os_field_get(tmp, ADF4382_SW_SYNC_MSK); + + return 0; +} + +/** + * @brief ADF4382 SPI Scratchpad check. + * @param dev - The device structure. + * @return - 0 in case of success or negative error code. + */ +static int adf4382_check_scratchpad(struct adf4382_dev *dev) +{ + uint8_t scratchpad; + int ret; + + ret = adf4382_spi_write(dev, 0x00A, ADF4382_SPI_SCRATCHPAD_TEST); + if (ret) + return ret; + + ret = adf4382_spi_read(dev, 0x00A, &scratchpad); + if (ret) + return ret; + + if (scratchpad != ADF4382_SPI_SCRATCHPAD_TEST) + return -EINVAL; + + return 0; +} + +/** + * @brief Update core bias table for ADF4383. + * @param dev - The device structure. + * @return - 0 in case of success or negative error code. + */ +static int adf4383_update_core_bias_table(struct adf4382_dev *dev) +{ + int ret; + + ret = adf4382_spi_write(dev, 0x109, 0x3); + if (ret) + return ret; + ret = adf4382_spi_write(dev, 0x10A, 0x7); + if (ret) + return ret; + ret = adf4382_spi_write(dev, 0x10F, 0x7); + if (ret) + return ret; + ret = adf4382_spi_write(dev, 0x110, 0x7); + if (ret) + return ret; + ret = adf4382_spi_write(dev, 0x111, 0x7); + if (ret) + return ret; + + return 0; +} + +/** + * @brief Initializes the ADF4382. + * @param dev - The device structure. + * @param init_param - The structure containing the device initial parameters. + * @return - 0 in case of success or negative error code. + */ +int adf4382_init(struct adf4382_dev **dev, + struct adf4382_init_param *init_param) +{ + struct adf4382_dev *device; + bool en = true; + uint8_t i; + int ret; + + device = (struct adf4382_dev *)no_os_calloc(1, sizeof(*device)); + if (!device) + return -ENOMEM; + + ret = no_os_spi_init(&device->spi_desc, init_param->spi_init); + if (ret) + goto error_dev; + + device->spi_3wire_en = init_param->spi_3wire_en; + device->cmos_3v3 = init_param->cmos_3v3; + device->ref_freq_hz = init_param->ref_freq_hz; + device->freq = init_param->freq; + device->ref_doubler_en = init_param->ref_doubler_en; + device->ref_div = init_param->ref_div; + device->cp_i = init_param->cp_i; + device->bleed_word = init_param->bleed_word; + device->ld_count = init_param->ld_count; + device->phase_adj = 0; + + switch (init_param->id) { + case ID_ADF4382: + device->freq_max = ADF4382_RFOUT_MAX; + device->freq_min = ADF4382_RFOUT_MIN; + device->vco_max = ADF4382_VCO_FREQ_MAX; + device->vco_min = ADF4382_VCO_FREQ_MIN; + device->clkout_div_reg_val_max = ADF4382_CLKOUT_DIV_REG_VAL_MAX; + break; + case ID_ADF4382A: + device->freq_max = ADF4382A_RFOUT_MAX; + device->freq_min = ADF4382A_RFOUT_MIN; + device->vco_max = ADF4382A_VCO_FREQ_MAX; + device->vco_min = ADF4382A_VCO_FREQ_MIN; + device->clkout_div_reg_val_max = ADF4382A_CLKOUT_DIV_REG_VAL_MAX; + break; + case ID_ADF4383: + device->freq_max = ADF4383_RFOUT_MAX; + device->freq_min = ADF4383_RFOUT_MIN; + device->vco_max = ADF4383_VCO_FREQ_MAX; + device->vco_min = ADF4383_VCO_FREQ_MIN; + device->clkout_div_reg_val_max = ADF4382_CLKOUT_DIV_REG_VAL_MAX; + break; + default: + goto error_spi; + } + + ret = adf4382_spi_write(device, 0x00, ADF4382_RESET_CMD); + if (ret) + goto error_spi; + + no_os_udelay(ADF4382_POR_DELAY_US); + + if (device->spi_3wire_en) + en = false; + + /* SPI set to 4 wire */ + ret = adf4382_spi_write(device, 0x00, ADF4382_SPI_3W_CFG(en)); + if (ret) + goto error_spi; + + ret = adf4382_spi_write(device, 0x3D, + no_os_field_prep(ADF4382_CMOS_OV_MSK, + device->cmos_3v3)); + if (ret) + goto error_spi; + + ret = adf4382_check_scratchpad(device); + if (ret) + goto error_spi; + + for (i = 0; i < NO_OS_ARRAY_SIZE(adf4382_reg_defaults); i++) { + ret = adf4382_spi_write(device, + adf4382_reg_defaults[i].reg, + adf4382_reg_defaults[i].val); + if (ret) + goto error_spi; + } + + if (ID_ADF4383 == init_param->id) { + ret = adf4383_update_core_bias_table(device); + if (ret) + goto error_spi; + } + + ret = adf4382_set_freq(device); + if (ret) + goto error_spi; + + ret = adf4382_set_out_power(device, 0, 9); + if (ret) + goto error_spi; + ret = adf4382_set_out_power(device, 1, 9); + if (ret) + goto error_spi; + *dev = device; + + return ret; +error_spi: + no_os_spi_remove(device->spi_desc); +error_dev: + no_os_free(device); + return ret; +} + +/** + * @brief Free resources allocated for ADF4382 + * @param dev - The device structure. + * @return - 0 in case of success or negative error code. + */ +int adf4382_remove(struct adf4382_dev *dev) +{ + int ret; + + ret = no_os_spi_remove(dev->spi_desc); + if (ret) + no_os_free(dev); + + return 0; +} diff --git a/14_RADAR_Old_version/Firmware/Microcontroller/adf4382.h b/14_RADAR_Old_version/Firmware/Microcontroller/adf4382.h new file mode 100644 index 0000000..0d479fe --- /dev/null +++ b/14_RADAR_Old_version/Firmware/Microcontroller/adf4382.h @@ -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 +#include +#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 diff --git a/14_RADAR_Old_version/Firmware/Microcontroller/hardware_config.h b/14_RADAR_Old_version/Firmware/Microcontroller/hardware_config.h new file mode 100644 index 0000000..800abaf --- /dev/null +++ b/14_RADAR_Old_version/Firmware/Microcontroller/hardware_config.h @@ -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 diff --git a/14_RADAR_Old_version/Firmware/Microcontroller/iio.c b/14_RADAR_Old_version/Firmware/Microcontroller/iio.c new file mode 100644 index 0000000..2ec966e --- /dev/null +++ b/14_RADAR_Old_version/Firmware/Microcontroller/iio.c @@ -0,0 +1,2039 @@ +/***************************************************************************//** + * @file iio.c + * @brief Implementation of iio. + * @author Cristian Pop (cristian.pop@analog.com) + * @author Mihail Chindris (mihail.chindris@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 "iio.h" +#include "iio_types.h" +#include "iiod.h" +#include "ctype.h" +#include "no_os_util.h" +#include "no_os_list.h" +#include "no_os_error.h" +#include "no_os_uart.h" +#include "no_os_error.h" +#include "no_os_alloc.h" +#include "no_os_circular_buffer.h" +#include +#include +#include + +#ifdef NO_OS_NETWORKING +#include "no_os_delay.h" +#include "tcp_socket.h" +#endif + +#ifdef NO_OS_LWIP_NETWORKING +#include "no_os_delay.h" +#include "tcp_socket.h" +#include "lwip_socket.h" +#endif + +#define IIOD_PORT 30431 +#define MAX_SOCKET_TO_HANDLE 10 +#define REG_ACCESS_ATTRIBUTE "direct_reg_access" +#define IIOD_CONN_BUFFER_SIZE 0x1000 +#define NO_TRIGGER (uint32_t)-1 + +#define NO_OS_STRINGIFY(x) #x +#define NO_OS_TOSTRING(x) NO_OS_STRINGIFY(x) + +static char uart_buff[IIOD_CONN_BUFFER_SIZE]; + +static char header[] = + "" + "" + "" + "" + "" + "" + "" + "" + "" + "" + "" + "" + "" + "" + "" + "" + "" + "]>" + ""; +static char header_end[] = ""; + +static const char * const iio_chan_type_string[] = { + [IIO_VOLTAGE] = "voltage", + [IIO_CURRENT] = "current", + [IIO_ALTVOLTAGE] = "altvoltage", + [IIO_ANGL_VEL] = "anglvel", + [IIO_TEMP] = "temp", + [IIO_CAPACITANCE] = "capacitance", + [IIO_ACCEL] = "accel", + [IIO_RESISTANCE] = "resistance", + [IIO_MAGN] = "magn", + [IIO_INCLI] = "incli", + [IIO_VELOCITY] = "velocity", + [IIO_ANGL] = "angl", + [IIO_ROT] = "rot", + [IIO_COUNT] = "count", + [IIO_DELTA_ANGL] = "deltaangl", + [IIO_DELTA_VELOCITY] = "deltavelocity", + [IIO_WEIGHT] = "weight", +}; + +static const char * const iio_modifier_names[] = { + [IIO_MOD_X] = "x", + [IIO_MOD_Y] = "y", + [IIO_MOD_Z] = "z", + [IIO_MOD_TEMP_AMBIENT] = "ambient", + [IIO_MOD_PITCH] = "pitch", + [IIO_MOD_YAW] = "yaw", + [IIO_MOD_ROLL] = "roll", +}; + +/* Parameters used in show and store functions */ +struct attr_fun_params { + void *dev_instance; + char *buf; + uint32_t len; + struct iio_ch_info *ch_info; +}; + +struct iio_buffer_priv { + /* Field visible by user */ + struct iio_buffer public; + /** Buffer to read or write data. A reference will be found in buffer */ + struct no_os_circular_buffer cb; + /* Buffer provide by user. */ + int8_t *raw_buf; + /* Length of raw_buf */ + uint32_t raw_buf_len; + /* Set when this devices has buffer */ + bool initalized; + /* Set when no_os_calloc was used to initalize cb.buf */ + bool allocated; +}; + +/** + * @struct iio_dev_priv + * @brief Links a physical device instance "void *dev_instance" + * with a "iio_device *iio" that describes capabilities of the device. + */ +struct iio_dev_priv { + /** Will be: iio:device[0...n] n beeing the count of registerd devices*/ + char dev_id[MAX_DEV_ID]; + /** Device name */ + const char *name; + /** Physical instance of a device */ + void *dev_instance; + /** Structure to be passed to callbacks */ + struct iio_device_data dev_data; + /** Used to read debug attributes */ + uint32_t active_reg_addr; + /** Device descriptor(describes channels and attributes) */ + struct iio_device *dev_descriptor; + /* Structure storing buffer related fields */ + struct iio_buffer_priv buffer; + /* Set to -1 when no trigger is set*/ + uint32_t trig_idx; +}; + +/** + * @struct iio_trig_priv + * @brief Links a physical trigger instance "void *instance" + * with a "iio_trigger *descriptor" that describes capabilities of the trigger. + */ +struct iio_trig_priv { + /** Will be: iio:trigger[0...n] */ + char id[MAX_TRIG_ID]; + /** Trigger name */ + char *name; + /** Physical instance of a trigger */ + void *instance; + /** Trigger descriptor(describes type of trigger and its attributes) */ + struct iio_trigger *descriptor; + /** Set to true when the triggering condition is met */ + bool triggered; +}; + +struct iio_desc { + struct iiod_desc *iiod; + struct iiod_ops iiod_ops; + void *phy_desc; + char *xml_desc; + uint32_t xml_size; + struct iio_ctx_attr *ctx_attrs; + uint32_t nb_ctx_attr; + struct iio_dev_priv *devs; + uint32_t nb_devs; + struct iio_trig_priv *trigs; + uint32_t nb_trigs; + struct no_os_uart_desc *uart_desc; + int (*recv)(void *conn, uint8_t *buf, uint32_t len); + int (*send)(void *conn, uint8_t *buf, uint32_t len); + /* FIFO for socket descriptors */ + struct no_os_circular_buffer *conns; +#if defined(NO_OS_NETWORKING) || defined(NO_OS_LWIP_NETWORKING) + struct tcp_socket_desc *current_sock; + /* Instance of server socket */ + struct tcp_socket_desc *server; +#endif +}; + +static inline int32_t _pop_conn(struct iio_desc *desc, uint32_t *conn_id) +{ + uint32_t size; + + no_os_cb_size(desc->conns, &size); + if (size < sizeof(uint32_t)) + return -EAGAIN; + + return no_os_cb_read(desc->conns, conn_id, sizeof(*conn_id)); +} + +static inline int32_t _push_conn(struct iio_desc *desc, uint32_t conn_id) +{ + return no_os_cb_write(desc->conns, &conn_id, sizeof(conn_id)); +} + +static inline int32_t _nb_active_conns(struct iio_desc *desc) +{ + uint32_t size; + + no_os_cb_size(desc->conns, &size); + + return size / sizeof(uint32_t); +} + + +static int iio_recv(struct iiod_ctx *ctx, uint8_t *buf, uint32_t len) +{ + struct iio_desc *desc = ctx->instance; + + return desc->recv(ctx->conn, buf, len); +} + +static int iio_send(struct iiod_ctx *ctx, uint8_t *buf, uint32_t len) +{ + struct iio_desc *desc = ctx->instance; + + return desc->send(ctx->conn, buf, len); +} + +static inline void _print_ch_id(char *buff, struct iio_channel *ch) +{ + if (ch->modified) { + sprintf(buff, "%s_%s", iio_chan_type_string[ch->ch_type], + iio_modifier_names[ch->channel2]); + } else { + if (ch->indexed) { + if (ch->diferential) + sprintf(buff, "%s%d-%s%d", iio_chan_type_string[ch->ch_type], + (int)ch->channel, iio_chan_type_string[ch->ch_type], + (int)ch->channel2); + else + sprintf(buff, "%s%d", iio_chan_type_string[ch->ch_type], + (int)ch->channel); + } else { + sprintf(buff, "%s", iio_chan_type_string[ch->ch_type]); + } + } +} + +/** + * @brief Get channel ID from a list of channels. + * @param channel - Channel name. + * @param desc - Device descriptor + * @param ch_out - If "true" is output channel, if "false" is input channel. + * @return Channel ID, or negative value if attribute is not found. + */ +static inline struct iio_channel *iio_get_channel(const char *channel, + struct iio_device *desc, bool ch_out) +{ + int16_t i = 0; + char ch_id[MAX_CHN_ID]; + + while (i < desc->num_ch) { + _print_ch_id(ch_id, &desc->channels[i]); + if (!strcmp(channel, ch_id) && + (desc->channels[i].ch_out == ch_out)) + return &desc->channels[i]; + i++; + } + + return NULL; +} + +/** + * @brief Find interface with "device_name". + * @param device_name - Device name. + * @param iio_dev_privs - List of interfaces. + * @return Interface pointer if interface is found, NULL otherwise. + */ +static struct iio_dev_priv *get_iio_device(struct iio_desc *desc, + const char *device_name) +{ + uint32_t i; + + for (i = 0; i < desc->nb_devs; i++) { + if (strcmp(desc->devs[i].dev_id, device_name) == 0) + return &desc->devs[i]; + } + + return NULL; +} + +/** + * @brief Find interface with "trigger_id". + * @param trigger_id - Trigger id (trigger0, trigger1, etc.). + * @param iio_trig_privs - List of interfaces. + * @return Interface pointer if interface is found, NULL otherwise. + */ +static struct iio_trig_priv *get_iio_trig_device(struct iio_desc *desc, + const char *trigger_id) +{ + uint32_t i; + + for (i = 0; i < desc->nb_trigs; i++) { + if (strcmp(desc->trigs[i].id, trigger_id) == 0) + return &desc->trigs[i]; + } + + return NULL; +} + +/** + * @brief Sets buffers count. + * @param ctx - IIO instance and conn instance. + * @param device - String containing device name. + * @param buffers_count - Value to be set. + * @return Positive if index was set, negative if not. + */ +static int iio_set_buffers_count(struct iiod_ctx *ctx, const char *device, + uint32_t buffers_count) +{ + struct iio_desc *desc = ctx->instance; + + if (!get_iio_device(desc, device)) + return -ENODEV; + + /* Our implementation uses a circular buffer to send/receive data so + * only 1 is a valid value. + */ + if (buffers_count != 1) + return -EINVAL; + + return 0; +} + +/** + * @brief Read all attributes from an attribute list. + * @param device - Physical instance of a device. + * @param buf - Buffer where values are read. + * @param len - Maximum length of value to be stored in buf. + * @param channel - Channel properties. + * @param attributes - List of attributes to be read. + * @return Number of bytes read or negative value in case of error. + */ +static int iio_read_all_attr(struct attr_fun_params *params, + struct iio_attribute *attributes) +{ + /* TODO Not sure if working corectly */ + return -EINVAL; + +#if 0 + int16_t i = 0, j = 0; + char local_buf[256]; + int attr_length; + uint32_t *pattr_length; + + while (attributes[i].name) { + attr_length = attributes[i].show(params->dev_instance, + local_buf, params->len, + params->ch_info, + attributes[i].priv); + if (NO_OS_IS_ERR_VALUE(attr_length)) + attr_length = snprintf(local_buf, params->len, "%d", + attr_length); + + attr_length += 1;//Add '\0' to the count + pattr_length = (uint32_t *)(params->buf + j); + if (j + 4 > params->len) + return -EINVAL; + *pattr_length = no_os_bswap_constant_32(attr_length); + j += 4; + if (attr_length >= 0) { + if (attr_length + j > params->len) + return -EINVAL; + sprintf(params->buf + j, "%s", local_buf); + if (attr_length & 0x3) /* multiple of 4 */ + attr_length = ((attr_length >> 2) + 1) << 2; + j += attr_length; + } + i++; + } + if (j == 0) + return -ENOENT; + + return j; +#endif +} + +/** + * @brief Write all attributes from an attribute list. + * @param device - Physical instance of a device. + * @param buf - Values to be written. + * @param len - Length of buf. + * @param channel - Channel properties. + * @param attributes - List of attributes to be written. + * @return Number of written bytes or negative value in case of error. + */ +static int iio_write_all_attr(struct attr_fun_params *params, + struct iio_attribute *attributes) +{ + /* TODO Not sure if working corectly */ + return -EINVAL; + +#if 0 + int16_t i = 0, j = 0; + int16_t attr_length; + + while (attributes[i].name) { + attr_length = no_os_bswap_constant_32((uint32_t)(params->buf + j)); + j += 4; + attributes[i].store(params->dev_instance, (params->buf + j), + attr_length, params->ch_info, + attributes[i].priv); + j += attr_length; + if (j & 0x3) + j = ((j >> 2) + 1) << 2; + i++; + } + + if (params->len == 0) + return -ENOENT; + + return params->len; +#endif +} + +/** + * @brief Read/write attribute. + * @param params - Structure describing parameters for store and show functions + * @param attributes - Array of attributes. + * @param attr_name - Attribute name to be modified + * @param is_write -If it has value "1", writes attribute, otherwise reads + * attribute. + * @return Length of chars written/read or negative value in case of error. + */ +static int iio_rd_wr_attribute(struct attr_fun_params *params, + struct iio_attribute *attributes, + const char *attr_name, + bool is_write) +{ + int16_t i = 0; + + /* Search attribute */ + while (attributes[i].name) { + if (!strcmp(attr_name, attributes[i].name)) + break; + i++; + } + + if (!attributes[i].name) + return -ENOENT; + + if (is_write) { + if (!attributes[i].store) + return -ENOENT; + + return attributes[i].store(params->dev_instance, params->buf, + params->len, params->ch_info, + attributes[i].priv); + } else { + if (!attributes[i].show) + return -ENOENT; + return attributes[i].show(params->dev_instance, params->buf, + params->len, params->ch_info, + attributes[i].priv); + } +} + +/* Read a device register. The register address to read is set on + * in desc->active_reg_addr in the function set_demo_reg_attr + */ +static int32_t debug_reg_read(struct iio_dev_priv *dev, char *buf, uint32_t len) +{ + uint32_t value; + int32_t ret; + + value = 0; + ret = dev->dev_descriptor->debug_reg_read(dev->dev_instance, + dev->active_reg_addr, + &value); + if (NO_OS_IS_ERR_VALUE(ret)) + return ret; + + return snprintf(buf, len, "%"PRIu32"", value); +} + +/* Flow of reading and writing registers. This is how iio works for + * direct_reg_access attribute: + * Read register: + * //Reg_addr in decimal + * reg_addr = "10"; + * 1. debug_reg_write(dev, reg_addr, len); + * 2. debug_reg_read(dev, out_buf, out_len); + * Write register: + * sprintf(write_buf, "0x%x 0x%x", reg_addr, value); + * 1. debug_reg_write(dev, write_buf,len); + */ +static int32_t debug_reg_write(struct iio_dev_priv *dev, const char *buf, + uint32_t len) +{ + uint32_t nb_filled; + uint32_t addr; + uint32_t value; + int32_t ret; + + nb_filled = sscanf(buf, "0x%"PRIx32" 0x%"PRIx32"", &addr, &value); + if (nb_filled == 2) { + /* Write register */ + ret = dev->dev_descriptor->debug_reg_write(dev->dev_instance, + addr, value); + if (NO_OS_IS_ERR_VALUE(ret)) + return ret; + } else { + nb_filled = sscanf(buf, "%"PRIu32, &addr); + if (nb_filled == 1) { + dev->active_reg_addr = addr; + return len; + } else { + return -EINVAL; + } + } + + return len; +} + +static int32_t __iio_str_parse(char *buf, int32_t *integer, int32_t *_fract, + int32_t *_fract_scale, bool scale_db) +{ + char *p; + + p = strtok(buf, "."); + if (p == NULL) + return -EINVAL; + + *integer = strtol(p, NULL, 0); + + if (scale_db) { + p = strtok(NULL, "db"); + if (p == NULL) + p = strtok(NULL, " db"); + } else + p = strtok(NULL, "\n"); + + if (p == NULL) + return -EINVAL; + + *_fract = strtol(p, NULL, 10); + + /* Handle leading zeroes */ + while (*p++ == '0' && *_fract > 0) + *_fract_scale *= 10; + + /* Handle values between -1 and 0 */ + if (*integer == 0 && buf[0] == '-') + *_fract *= -1; + + return 0; +} + +static int32_t _iio_fract_interpret(int32_t fract, int32_t subunits) +{ + int32_t temp; + int32_t mult = 1; + + if (fract < 0) { + mult = -1; + fract = -fract; + } + + /* Divide to nearest subunit-scale if fract part is more than subunit */ + while (fract >= subunits) + fract = NO_OS_DIV_ROUND_CLOSEST(fract, 10); + + temp = fract; + + while ((subunits != 0) || (temp != 0)) { + temp /= 10; + subunits /= 10; + if (!temp) + break; + if (subunits <= 1) + fract /= 10; + } + + return fract * subunits * mult; +} + +int32_t iio_parse_value(char *buf, enum iio_val fmt, int32_t *val, + int32_t *val2) +{ + int32_t ret = 0; + int32_t integer, _fract = 0, _fract_scale = 1; + char ch; + + switch (fmt) { + case IIO_VAL_INT: + integer = strtol(buf, NULL, 0); + break; + case IIO_VAL_INT_PLUS_MICRO_DB: + ret = __iio_str_parse(buf, &integer, &_fract, + &_fract_scale, true); + if (ret < 0) + return ret; + _fract = _iio_fract_interpret(_fract, 1000000 / _fract_scale); + break; + case IIO_VAL_INT_PLUS_MICRO: + ret = __iio_str_parse(buf, &integer, &_fract, + &_fract_scale, false); + if (ret < 0) + return ret; + _fract = _iio_fract_interpret(_fract, 1000000 / _fract_scale); + break; + case IIO_VAL_INT_PLUS_NANO: + ret = __iio_str_parse(buf, &integer, &_fract, + &_fract_scale, false); + if (ret < 0) + return ret; + _fract = _iio_fract_interpret(_fract, + 1000000000 / _fract_scale); + break; + case IIO_VAL_FRACTIONAL: + ret = __iio_str_parse(buf, &integer, &_fract, + &_fract_scale, false); + if (ret < 0) + return ret; + break; + case IIO_VAL_CHAR: + if (sscanf(buf, "%c", &ch) != 1) + return -EINVAL; + integer = ch; + break; + default: + return -EINVAL; + } + + if (val) + *val = integer; + if (val2) + *val2 = _fract; + + return ret; +} + +int iio_format_value(char *buf, uint32_t len, enum iio_val fmt, + int32_t size, int32_t *vals) +{ + int64_t tmp; + int32_t integer, fractional; + bool dB = false; + int32_t i = 0; + uint32_t l = 0; + + switch (fmt) { + case IIO_VAL_INT: + return snprintf(buf, len, "%"PRIi32"", vals[0]); + case IIO_VAL_INT_PLUS_MICRO_DB: + dB = true; + /* intentional fall through */ + case IIO_VAL_INT_PLUS_MICRO: + return snprintf(buf, len, "%s%"PRIi32".%06"PRIu32"%s", + vals[1] < 0 ? "-" : "", vals[0], + (uint32_t)vals[1], dB ? " dB" : ""); + case IIO_VAL_INT_PLUS_NANO: + return snprintf(buf, len, "%s%"PRIi32".%09"PRIu32"", + vals[1] < 0 ? "-" : "", vals[0], + (uint32_t)vals[1]); + case IIO_VAL_FRACTIONAL: + tmp = no_os_div_s64((int64_t)vals[0] * 1000000000LL, vals[1]); + fractional = vals[1]; + integer = (int32_t)no_os_div_s64_rem(tmp, 1000000000, &fractional); + + if (integer == 0 && fractional < 0) + return snprintf(buf, len, "-0.%09u", abs(fractional)); + + return snprintf(buf, len, "%"PRIi32".%09u", integer, + abs(fractional)); + case IIO_VAL_FRACTIONAL_LOG2: + tmp = no_os_shift_right((int64_t)vals[0] * 1000000000LL, vals[1]); + integer = (int32_t)no_os_div_s64_rem(tmp, 1000000000LL, &fractional); + + if (integer == 0 && fractional < 0) + return snprintf(buf, len, "-0.%09u", abs(fractional)); + + return snprintf(buf, len, "%"PRIi32".%09u", integer, + abs(fractional)); + case IIO_VAL_INT_MULTIPLE: { + while (i < size) { + l += snprintf(&buf[l], len - l, "%"PRIi32" ", vals[i]); + if (l >= len) + break; + i++; + } + return l; + } + case IIO_VAL_CHAR: + return snprintf(buf, len, "%c", (char)vals[0]); + default: + return 0; + } +} + +static struct iio_attribute *get_attributes(enum iio_attr_type type, + struct iio_dev_priv *dev, + struct iio_channel *ch) +{ + switch (type) { + case IIO_ATTR_TYPE_DEBUG: + return dev->dev_descriptor->debug_attributes; + break; + case IIO_ATTR_TYPE_DEVICE: + return dev->dev_descriptor->attributes; + break; + case IIO_ATTR_TYPE_BUFFER: + return dev->dev_descriptor->buffer_attributes; + break; + case IIO_ATTR_TYPE_CH_IN: + case IIO_ATTR_TYPE_CH_OUT: + return ch->attributes; + } + + return NULL; +} + +/** + * @brief Returns trigger attributes. + * @param type - Attribute type. + * @param trig - Trigger instance. + * @return Attributes pointer if attributes exist, NULL otherwise. + */ +static struct iio_attribute *get_trig_attributes(enum iio_attr_type type, + struct iio_trig_priv *trig) +{ + switch (type) { + /* Only device type attributes allowed for triggers */ + case IIO_ATTR_TYPE_DEVICE: + return trig->descriptor->attributes; + break; + default: + break; + } + + return NULL; +} + +/** + * @brief Read global attribute of a device. + * @param ctx - IIO instance and conn instance + * @param device - String containing device name. + * @param attr - String containing attribute name. + * @param buf - Buffer where value is read. + * @param len - Maximum length of value to be stored in buf. + * @return Number of bytes read. + */ +static int iio_read_attr(struct iiod_ctx *ctx, const char *device, + struct iiod_attr *attr, char *buf, uint32_t len) +{ + struct iio_dev_priv *dev; + struct iio_trig_priv *trig_dev; + struct iio_ch_info ch_info; + struct iio_channel *ch = NULL; + struct attr_fun_params params; + struct iio_attribute *attributes; + int8_t ch_out; + + dev = get_iio_device(ctx->instance, device); + + /* If IIO device with given name is found, handle reading of attributes */ + if (dev) { + if (attr->type == IIO_ATTR_TYPE_DEBUG && + strcmp(attr->name, REG_ACCESS_ATTRIBUTE) == 0) { + if (dev->dev_descriptor->debug_reg_read) + return debug_reg_read(dev, buf, len); + return -ENOENT; + } + + if (attr->channel[0] != '\0') { + ch_out = attr->type == IIO_ATTR_TYPE_CH_OUT ? 1 : 0; + ch = iio_get_channel(attr->channel, dev->dev_descriptor, + ch_out); + if (!ch) + return -ENOENT; + ch_info.ch_out = ch_out; + ch_info.ch_num = ch->channel; + ch_info.type = ch->ch_type; + ch_info.differential = ch->diferential; + ch_info.address = ch->address; + params.ch_info = &ch_info; + } else { + params.ch_info = NULL; + } + + params.buf = buf; + params.len = len; + params.dev_instance = dev->dev_instance; + attributes = get_attributes(attr->type, dev, ch); + if (!strcmp(attr->name, "")) + return iio_read_all_attr(¶ms, attributes); + return iio_rd_wr_attribute(¶ms, attributes, attr->name, 0); + } + + /* IIO device with given name is not found, verify if it corresponds to a trigger */ + trig_dev = get_iio_trig_device(ctx->instance, device); + + /* If IIO trigger with given name is found, handle reading of attributes */ + if (trig_dev) { + params.ch_info = NULL; /* Triggers cannot have channels */ + params.buf = buf; + params.len = len; + params.dev_instance = trig_dev->instance; + attributes = get_trig_attributes(attr->type, trig_dev); + if (!strcmp(attr->name, "")) + return iio_read_all_attr(¶ms, attributes); + return iio_rd_wr_attribute(¶ms, attributes, attr->name, 0); + } + + /* No device and no trigger with given name were found */ + return -ENODEV; +} + +/** + * @brief Write global attribute of a device. + * @param device - String containing device name. + * @param ctx - IIO instance and conn instance + * @param attr - String containing attribute name. + * @param buf - Value to be written. + * @param len - Length of data. + * @return Number of written bytes. + */ +static int iio_write_attr(struct iiod_ctx *ctx, const char *device, + struct iiod_attr *attr, char *buf, uint32_t len) +{ + struct iio_dev_priv *dev; + struct iio_trig_priv *trig_dev; + struct attr_fun_params params; + struct iio_attribute *attributes; + struct iio_ch_info ch_info; + struct iio_channel *ch = NULL; + int8_t ch_out; + + dev = get_iio_device(ctx->instance, device); + + /* If IIO device with given name is found, handle writing of attributes */ + if (dev) { + + if (attr->type == IIO_ATTR_TYPE_DEBUG && + strcmp(attr->name, REG_ACCESS_ATTRIBUTE) == 0) { + if (dev->dev_descriptor->debug_reg_write) + return debug_reg_write(dev, buf, len); + return -ENOENT; + } + + if (attr->channel[0] != '\0') { + ch_out = attr->type == IIO_ATTR_TYPE_CH_OUT ? 1 : 0; + ch = iio_get_channel(attr->channel, dev->dev_descriptor, + ch_out); + if (!ch) + return -ENOENT; + + ch_info.ch_out = ch_out; + ch_info.ch_num = ch->channel; + ch_info.type = ch->ch_type; + ch_info.differential = ch->diferential; + ch_info.address = ch->address; + params.ch_info = &ch_info; + } else { + params.ch_info = NULL; + } + + params.buf = (char *)buf; + params.len = len; + params.dev_instance = dev->dev_instance; + attributes = get_attributes(attr->type, dev, ch); + if (!strcmp(attr->name, "")) + return iio_write_all_attr(¶ms, attributes); + return iio_rd_wr_attribute(¶ms, attributes, attr->name, 1); + } + + /* IIO device with given name is not found, verify if it corresponds to a trigger */ + trig_dev = get_iio_trig_device(ctx->instance, device); + + /* If IIO trigger with given name is found, handle writing of attributes */ + if (trig_dev) { + params.ch_info = NULL; /* Triggers cannot have channels */ + params.buf = (char *)buf; + params.len = len; + params.dev_instance = trig_dev->instance; + attributes = get_trig_attributes(attr->type, trig_dev); + if (!strcmp(attr->name, "")) + return iio_read_all_attr(¶ms, attributes); + return iio_rd_wr_attribute(¶ms, attributes, attr->name, 1); + } + + /* No device and no trigger with given name were found */ + return -ENODEV; +} + +/** + * @brief Searches for trigger id and returns trigger index. + * @param desc - IIO descriptor. + * @param id - Trigger id (trigger0, trigger1, etc.). + * @return Trigger index. NO_TRIGGER in case trigger is not found. + */ +static uint32_t iio_get_trig_idx_by_id(struct iio_desc *desc, const char *id) +{ + uint32_t i; + + if (!id) + return NO_TRIGGER; + + for (i = 0; i < desc->nb_trigs; i++) + if (strcmp(desc->trigs[i].id, id) == 0) + return i; + + return NO_TRIGGER; +} + +/** + * @brief Searches for trigger name and returns trigger index. + * @param desc - IIO descriptor. + * @param name - Trigger name. + * @return Trigger index. NO_TRIGGER in case trigger is not found. + */ +static uint32_t iio_get_trig_idx_by_name(struct iio_desc *desc, + const char *name) +{ + uint32_t i; + + if (!name) + return NO_TRIGGER; + + for (i = 0; i < desc->nb_trigs; i++) + if (strcmp(desc->trigs[i].name, name) == 0) + return i; + + return NO_TRIGGER; +} + +/** + * @brief Searches for active trigger of the given device and returns trigger name. + * @param ctx - IIO instance and conn instance. + * @param device - String containing device name. + * @param trigger - Trigger name to be returned. + * @param len - Maximum length of value to be stored in name. + * @return Number of bytes written in name. + */ +static int iio_get_trigger(struct iiod_ctx *ctx, const char *device, + char *trigger, uint32_t len) +{ + struct iio_dev_priv *dev; + struct iio_trig_priv *trig; + struct iio_desc *desc = ctx->instance; + + if (!desc->nb_trigs) + return -ENOENT; + + trig = get_iio_trig_device(desc, device); + /* Device is a trigger and triggers cannot have other triggers */ + if (trig) + return -ENOENT; + + dev = get_iio_device(desc, device); + if (!dev) + return -ENODEV; + + if (dev->trig_idx == NO_TRIGGER) { + trigger[0] = '\0'; + + return 0; + } + + return snprintf(trigger, len, "%s", desc->trigs[dev->trig_idx].name); +} + +/** + * @brief Searches for given trigger id for the given device and if found, it + * sets the trigger. + * @param ctx - IIO instance and conn instance. + * @param device - String containing device name. + * @param trigger - Trigger id to be set. + * @param len - Maximum length of value to be returned. + * @return Positive if index was set, negative if not. + */ +static int iio_set_trigger(struct iiod_ctx *ctx, const char *device, + const char *trigger, uint32_t len) +{ + struct iio_dev_priv *dev; + struct iio_trig_priv *trig; + uint32_t i; + struct iio_desc *desc = ctx->instance; + + if (!desc->nb_trigs) + return -ENOENT; + + trig = get_iio_trig_device(desc, device); + /* Device is a trigger and triggers cannot have other triggers */ + if (trig) + return -ENOENT; + + dev = get_iio_device(desc, device); + if (!dev) + return -ENODEV; + + if (trigger[0] == '\0') { + dev->trig_idx = NO_TRIGGER; + return 0; + } + + i = iio_get_trig_idx_by_id(desc, trigger); + if (i == NO_TRIGGER) + return -EINVAL; + + dev->trig_idx = i; + + return len; +} + +/** + * @brief Asynchronous trigger processing routine. + * @param desc - IIO descriptor. + */ +static void iio_process_async_triggers(struct iio_desc *desc) +{ + struct iio_dev_priv *dev; + uint32_t i; + + for (i = 0; i < desc->nb_devs; i++) { + dev = desc->devs + i; + if (dev->trig_idx == NO_TRIGGER) + continue; + + if (!desc->trigs[dev->trig_idx].triggered) + continue; + + if (dev->dev_descriptor->trigger_handler) { + dev->dev_descriptor->trigger_handler(&dev->dev_data); + desc->trigs[i].triggered = 0; + } + } +} + +/** + * @brief Searches for trigger name and processes the trigger based on its + * type (sync or async with the interrupt). + * @param desc - IIO descriptor. + * @param trigger_name - Trigger name. + * + * @return ret - Result of the processing procedure. + */ +int iio_process_trigger_type(struct iio_desc *desc, char *trigger_name) +{ + uint32_t i; + uint32_t trig_id; + struct iio_trig_priv *trig; + + trig_id = iio_get_trig_idx_by_name(desc, trigger_name); + + if (trig_id == NO_TRIGGER) + return -EINVAL; + + struct iio_dev_priv *dev; + + for (i = 0; i < desc->nb_devs; i++) { + dev = desc->devs + i; + if (dev->trig_idx == trig_id) { + trig = &desc->trigs[trig_id]; + if (trig->descriptor->is_synchronous) { + if (dev->dev_descriptor->trigger_handler) + dev->dev_descriptor->trigger_handler(&dev->dev_data); + } else { + trig->triggered = 1; + } + } + } + + return 0; +} + +static uint32_t bytes_per_scan(struct iio_channel *channels, uint32_t mask) +{ + uint32_t cnt, i, length, largest = 1; + + cnt = 0; + i = 0; + while (mask) { + if ((mask & 1)) { + length = channels[i].scan_type->storagebits / 8; + + if (length > largest) + largest = length; + + if (cnt % length) + cnt += 2 * length - (cnt % length); + else + cnt += length; + } + + mask >>= 1; + ++i; + } + + if (cnt % largest) + cnt += largest - (cnt % largest); + + return cnt; +} + +/** + * @brief Open device. + * @param ctx - IIO instance and conn instance + * @param device - String containing device name. + * @param sample_size - Sample size. + * @param mask - Channels to be opened. + * @return 0, negative value in case of failure. + */ +static int iio_open_dev(struct iiod_ctx *ctx, const char *device, + uint32_t samples, uint32_t mask, bool cyclic) +{ + struct iio_desc *desc; + struct iio_dev_priv *dev; + struct iio_trig_priv *trig; + uint32_t ch_mask; + int32_t ret; + int8_t *buf; + uint32_t buf_size; + + dev = get_iio_device(ctx->instance, device); + if (!dev) + return -ENODEV; + + if (!dev->buffer.initalized) + return -EINVAL; + + ch_mask = 0xFFFFFFFF >> (32 - dev->dev_descriptor->num_ch); + mask &= ch_mask; + if (!mask) + return -ENOENT; + + dev->buffer.public.cyclic_info.is_cyclic = cyclic; + dev->buffer.public.cyclic_info.buff_index = 0; + + dev->buffer.public.active_mask = mask; + dev->buffer.public.bytes_per_scan = + bytes_per_scan(dev->dev_descriptor->channels, mask); + dev->buffer.public.size = dev->buffer.public.bytes_per_scan * samples; + dev->buffer.public.samples = samples; + if (dev->buffer.raw_buf && dev->buffer.raw_buf_len) { + if (dev->buffer.raw_buf_len < dev->buffer.public.size) + /* Need a bigger buffer or to allocate */ + return -ENOMEM; + buf_size = dev->buffer.raw_buf_len - (dev->buffer.raw_buf_len % + dev->buffer.public.size); + buf = dev->buffer.raw_buf; + } else { + if (dev->buffer.allocated) { + /* Free in case iio_close_dev wasn't called to free it*/ + no_os_free(dev->buffer.cb.buff); + dev->buffer.allocated = 0; + } + buf_size = dev->buffer.public.size; + buf = (int8_t *)no_os_calloc(dev->buffer.public.size, sizeof(*buf)); + if (!buf) + return -ENOMEM; + dev->buffer.allocated = 1; + } + + ret = no_os_cb_cfg(&dev->buffer.cb, buf, buf_size); + if (NO_OS_IS_ERR_VALUE(ret)) { + if (dev->buffer.allocated) { + no_os_free(dev->buffer.cb.buff); + dev->buffer.allocated = 0; + } + + return ret; + } + + if (dev->dev_descriptor->pre_enable) { + ret = dev->dev_descriptor->pre_enable(dev->dev_instance, mask); + if (NO_OS_IS_ERR_VALUE(ret)) { + if (dev->buffer.allocated) { + no_os_free(dev->buffer.cb.buff); + dev->buffer.allocated = 0; + } + return ret; + } + } + + desc = ctx->instance; + if (dev->trig_idx != NO_TRIGGER) { + trig = &desc->trigs[dev->trig_idx]; + if (trig->descriptor->enable) + ret = trig->descriptor->enable(trig->instance); + } + + return ret; +} + +/** + * @brief Close device. + * @param ctx - IIO instance and conn instance + * @param device - String containing device name. + * @return 0, negative value in case of failure. + */ +static int iio_close_dev(struct iiod_ctx *ctx, const char *device) +{ + struct iio_desc *desc; + struct iio_dev_priv *dev; + struct iio_trig_priv *trig; + int ret = 0; + + dev = get_iio_device(ctx->instance, device); + if (!dev) + return -1; + + if (!dev->buffer.initalized) + return -EINVAL; + + if (dev->buffer.allocated) { + /* Should something else be used to free internal strucutre */ + no_os_free(dev->buffer.cb.buff); + dev->buffer.allocated = 0; + } + + desc = ctx->instance; + if (dev->trig_idx != NO_TRIGGER) { + trig = &desc->trigs[dev->trig_idx]; + if (trig->descriptor->disable) { + ret = trig->descriptor->disable(trig->instance); + if (ret) + return ret; + } + } + + dev->buffer.public.active_mask = 0; + if (dev->dev_descriptor->post_disable) + ret = dev->dev_descriptor->post_disable(dev->dev_instance); + + return ret; +} + +static int iio_call_submit(struct iiod_ctx *ctx, const char *device, + enum iio_buffer_direction dir) +{ + struct iio_dev_priv *dev; + + dev = get_iio_device(ctx->instance, device); + if (!dev || !dev->buffer.initalized) + return -EINVAL; + + dev->buffer.public.dir = dir; + if (dev->dev_descriptor->submit && dev->trig_idx == NO_TRIGGER) + return dev->dev_descriptor->submit(&dev->dev_data); + else if ((dir == IIO_DIRECTION_INPUT && dev->dev_descriptor->read_dev + && dev->trig_idx == NO_TRIGGER) + || (dir == IIO_DIRECTION_OUTPUT && + dev->dev_descriptor->write_dev && dev->trig_idx == NO_TRIGGER)) { + /* Code used to don't break devices using read_dev */ + int32_t ret; + void *buff; + struct iio_buffer *buffer = &dev->buffer.public; + + ret = iio_buffer_get_block(buffer, &buff); + if (NO_OS_IS_ERR_VALUE(ret)) + return ret; + + if (dir == IIO_DIRECTION_INPUT) + ret = dev->dev_descriptor->read_dev(dev->dev_instance, + buff, buffer->samples); + else + ret = dev->dev_descriptor->write_dev(dev->dev_instance, + buff, buffer->samples); + if (NO_OS_IS_ERR_VALUE(ret)) + return ret; + + return iio_buffer_block_done(buffer); + } + + return 0; +} + +static int iio_push_buffer(struct iiod_ctx *ctx, const char *device) +{ + return iio_call_submit(ctx, device, IIO_DIRECTION_OUTPUT); +} + +static int iio_refill_buffer(struct iiod_ctx *ctx, const char *device) +{ + return iio_call_submit(ctx, device, IIO_DIRECTION_INPUT); +} + +/** + * @brief Read chunk of data from RAM to pbuf. Call + * "iio_transfer_dev_to_mem()" first. + * @param device - String containing device name. + * @param pbuf - Buffer where value is stored. + * @param offset - Offset to the remaining data after reading n chunks. + * @param bytes_count - Number of bytes to read. + * @return: Bytes_count or negative value in case of error. + */ +static int iio_read_buffer(struct iiod_ctx *ctx, const char *device, char *buf, + uint32_t bytes) +{ + struct iio_dev_priv *dev; + int32_t ret; + uint32_t size; + + dev = get_iio_device(ctx->instance, device); + if (!dev || !dev->buffer.initalized) + return -EINVAL; + + ret = no_os_cb_size(&dev->buffer.cb, &size); +#ifdef IIO_IGNORE_BUFF_OVERRUN_ERR +#warning Buffer overrun error checking is disabled. + if (ret != -NO_OS_EOVERRUN) +#endif + if (NO_OS_IS_ERR_VALUE(ret)) + return ret; + + bytes = no_os_min(size, bytes); + if (!bytes) + return -EAGAIN; + + + ret = no_os_cb_read(&dev->buffer.cb, buf, bytes); +#ifdef IIO_IGNORE_BUFF_OVERRUN_ERR + if (ret != -NO_OS_EOVERRUN) +#endif + if (NO_OS_IS_ERR_VALUE(ret)) + return ret; + + return bytes; +} + + +/** + * @brief Write chunk of data into RAM. + * @param device - String containing device name. + * @param buf - Values to write. + * @param offset - Offset in memory after the nth chunk of data. + * @param bytes_count - Number of bytes to write. + * @return Bytes_count or negative value in case of error. + */ +static int iio_write_buffer(struct iiod_ctx *ctx, const char *device, + const char *buf, uint32_t bytes) +{ + struct iio_dev_priv *dev; + int32_t ret; + uint32_t available; + uint32_t size; + + dev = get_iio_device(ctx->instance, device); + if (!dev || !dev->buffer.initalized) + return -EINVAL; + + ret = no_os_cb_size(&dev->buffer.cb, &size); + if (NO_OS_IS_ERR_VALUE(ret)) + return ret; + + available = dev->buffer.public.size - size; + bytes = no_os_min(available, bytes); + ret = no_os_cb_write(&dev->buffer.cb, buf, bytes); + if (NO_OS_IS_ERR_VALUE(ret)) + return ret; + + return bytes; +} + +int iio_buffer_get_block(struct iio_buffer *buffer, void **addr) +{ + uint32_t size; + + if (!buffer) + return -EINVAL; + + if (buffer->dir == IIO_DIRECTION_INPUT) + return no_os_cb_prepare_async_write(buffer->buf, buffer->size, addr, &size); + + return no_os_cb_prepare_async_read(buffer->buf, buffer->size, addr, &size); +} + +int iio_buffer_block_done(struct iio_buffer *buffer) +{ + if (!buffer) + return -EINVAL; + + if (buffer->dir == IIO_DIRECTION_INPUT) + return no_os_cb_end_async_write(buffer->buf); + + return no_os_cb_end_async_read(buffer->buf); +} + +/* Write to buffer iio_buffer.bytes_per_scan bytes from data */ +int iio_buffer_push_scan(struct iio_buffer *buffer, void *data) +{ + if (!buffer) + return -EINVAL; + + return no_os_cb_write(buffer->buf, data, buffer->bytes_per_scan); +} + +/* Read from buffer iio_buffer.bytes_per_scan bytes into data */ +int iio_buffer_pop_scan(struct iio_buffer *buffer, void *data) +{ + if (!buffer) + return -EINVAL; + + int ret; + + ret = no_os_cb_read(buffer->buf, data, buffer->bytes_per_scan); + + if (buffer->cyclic_info.is_cyclic) { + if (buffer->buf->read.idx == buffer->buf->write.idx) + buffer->buf->read.idx = 0; + } + + return ret; +} + +#if defined(NO_OS_NETWORKING) || defined(NO_OS_LWIP_NETWORKING) + +static int32_t accept_network_clients(struct iio_desc *desc) +{ + struct tcp_socket_desc *sock; + struct iiod_conn_data data; + int32_t ret; + uint32_t id; + + do { + ret = socket_accept(desc->server, &sock); + if (NO_OS_IS_ERR_VALUE(ret)) + return ret; + + data.conn = sock; + data.buf = no_os_calloc(1, IIOD_CONN_BUFFER_SIZE); + data.len = IIOD_CONN_BUFFER_SIZE; + + if (!data.buf) { + ret = -ENOMEM; + goto close_socket; + } + + ret = iiod_conn_add(desc->iiod, &data, &id); + if (NO_OS_IS_ERR_VALUE(ret)) + goto free_buf; + + ret = _push_conn(desc, id); + if (NO_OS_IS_ERR_VALUE(ret)) + goto remove_conn; + } while (true); + + return 0; + +remove_conn: + iiod_conn_remove(desc->iiod, id, &data); +free_buf: + no_os_free(data.buf); +close_socket: + socket_remove(sock); + + return ret; +} +#endif + +/** + * @brief Execute an iio step + * @param desc - IIo descriptor + * @return 0 in case of success or negative value otherwise. + */ +int iio_step(struct iio_desc *desc) +{ + struct iiod_conn_data data; + uint32_t conn_id; + int32_t ret; + + iio_process_async_triggers(desc); + +#if defined(NO_OS_NETWORKING) || defined(NO_OS_LWIP_NETWORKING) + if (desc->server) { + ret = accept_network_clients(desc); + if (NO_OS_IS_ERR_VALUE(ret) && ret != -EAGAIN) + return ret; +#if defined(NO_OS_LWIP_NETWORKING) + no_os_lwip_step(desc->server->net->net, desc->server->net->net); +#endif + } +#endif + + ret = _pop_conn(desc, &conn_id); + if (NO_OS_IS_ERR_VALUE(ret)) + return ret; + + ret = iiod_conn_step(desc->iiod, conn_id); + if (ret == -ENOTCONN) { +#if defined(NO_OS_NETWORKING) || defined(NO_OS_LWIP_NETWORKING) + iiod_conn_remove(desc->iiod, conn_id, &data); + socket_remove(data.conn); + no_os_free(data.buf); +#endif + } else { + _push_conn(desc, conn_id); + } + + return ret; +} + +/** + * @brief Add context attributes into xml string buffer. + * @param desc - IIo descriptor. + * @param buff - xml buffer. + * @param buff_size - size of buffer + * @return 0 in case of success or negative value otherwise. + */ +static uint32_t iio_add_ctx_attr_in_xml(struct iio_desc *desc, char *buff, + uint32_t buff_size) +{ + struct iio_ctx_attr *attr; + char dummy_buff[50]; + int32_t i; + int32_t j; + int32_t n; + + if ((int32_t)buff_size == -1) + n = 0; + else + n = buff_size; + + if (buff == NULL) + /* Set dummy value for buff. It is used only for counting */ + buff = dummy_buff; + + i = 0; + + attr = desc->ctx_attrs; + if (attr) + for (j = 0; j < (int32_t)desc->nb_ctx_attr; j++) { + i += snprintf(buff + i, + no_os_max(n - i, 0), + "", + attr[j].value); + } + + return i; +} + +/* + * Generate an xml describing a device and write it to buff. + * Will return the size of the xml. + * If buff_size is 0, no data will be written to buff, but size will be returned + */ +static uint32_t iio_generate_device_xml(struct iio_device *device, char *name, + char *id, char *buff, + uint32_t buff_size) +{ + struct iio_channel *ch; + struct iio_attribute *attr; + char ch_id[50]; + int32_t i; + int32_t j; + int32_t k; + int32_t n; + + if ((int32_t)buff_size == -1) + n = 0; + else + n = buff_size; + + if (buff == NULL) + /* Set dummy value for buff. It is used only for counting */ + buff = ch_id; + + i = 0; + + i += snprintf(buff + i, no_os_max(n - i, 0), + "", id, name); + + /* Write channels */ + if (device->channels) + for (j = 0; j < device->num_ch; j++) { + ch = &device->channels[j]; + _print_ch_id(ch_id, ch); + i += snprintf(buff + i, no_os_max(n - i, 0), + "name) + i += snprintf(buff + i, no_os_max(n - i, 0), + " name=\"%s\"", + ch->name); + i += snprintf(buff + i, no_os_max(n - i, 0), + " type=\"%s\" >", + ch->ch_out ? "output" : "input"); + + if (ch->scan_type) + i += snprintf(buff + i, no_os_max(n - i, 0), + ">%d\" />", + ch->scan_index, + ch->scan_type->is_big_endian ? "be" : "le", + ch->scan_type->sign, + ch->scan_type->realbits, + ch->scan_type->storagebits, + ch->scan_type->shift); + + /* Write channel attributes */ + if (ch->attributes) + for (k = 0; ch->attributes[k].name; k++) { + attr = &ch->attributes[k]; + i += snprintf(buff + i, no_os_max(n - i, 0), "name); + if (ch->diferential) { + switch (attr->shared) { + case IIO_SHARED_BY_ALL: + i += snprintf(buff + i, no_os_max(n - i, 0), + "filename=\"%s\"", + attr->name); + break; + case IIO_SHARED_BY_DIR: + i += snprintf(buff + i, no_os_max(n - i, 0), + "filename=\"%s_%s\"", + ch->ch_out ? "out" : "in", + attr->name); + break; + case IIO_SHARED_BY_TYPE: + i += snprintf(buff + i, no_os_max(n - i, 0), + "filename=\"%s_%s-%s_%s\"", + ch->ch_out ? "out" : "in", + iio_chan_type_string[ch->ch_type], + iio_chan_type_string[ch->ch_type], + attr->name); + break; + case IIO_SEPARATE: + if (!ch->indexed) { + // Differential channels must be indexed! + return -EINVAL; + } + i += snprintf(buff + i, no_os_max(n - i, 0), + "filename=\"%s_%s%d-%s%d_%s\"", + ch->ch_out ? "out" : "in", + iio_chan_type_string[ch->ch_type], + ch->channel, + iio_chan_type_string[ch->ch_type], + ch->channel2, + attr->name); + break; + } + } else { + switch (attr->shared) { + case IIO_SHARED_BY_ALL: + i += snprintf(buff + i, no_os_max(n - i, 0), + "filename=\"%s\"", + attr->name); + break; + case IIO_SHARED_BY_DIR: + i += snprintf(buff + i, no_os_max(n - i, 0), + "filename=\"%s_%s\"", + ch->ch_out ? "out" : "in", + attr->name); + break; + case IIO_SHARED_BY_TYPE: + i += snprintf(buff + i, no_os_max(n - i, 0), + "filename=\"%s_%s_%s\"", + ch->ch_out ? "out" : "in", + iio_chan_type_string[ch->ch_type], + attr->name); + break; + case IIO_SEPARATE: + if (ch->indexed) + i += snprintf(buff + i, no_os_max(n - i, 0), + "filename=\"%s_%s%d_%s\"", + ch->ch_out ? "out" : "in", + iio_chan_type_string[ch->ch_type], + ch->channel, + attr->name); + else + i += snprintf(buff + i, no_os_max(n - i, 0), + "filename=\"%s_%s_%s\"", + ch->ch_out ? "out" : "in", + iio_chan_type_string[ch->ch_type], + attr->name); + break; + } + } + i += snprintf(buff + i, no_os_max(n - i, 0), " />"); + } + + i += snprintf(buff + i, no_os_max(n - i, 0), ""); + } + + /* Write device attributes */ + if (device->attributes) + for (j = 0; device->attributes[j].name; j++) + i += snprintf(buff + i, no_os_max(n - i, 0), + "", + device->attributes[j].name); + + /* Write debug attributes */ + if (device->debug_attributes) + for (j = 0; device->debug_attributes[j].name; j++) + i += snprintf(buff + i, no_os_max(n - i, 0), + "", + device->debug_attributes[j].name); + if (device->debug_reg_read || device->debug_reg_write) + i += snprintf(buff + i, no_os_max(n - i, 0), + ""); + + /* Write buffer attributes */ + if (device->buffer_attributes) + for (j = 0; device->buffer_attributes[j].name; j++) + i += snprintf(buff + i, no_os_max(n - i, 0), + "", + device->buffer_attributes[j].name); + + i += snprintf(buff + i, no_os_max(n - i, 0), ""); + + return i; +} + +static int32_t iio_init_xml(struct iio_desc *desc) +{ + struct iio_dev_priv *dev; + struct iio_trig_priv *trig; + struct iio_device dummy = { 0 }; + uint32_t i, size, of; + + /* -2 because of the 0 character */ + size = sizeof(header) + sizeof(header_end) - 2; + size += iio_add_ctx_attr_in_xml(desc, NULL, -1); + for (i = 0; i < desc->nb_devs; i++) { + dev = desc->devs + i; + size += iio_generate_device_xml(dev->dev_descriptor, + (char *)dev->name, + dev->dev_id, NULL, -1); + } + for (i = 0; i < desc->nb_trigs; i++) { + trig = desc->trigs + i; + dummy.attributes = trig->descriptor->attributes; + size += iio_generate_device_xml(&dummy, trig->name, trig->id, + NULL, -1); + } + + desc->xml_desc = (char *)no_os_calloc(size + 1, sizeof(*desc->xml_desc)); + if (!desc->xml_desc) + return -ENOMEM; + + desc->xml_size = size; + + strcpy(desc->xml_desc, header); + of = sizeof(header) - 1; + of += iio_add_ctx_attr_in_xml(desc, desc->xml_desc + of, size - of); + for (i = 0; i < desc->nb_devs; i++) { + dev = desc->devs + i; + of += iio_generate_device_xml(dev->dev_descriptor, + (char *)dev->name, dev->dev_id, + desc->xml_desc + of, size - of); + } + for (i = 0; i < desc->nb_trigs; i++) { + trig = desc->trigs + i; + dummy.attributes = trig->descriptor->attributes; + of += iio_generate_device_xml(&dummy, trig->name, trig->id, + desc->xml_desc + of, size - of); + } + + strcpy(desc->xml_desc + of, header_end); + + return 0; +} + +static int32_t iio_init_devs(struct iio_desc *desc, + struct iio_device_init *devs, uint32_t n) +{ + uint32_t i; + struct iio_dev_priv *ldev; + struct iio_device_init *ndev; + + desc->nb_devs = n; + desc->devs = (struct iio_dev_priv *)no_os_calloc(desc->nb_devs, + sizeof(*desc->devs)); + if (!desc->devs) + return -ENOMEM; + + for (i = 0; i < n; i++) { + ndev = devs + i; + ldev = desc->devs + i; + ldev->dev_descriptor = ndev->dev_descriptor; + sprintf(ldev->dev_id, "iio:device%"PRIu32"", i); + ldev->trig_idx = iio_get_trig_idx_by_id(desc, ndev->trigger_id); + ldev->dev_instance = ndev->dev; + ldev->dev_data.dev = ndev->dev; + ldev->dev_data.buffer = &ldev->buffer.public; + ldev->name = ndev->name; + if (ndev->dev_descriptor->read_dev || + ndev->dev_descriptor->write_dev || + ndev->dev_descriptor->submit || + ndev->dev_descriptor->trigger_handler) { + ldev->buffer.raw_buf = ndev->raw_buf; + ldev->buffer.raw_buf_len = ndev->raw_buf_len; + ldev->buffer.public.buf = &ldev->buffer.cb; + ldev->buffer.initalized = 1; + } else { + ldev->buffer.initalized = 0; + } + } + + return 0; +} + +/** + * @brief Initializes IIO triggers. + * @param desc - IIO descriptor. + * @param trigs - Triggers array. + * @param n - Number of triggers to be initialized. + * @return 0 in case of success or negative value otherwise. + */ +static int32_t iio_init_trigs(struct iio_desc *desc, + struct iio_trigger_init *trigs, uint32_t n) +{ + uint32_t i; + struct iio_trig_priv *trig_priv_iter; + struct iio_trigger_init *trig_init_iter; + + desc->nb_trigs = n; + desc->trigs = (struct iio_trig_priv *)no_os_calloc(desc->nb_trigs, + sizeof(*desc->trigs)); + if (!desc->trigs) + return -ENOMEM; + + for (i = 0; i < n; i++) { + trig_init_iter = trigs + i; + trig_priv_iter = desc->trigs + i; + trig_priv_iter->instance = trig_init_iter->trig; + trig_priv_iter->name = trig_init_iter->name; + trig_priv_iter->descriptor = trig_init_iter->descriptor; + sprintf(trig_priv_iter->id, "trigger%"PRIu32"", i); + } + + return 0; +} + +/** + * @brief Set communication ops and read/write ops + * @param desc - iio descriptor. + * @param init_param - appropriate init param. + * @return 0 in case of success or negative value otherwise. + */ +int iio_init(struct iio_desc **desc, struct iio_init_param *init_param) +{ + int32_t ret; + struct iio_desc *ldesc; + struct iiod_ops *ops; + struct iiod_init_param iiod_param; + uint32_t conn_id; + + if (!desc || !init_param) + return -EINVAL; + + ldesc = (struct iio_desc *)no_os_calloc(1, sizeof(*ldesc)); + if (!ldesc) + return -ENOMEM; + + ldesc->ctx_attrs = init_param->ctx_attrs; + ldesc->nb_ctx_attr = init_param->nb_ctx_attr; + + ret = iio_init_trigs(ldesc, init_param->trigs, init_param->nb_trigs); + if (NO_OS_IS_ERR_VALUE(ret)) + goto free_devs; + + ret = iio_init_devs(ldesc, init_param->devs, init_param->nb_devs); + if (NO_OS_IS_ERR_VALUE(ret)) + goto free_desc; + + ret = iio_init_xml(ldesc); + if (NO_OS_IS_ERR_VALUE(ret)) + goto free_trigs; + + /* device operations */ + ops = &ldesc->iiod_ops; + ops->read_attr = iio_read_attr; + ops->write_attr = iio_write_attr; + ops->get_trigger = iio_get_trigger; + ops->set_trigger = iio_set_trigger; + ops->read_buffer = iio_read_buffer; + ops->write_buffer = iio_write_buffer; + ops->refill_buffer = iio_refill_buffer; + ops->push_buffer = iio_push_buffer; + ops->open = iio_open_dev; + ops->close = iio_close_dev; + ops->send = iio_send; + ops->recv = iio_recv; + ops->set_buffers_count = iio_set_buffers_count; + + iiod_param.instance = ldesc; + iiod_param.ops = ops; + iiod_param.xml = ldesc->xml_desc; + iiod_param.xml_len = ldesc->xml_size; + iiod_param.phy_type = init_param->phy_type; + + ret = iiod_init(&ldesc->iiod, &iiod_param); + if (NO_OS_IS_ERR_VALUE(ret)) + goto free_xml; + + ret = no_os_cb_init(&ldesc->conns, + sizeof(uint32_t) * (IIOD_MAX_CONNECTIONS + 1)); + if (NO_OS_IS_ERR_VALUE(ret)) + goto free_iiod; + + if (init_param->phy_type == USE_UART) { + ldesc->send = (int (*)())no_os_uart_write; + ldesc->recv = (int (*)())no_os_uart_read; + ldesc->uart_desc = init_param->uart_desc; + + struct iiod_conn_data data = { + .conn = ldesc->uart_desc, + .buf = uart_buff, + .len = sizeof(uart_buff) + }; + ret = iiod_conn_add(ldesc->iiod, &data, &conn_id); + if (NO_OS_IS_ERR_VALUE(ret)) + goto free_conns; + _push_conn(ldesc, conn_id); + } +#if defined(NO_OS_NETWORKING) || defined(NO_OS_LWIP_NETWORKING) + else if (init_param->phy_type == USE_NETWORK) { + ldesc->send = (int (*)())socket_send; + ldesc->recv = (int (*)())socket_recv; + ret = socket_init(&ldesc->server, + init_param->tcp_socket_init_param); + if (NO_OS_IS_ERR_VALUE(ret)) + goto free_conns; + ret = socket_bind(ldesc->server, IIOD_PORT); + if (NO_OS_IS_ERR_VALUE(ret)) + goto free_pylink; + ret = socket_listen(ldesc->server, MAX_BACKLOG); + if (NO_OS_IS_ERR_VALUE(ret)) + goto free_pylink; + } +#endif + else if (init_param->phy_type == USE_LOCAL_BACKEND) { + ldesc->recv = init_param->local_backend->local_backend_event_read; + ldesc->send = init_param->local_backend->local_backend_event_write; + + struct iiod_conn_data data = { + .conn = NULL, + .buf = init_param->local_backend->local_backend_buff, + .len = init_param->local_backend->local_backend_buff_len + }; + ret = iiod_conn_add(ldesc->iiod, &data, &conn_id); + if (NO_OS_IS_ERR_VALUE(ret)) + goto free_conns; + _push_conn(ldesc, conn_id); + } else { + ret = -EINVAL; + goto free_conns; + } + + *desc = ldesc; + + return 0; + +free_pylink: +#if defined(NO_OS_NETWORKING) || defined(NO_OS_LWIP_NETWORKING) + socket_remove(ldesc->server); +#endif +free_conns: + no_os_cb_remove(ldesc->conns); +free_iiod: + iiod_remove(ldesc->iiod); +free_xml: + no_os_free(ldesc->xml_desc); +free_trigs: + no_os_free(ldesc->trigs); +free_devs: + no_os_free(ldesc->devs); +free_desc: + no_os_free(ldesc); + + return ret; +} + +/** + * @brief Free the resources allocated by "iio_init()". + * @param desc: iio descriptor. + * @return 0 in case of success or negative value otherwise. + */ +int iio_remove(struct iio_desc *desc) +{ + struct iiod_conn_data data; + int ret; + + if (!desc) + return -EINVAL; + +#if defined(NO_OS_NETWORKING) || defined(NO_OS_LWIP_NETWORKING) + for (int i = 0; i < IIOD_MAX_CONNECTIONS; i++) { + ret = iiod_conn_remove(desc->iiod, i, &data); + if (!ret) { + no_os_free(data.buf); + socket_remove(data.conn); + } + } + socket_remove(desc->server); +#endif + no_os_cb_remove(desc->conns); + iiod_remove(desc->iiod); + no_os_free(desc->devs); + no_os_free(desc->trigs); + no_os_free(desc->xml_desc); + no_os_free(desc); + + return 0; +} diff --git a/14_RADAR_Old_version/Firmware/Microcontroller/iio.h b/14_RADAR_Old_version/Firmware/Microcontroller/iio.h new file mode 100644 index 0000000..c277acb --- /dev/null +++ b/14_RADAR_Old_version/Firmware/Microcontroller/iio.h @@ -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_ */ diff --git a/14_RADAR_Old_version/Firmware/Microcontroller/iio_adf4382.c b/14_RADAR_Old_version/Firmware/Microcontroller/iio_adf4382.c new file mode 100644 index 0000000..da91a24 --- /dev/null +++ b/14_RADAR_Old_version/Firmware/Microcontroller/iio_adf4382.c @@ -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 +#include +#include +#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; +} diff --git a/14_RADAR_Old_version/Firmware/Microcontroller/iio_adf4382.h b/14_RADAR_Old_version/Firmware/Microcontroller/iio_adf4382.h new file mode 100644 index 0000000..58b2eab --- /dev/null +++ b/14_RADAR_Old_version/Firmware/Microcontroller/iio_adf4382.h @@ -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 diff --git a/14_RADAR_Old_version/Firmware/Microcontroller/iio_app.c b/14_RADAR_Old_version/Firmware/Microcontroller/iio_app.c new file mode 100644 index 0000000..5840788 --- /dev/null +++ b/14_RADAR_Old_version/Firmware/Microcontroller/iio_app.c @@ -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 +#include +#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 +#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, ¶m.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 diff --git a/14_RADAR_Old_version/Firmware/Microcontroller/iio_app.h b/14_RADAR_Old_version/Firmware/Microcontroller/iio_app.h new file mode 100644 index 0000000..6c11132 --- /dev/null +++ b/14_RADAR_Old_version/Firmware/Microcontroller/iio_app.h @@ -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 diff --git a/14_RADAR_Old_version/Firmware/Microcontroller/iio_trigger.c b/14_RADAR_Old_version/Firmware/Microcontroller/iio_trigger.c new file mode 100644 index 0000000..e4796cd --- /dev/null +++ b/14_RADAR_Old_version/Firmware/Microcontroller/iio_trigger.c @@ -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 +#include +#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; +} diff --git a/14_RADAR_Old_version/Firmware/Microcontroller/iio_trigger.h b/14_RADAR_Old_version/Firmware/Microcontroller/iio_trigger.h new file mode 100644 index 0000000..115a0a2 --- /dev/null +++ b/14_RADAR_Old_version/Firmware/Microcontroller/iio_trigger.h @@ -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_ */ diff --git a/14_RADAR_Old_version/Firmware/Microcontroller/iio_types.h b/14_RADAR_Old_version/Firmware/Microcontroller/iio_types.h new file mode 100644 index 0000000..712b281 --- /dev/null +++ b/14_RADAR_Old_version/Firmware/Microcontroller/iio_types.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 +#include +#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_ */ diff --git a/14_RADAR_Old_version/Firmware/Microcontroller/iiod.c b/14_RADAR_Old_version/Firmware/Microcontroller/iiod.c new file mode 100644 index 0000000..892bd90 --- /dev/null +++ b/14_RADAR_Old_version/Firmware/Microcontroller/iiod.c @@ -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 +#include +#include +#include +#include + +#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; +} diff --git a/14_RADAR_Old_version/Firmware/Microcontroller/iiod.h b/14_RADAR_Old_version/Firmware/Microcontroller/iiod.h new file mode 100644 index 0000000..dce63cf --- /dev/null +++ b/14_RADAR_Old_version/Firmware/Microcontroller/iiod.h @@ -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 +#include + +#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 diff --git a/14_RADAR_Old_version/Firmware/Microcontroller/iiod_private.h b/14_RADAR_Old_version/Firmware/Microcontroller/iiod_private.h new file mode 100644 index 0000000..ee1591f --- /dev/null +++ b/14_RADAR_Old_version/Firmware/Microcontroller/iiod_private.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 diff --git a/14_RADAR_Old_version/Firmware/Microcontroller/jesd204.h b/14_RADAR_Old_version/Firmware/Microcontroller/jesd204.h new file mode 100644 index 0000000..a23b1c1 --- /dev/null +++ b/14_RADAR_Old_version/Firmware/Microcontroller/jesd204.h @@ -0,0 +1,295 @@ +/** + * The JESD204 framework + * + * Copyright (c) 2022 Analog Devices Inc. + */ +#ifndef _JESD204_H_ +#define _JESD204_H_ + +#include +#include +#include + +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 diff --git a/14_RADAR_Old_version/Firmware/Microcontroller/main.cpp b/14_RADAR_Old_version/Firmware/Microcontroller/main.cpp new file mode 100644 index 0000000..ff18e92 --- /dev/null +++ b/14_RADAR_Old_version/Firmware/Microcontroller/main.cpp @@ -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 +#include +#include +#include +#include +#include +#include +#include +/* 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 */ diff --git a/14_RADAR_Old_version/Firmware/Microcontroller/main.h b/14_RADAR_Old_version/Firmware/Microcontroller/main.h new file mode 100644 index 0000000..f3671b6 --- /dev/null +++ b/14_RADAR_Old_version/Firmware/Microcontroller/main.h @@ -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 */ diff --git a/14_RADAR_Old_version/Firmware/Microcontroller/no_os_ain.h b/14_RADAR_Old_version/Firmware/Microcontroller/no_os_ain.h new file mode 100644 index 0000000..bdecf43 --- /dev/null +++ b/14_RADAR_Old_version/Firmware/Microcontroller/no_os_ain.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 + + +/** + * @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 diff --git a/14_RADAR_Old_version/Firmware/Microcontroller/no_os_alloc.c b/14_RADAR_Old_version/Firmware/Microcontroller/no_os_alloc.c new file mode 100644 index 0000000..cf5a12c --- /dev/null +++ b/14_RADAR_Old_version/Firmware/Microcontroller/no_os_alloc.c @@ -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); +} diff --git a/14_RADAR_Old_version/Firmware/Microcontroller/no_os_alloc.h b/14_RADAR_Old_version/Firmware/Microcontroller/no_os_alloc.h new file mode 100644 index 0000000..51f6567 --- /dev/null +++ b/14_RADAR_Old_version/Firmware/Microcontroller/no_os_alloc.h @@ -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 +#include + +/* 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_ diff --git a/14_RADAR_Old_version/Firmware/Microcontroller/no_os_aout.h b/14_RADAR_Old_version/Firmware/Microcontroller/no_os_aout.h new file mode 100644 index 0000000..95a22f7 --- /dev/null +++ b/14_RADAR_Old_version/Firmware/Microcontroller/no_os_aout.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 + + +/** + * @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 diff --git a/14_RADAR_Old_version/Firmware/Microcontroller/no_os_axi_io.h b/14_RADAR_Old_version/Firmware/Microcontroller/no_os_axi_io.h new file mode 100644 index 0000000..c346559 --- /dev/null +++ b/14_RADAR_Old_version/Firmware/Microcontroller/no_os_axi_io.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 + +/* 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_ diff --git a/14_RADAR_Old_version/Firmware/Microcontroller/no_os_circular_buffer.c b/14_RADAR_Old_version/Firmware/Microcontroller/no_os_circular_buffer.c new file mode 100644 index 0000000..008aff8 --- /dev/null +++ b/14_RADAR_Old_version/Firmware/Microcontroller/no_os_circular_buffer.c @@ -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 +#include +#include +#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); +} diff --git a/14_RADAR_Old_version/Firmware/Microcontroller/no_os_circular_buffer.h b/14_RADAR_Old_version/Firmware/Microcontroller/no_os_circular_buffer.h new file mode 100644 index 0000000..f5bec93 --- /dev/null +++ b/14_RADAR_Old_version/Firmware/Microcontroller/no_os_circular_buffer.h @@ -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 + +/** + * @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_ diff --git a/14_RADAR_Old_version/Firmware/Microcontroller/no_os_clk.c b/14_RADAR_Old_version/Firmware/Microcontroller/no_os_clk.c new file mode 100644 index 0000000..8c80d34 --- /dev/null +++ b/14_RADAR_Old_version/Firmware/Microcontroller/no_os_clk.c @@ -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); +} diff --git a/14_RADAR_Old_version/Firmware/Microcontroller/no_os_clk.h b/14_RADAR_Old_version/Firmware/Microcontroller/no_os_clk.h new file mode 100644 index 0000000..9a6ba9d --- /dev/null +++ b/14_RADAR_Old_version/Firmware/Microcontroller/no_os_clk.h @@ -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 + +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_ diff --git a/14_RADAR_Old_version/Firmware/Microcontroller/no_os_crc.h b/14_RADAR_Old_version/Firmware/Microcontroller/no_os_crc.h new file mode 100644 index 0000000..f90ceb2 --- /dev/null +++ b/14_RADAR_Old_version/Firmware/Microcontroller/no_os_crc.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_ diff --git a/14_RADAR_Old_version/Firmware/Microcontroller/no_os_crc16.c b/14_RADAR_Old_version/Firmware/Microcontroller/no_os_crc16.c new file mode 100644 index 0000000..db12788 --- /dev/null +++ b/14_RADAR_Old_version/Firmware/Microcontroller/no_os_crc16.c @@ -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; +} diff --git a/14_RADAR_Old_version/Firmware/Microcontroller/no_os_crc16.h b/14_RADAR_Old_version/Firmware/Microcontroller/no_os_crc16.h new file mode 100644 index 0000000..a168e4d --- /dev/null +++ b/14_RADAR_Old_version/Firmware/Microcontroller/no_os_crc16.h @@ -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 +#include + +#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_ diff --git a/14_RADAR_Old_version/Firmware/Microcontroller/no_os_crc24.c b/14_RADAR_Old_version/Firmware/Microcontroller/no_os_crc24.c new file mode 100644 index 0000000..dbeeae0 --- /dev/null +++ b/14_RADAR_Old_version/Firmware/Microcontroller/no_os_crc24.c @@ -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); +} diff --git a/14_RADAR_Old_version/Firmware/Microcontroller/no_os_crc24.h b/14_RADAR_Old_version/Firmware/Microcontroller/no_os_crc24.h new file mode 100644 index 0000000..854a2ef --- /dev/null +++ b/14_RADAR_Old_version/Firmware/Microcontroller/no_os_crc24.h @@ -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 +#include + +#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_ diff --git a/14_RADAR_Old_version/Firmware/Microcontroller/no_os_crc8.c b/14_RADAR_Old_version/Firmware/Microcontroller/no_os_crc8.c new file mode 100644 index 0000000..3a8d15c --- /dev/null +++ b/14_RADAR_Old_version/Firmware/Microcontroller/no_os_crc8.c @@ -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; +} diff --git a/14_RADAR_Old_version/Firmware/Microcontroller/no_os_crc8.h b/14_RADAR_Old_version/Firmware/Microcontroller/no_os_crc8.h new file mode 100644 index 0000000..b2eadfd --- /dev/null +++ b/14_RADAR_Old_version/Firmware/Microcontroller/no_os_crc8.h @@ -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 +#include + +#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_ diff --git a/14_RADAR_Old_version/Firmware/Microcontroller/no_os_delay.h b/14_RADAR_Old_version/Firmware/Microcontroller/no_os_delay.h new file mode 100644 index 0000000..d287f14 --- /dev/null +++ b/14_RADAR_Old_version/Firmware/Microcontroller/no_os_delay.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 + +/** + * @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_ diff --git a/14_RADAR_Old_version/Firmware/Microcontroller/no_os_dma.c b/14_RADAR_Old_version/Firmware/Microcontroller/no_os_dma.c new file mode 100644 index 0000000..7e46a96 --- /dev/null +++ b/14_RADAR_Old_version/Firmware/Microcontroller/no_os_dma.c @@ -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 +#include "no_os_dma.h" +#include +#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; +} diff --git a/14_RADAR_Old_version/Firmware/Microcontroller/no_os_dma.h b/14_RADAR_Old_version/Firmware/Microcontroller/no_os_dma.h new file mode 100644 index 0000000..912c47a --- /dev/null +++ b/14_RADAR_Old_version/Firmware/Microcontroller/no_os_dma.h @@ -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 +#include +#include + +#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 diff --git a/14_RADAR_Old_version/Firmware/Microcontroller/no_os_eeprom.c b/14_RADAR_Old_version/Firmware/Microcontroller/no_os_eeprom.c new file mode 100644 index 0000000..d6536ed --- /dev/null +++ b/14_RADAR_Old_version/Firmware/Microcontroller/no_os_eeprom.c @@ -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 +#include +#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); +} diff --git a/14_RADAR_Old_version/Firmware/Microcontroller/no_os_eeprom.h b/14_RADAR_Old_version/Firmware/Microcontroller/no_os_eeprom.h new file mode 100644 index 0000000..37bb679 --- /dev/null +++ b/14_RADAR_Old_version/Firmware/Microcontroller/no_os_eeprom.h @@ -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 + + +/* 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_ diff --git a/14_RADAR_Old_version/Firmware/Microcontroller/no_os_error.h b/14_RADAR_Old_version/Firmware/Microcontroller/no_os_error.h new file mode 100644 index 0000000..3aa0c81 --- /dev/null +++ b/14_RADAR_Old_version/Firmware/Microcontroller/no_os_error.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 + +#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_ diff --git a/14_RADAR_Old_version/Firmware/Microcontroller/no_os_fifo.c b/14_RADAR_Old_version/Firmware/Microcontroller/no_os_fifo.c new file mode 100644 index 0000000..060d6f8 --- /dev/null +++ b/14_RADAR_Old_version/Firmware/Microcontroller/no_os_fifo.c @@ -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 +#include +#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; +} diff --git a/14_RADAR_Old_version/Firmware/Microcontroller/no_os_fifo.h b/14_RADAR_Old_version/Firmware/Microcontroller/no_os_fifo.h new file mode 100644 index 0000000..8a15659 --- /dev/null +++ b/14_RADAR_Old_version/Firmware/Microcontroller/no_os_fifo.h @@ -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 + +/** + * @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_ diff --git a/14_RADAR_Old_version/Firmware/Microcontroller/no_os_flash.h b/14_RADAR_Old_version/Firmware/Microcontroller/no_os_flash.h new file mode 100644 index 0000000..0f3a725 --- /dev/null +++ b/14_RADAR_Old_version/Firmware/Microcontroller/no_os_flash.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 + +/** + * @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_ diff --git a/14_RADAR_Old_version/Firmware/Microcontroller/no_os_font_8x8.c b/14_RADAR_Old_version/Firmware/Microcontroller/no_os_font_8x8.c new file mode 100644 index 0000000..d7fde18 --- /dev/null +++ b/14_RADAR_Old_version/Firmware/Microcontroller/no_os_font_8x8.c @@ -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 + +/* 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} +}; diff --git a/14_RADAR_Old_version/Firmware/Microcontroller/no_os_gpio.c b/14_RADAR_Old_version/Firmware/Microcontroller/no_os_gpio.c new file mode 100644 index 0000000..46c944e --- /dev/null +++ b/14_RADAR_Old_version/Firmware/Microcontroller/no_os_gpio.c @@ -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 +#include "no_os_gpio.h" +#include +#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; +} diff --git a/14_RADAR_Old_version/Firmware/Microcontroller/no_os_gpio.h b/14_RADAR_Old_version/Firmware/Microcontroller/no_os_gpio.h new file mode 100644 index 0000000..d45c110 --- /dev/null +++ b/14_RADAR_Old_version/Firmware/Microcontroller/no_os_gpio.h @@ -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 + +#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_ diff --git a/14_RADAR_Old_version/Firmware/Microcontroller/no_os_i2c.c b/14_RADAR_Old_version/Firmware/Microcontroller/no_os_i2c.c new file mode 100644 index 0000000..af7e11c --- /dev/null +++ b/14_RADAR_Old_version/Firmware/Microcontroller/no_os_i2c.c @@ -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 +#include "no_os_i2c.h" +#include +#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; +} diff --git a/14_RADAR_Old_version/Firmware/Microcontroller/no_os_i2c.h b/14_RADAR_Old_version/Firmware/Microcontroller/no_os_i2c.h new file mode 100644 index 0000000..ca4cfba --- /dev/null +++ b/14_RADAR_Old_version/Firmware/Microcontroller/no_os_i2c.h @@ -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 + +#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_ diff --git a/14_RADAR_Old_version/Firmware/Microcontroller/no_os_i3c.c b/14_RADAR_Old_version/Firmware/Microcontroller/no_os_i3c.c new file mode 100644 index 0000000..78e182c --- /dev/null +++ b/14_RADAR_Old_version/Firmware/Microcontroller/no_os_i3c.c @@ -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 +#include +#include +#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); +} diff --git a/14_RADAR_Old_version/Firmware/Microcontroller/no_os_i3c.h b/14_RADAR_Old_version/Firmware/Microcontroller/no_os_i3c.h new file mode 100644 index 0000000..0593c13 --- /dev/null +++ b/14_RADAR_Old_version/Firmware/Microcontroller/no_os_i3c.h @@ -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 +#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_ diff --git a/14_RADAR_Old_version/Firmware/Microcontroller/no_os_init.h b/14_RADAR_Old_version/Firmware/Microcontroller/no_os_init.h new file mode 100644 index 0000000..4f0d245 --- /dev/null +++ b/14_RADAR_Old_version/Firmware/Microcontroller/no_os_init.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_ diff --git a/14_RADAR_Old_version/Firmware/Microcontroller/no_os_irq.c b/14_RADAR_Old_version/Firmware/Microcontroller/no_os_irq.c new file mode 100644 index 0000000..3973a30 --- /dev/null +++ b/14_RADAR_Old_version/Firmware/Microcontroller/no_os_irq.c @@ -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 +#include +#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); +} diff --git a/14_RADAR_Old_version/Firmware/Microcontroller/no_os_irq.h b/14_RADAR_Old_version/Firmware/Microcontroller/no_os_irq.h new file mode 100644 index 0000000..fd9a2cd --- /dev/null +++ b/14_RADAR_Old_version/Firmware/Microcontroller/no_os_irq.h @@ -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 + +/** + * @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_ diff --git a/14_RADAR_Old_version/Firmware/Microcontroller/no_os_lf256fifo.c b/14_RADAR_Old_version/Firmware/Microcontroller/no_os_lf256fifo.c new file mode 100644 index 0000000..37ec2fb --- /dev/null +++ b/14_RADAR_Old_version/Firmware/Microcontroller/no_os_lf256fifo.c @@ -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 +#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); +} + diff --git a/14_RADAR_Old_version/Firmware/Microcontroller/no_os_lf256fifo.h b/14_RADAR_Old_version/Firmware/Microcontroller/no_os_lf256fifo.h new file mode 100644 index 0000000..a581d8e --- /dev/null +++ b/14_RADAR_Old_version/Firmware/Microcontroller/no_os_lf256fifo.h @@ -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 +#include +#include + +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 + diff --git a/14_RADAR_Old_version/Firmware/Microcontroller/no_os_list.c b/14_RADAR_Old_version/Firmware/Microcontroller/no_os_list.c new file mode 100644 index 0000000..8b4095b --- /dev/null +++ b/14_RADAR_Old_version/Firmware/Microcontroller/no_os_list.c @@ -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 + +/** + * @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; +} diff --git a/14_RADAR_Old_version/Firmware/Microcontroller/no_os_list.h b/14_RADAR_Old_version/Firmware/Microcontroller/no_os_list.h new file mode 100644 index 0000000..002d6be --- /dev/null +++ b/14_RADAR_Old_version/Firmware/Microcontroller/no_os_list.h @@ -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 +#include + +/** + * @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_ diff --git a/14_RADAR_Old_version/Firmware/Microcontroller/no_os_mdio.c b/14_RADAR_Old_version/Firmware/Microcontroller/no_os_mdio.c new file mode 100644 index 0000000..5c3aaa1 --- /dev/null +++ b/14_RADAR_Old_version/Firmware/Microcontroller/no_os_mdio.c @@ -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 +#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); +} diff --git a/14_RADAR_Old_version/Firmware/Microcontroller/no_os_mdio.h b/14_RADAR_Old_version/Firmware/Microcontroller/no_os_mdio.h new file mode 100644 index 0000000..8dc02b7 --- /dev/null +++ b/14_RADAR_Old_version/Firmware/Microcontroller/no_os_mdio.h @@ -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 +#include +#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 diff --git a/14_RADAR_Old_version/Firmware/Microcontroller/no_os_mutex.c b/14_RADAR_Old_version/Firmware/Microcontroller/no_os_mutex.c new file mode 100644 index 0000000..b5741e8 --- /dev/null +++ b/14_RADAR_Old_version/Firmware/Microcontroller/no_os_mutex.c @@ -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) {} + diff --git a/14_RADAR_Old_version/Firmware/Microcontroller/no_os_mutex.h b/14_RADAR_Old_version/Firmware/Microcontroller/no_os_mutex.h new file mode 100644 index 0000000..0ddbd8e --- /dev/null +++ b/14_RADAR_Old_version/Firmware/Microcontroller/no_os_mutex.h @@ -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_ diff --git a/14_RADAR_Old_version/Firmware/Microcontroller/no_os_pid.c b/14_RADAR_Old_version/Firmware/Microcontroller/no_os_pid.c new file mode 100644 index 0000000..c39bce4 --- /dev/null +++ b/14_RADAR_Old_version/Firmware/Microcontroller/no_os_pid.c @@ -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 +#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; +} diff --git a/14_RADAR_Old_version/Firmware/Microcontroller/no_os_pid.h b/14_RADAR_Old_version/Firmware/Microcontroller/no_os_pid.h new file mode 100644 index 0000000..20b212c --- /dev/null +++ b/14_RADAR_Old_version/Firmware/Microcontroller/no_os_pid.h @@ -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 +#include +#include + +/** + * @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 diff --git a/14_RADAR_Old_version/Firmware/Microcontroller/no_os_print_log.h b/14_RADAR_Old_version/Firmware/Microcontroller/no_os_print_log.h new file mode 100644 index 0000000..8a6877f --- /dev/null +++ b/14_RADAR_Old_version/Firmware/Microcontroller/no_os_print_log.h @@ -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 + +#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_ diff --git a/14_RADAR_Old_version/Firmware/Microcontroller/no_os_pwm.c b/14_RADAR_Old_version/Firmware/Microcontroller/no_os_pwm.c new file mode 100644 index 0000000..db6d0a4 --- /dev/null +++ b/14_RADAR_Old_version/Firmware/Microcontroller/no_os_pwm.c @@ -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 +#include "no_os_pwm.h" +#include +#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); +} diff --git a/14_RADAR_Old_version/Firmware/Microcontroller/no_os_pwm.h b/14_RADAR_Old_version/Firmware/Microcontroller/no_os_pwm.h new file mode 100644 index 0000000..278d518 --- /dev/null +++ b/14_RADAR_Old_version/Firmware/Microcontroller/no_os_pwm.h @@ -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 +#include + +#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_ diff --git a/14_RADAR_Old_version/Firmware/Microcontroller/no_os_rtc.h b/14_RADAR_Old_version/Firmware/Microcontroller/no_os_rtc.h new file mode 100644 index 0000000..5c7af0d --- /dev/null +++ b/14_RADAR_Old_version/Firmware/Microcontroller/no_os_rtc.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 + +/** + * @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_ diff --git a/14_RADAR_Old_version/Firmware/Microcontroller/no_os_semaphore.c b/14_RADAR_Old_version/Firmware/Microcontroller/no_os_semaphore.c new file mode 100644 index 0000000..b5c104a --- /dev/null +++ b/14_RADAR_Old_version/Firmware/Microcontroller/no_os_semaphore.c @@ -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) {} + diff --git a/14_RADAR_Old_version/Firmware/Microcontroller/no_os_semaphore.h b/14_RADAR_Old_version/Firmware/Microcontroller/no_os_semaphore.h new file mode 100644 index 0000000..e8f90d2 --- /dev/null +++ b/14_RADAR_Old_version/Firmware/Microcontroller/no_os_semaphore.h @@ -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_ diff --git a/14_RADAR_Old_version/Firmware/Microcontroller/no_os_sin_lut.c b/14_RADAR_Old_version/Firmware/Microcontroller/no_os_sin_lut.c new file mode 100644 index 0000000..0219bf2 --- /dev/null +++ b/14_RADAR_Old_version/Firmware/Microcontroller/no_os_sin_lut.c @@ -0,0 +1,68 @@ +#include + +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, +}; diff --git a/14_RADAR_Old_version/Firmware/Microcontroller/no_os_spi.c b/14_RADAR_Old_version/Firmware/Microcontroller/no_os_spi.c new file mode 100644 index 0000000..f752e01 --- /dev/null +++ b/14_RADAR_Old_version/Firmware/Microcontroller/no_os_spi.c @@ -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 +#include "no_os_spi.h" +#include +#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); +} diff --git a/14_RADAR_Old_version/Firmware/Microcontroller/no_os_spi.h b/14_RADAR_Old_version/Firmware/Microcontroller/no_os_spi.h new file mode 100644 index 0000000..9aa77cc --- /dev/null +++ b/14_RADAR_Old_version/Firmware/Microcontroller/no_os_spi.h @@ -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 + +#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_ diff --git a/14_RADAR_Old_version/Firmware/Microcontroller/no_os_tdm.c b/14_RADAR_Old_version/Firmware/Microcontroller/no_os_tdm.c new file mode 100644 index 0000000..e2bcf16 --- /dev/null +++ b/14_RADAR_Old_version/Firmware/Microcontroller/no_os_tdm.c @@ -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 +#include "no_os_tdm.h" +#include +#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); +} diff --git a/14_RADAR_Old_version/Firmware/Microcontroller/no_os_tdm.h b/14_RADAR_Old_version/Firmware/Microcontroller/no_os_tdm.h new file mode 100644 index 0000000..64fd5f7 --- /dev/null +++ b/14_RADAR_Old_version/Firmware/Microcontroller/no_os_tdm.h @@ -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 +#include + +/** + * @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_ diff --git a/14_RADAR_Old_version/Firmware/Microcontroller/no_os_timer.c b/14_RADAR_Old_version/Firmware/Microcontroller/no_os_timer.c new file mode 100644 index 0000000..d10870f --- /dev/null +++ b/14_RADAR_Old_version/Firmware/Microcontroller/no_os_timer.c @@ -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 +#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); +} diff --git a/14_RADAR_Old_version/Firmware/Microcontroller/no_os_timer.h b/14_RADAR_Old_version/Firmware/Microcontroller/no_os_timer.h new file mode 100644 index 0000000..3c8b565 --- /dev/null +++ b/14_RADAR_Old_version/Firmware/Microcontroller/no_os_timer.h @@ -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 + +#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_ diff --git a/14_RADAR_Old_version/Firmware/Microcontroller/no_os_trng.c b/14_RADAR_Old_version/Firmware/Microcontroller/no_os_trng.c new file mode 100644 index 0000000..a849c7a --- /dev/null +++ b/14_RADAR_Old_version/Firmware/Microcontroller/no_os_trng.c @@ -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 +#include "no_os_trng.h" +#include +#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); +} diff --git a/14_RADAR_Old_version/Firmware/Microcontroller/no_os_trng.h b/14_RADAR_Old_version/Firmware/Microcontroller/no_os_trng.h new file mode 100644 index 0000000..22fec6b --- /dev/null +++ b/14_RADAR_Old_version/Firmware/Microcontroller/no_os_trng.h @@ -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 + +/** + * @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_ diff --git a/14_RADAR_Old_version/Firmware/Microcontroller/no_os_uart.c b/14_RADAR_Old_version/Firmware/Microcontroller/no_os_uart.c new file mode 100644 index 0000000..4053645 --- /dev/null +++ b/14_RADAR_Old_version/Firmware/Microcontroller/no_os_uart.c @@ -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 +#include "no_os_uart.h" +#include +#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. */ +} diff --git a/14_RADAR_Old_version/Firmware/Microcontroller/no_os_uart.h b/14_RADAR_Old_version/Firmware/Microcontroller/no_os_uart.h new file mode 100644 index 0000000..b8605ff --- /dev/null +++ b/14_RADAR_Old_version/Firmware/Microcontroller/no_os_uart.h @@ -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 +#include +#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_ diff --git a/14_RADAR_Old_version/Firmware/Microcontroller/no_os_units.h b/14_RADAR_Old_version/Firmware/Microcontroller/no_os_units.h new file mode 100644 index 0000000..826ed3e --- /dev/null +++ b/14_RADAR_Old_version/Firmware/Microcontroller/no_os_units.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_ diff --git a/14_RADAR_Old_version/Firmware/Microcontroller/no_os_util.c b/14_RADAR_Old_version/Firmware/Microcontroller/no_os_util.c new file mode 100644 index 0000000..0b3239b --- /dev/null +++ b/14_RADAR_Old_version/Firmware/Microcontroller/no_os_util.c @@ -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 +#include +#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(÷nd, 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]; + } + } +} diff --git a/14_RADAR_Old_version/Firmware/Microcontroller/no_os_util.h b/14_RADAR_Old_version/Firmware/Microcontroller/no_os_util.h new file mode 100644 index 0000000..9bf54f3 --- /dev/null +++ b/14_RADAR_Old_version/Firmware/Microcontroller/no_os_util.h @@ -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 +#include +#include +#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_ diff --git a/14_RADAR_Old_version/Firmware/Microcontroller/parameters.c b/14_RADAR_Old_version/Firmware/Microcontroller/parameters.c new file mode 100644 index 0000000..dde0a55 --- /dev/null +++ b/14_RADAR_Old_version/Firmware/Microcontroller/parameters.c @@ -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, +}; diff --git a/14_RADAR_Old_version/Firmware/Microcontroller/parameters.h b/14_RADAR_Old_version/Firmware/Microcontroller/parameters.h new file mode 100644 index 0000000..328ce89 --- /dev/null +++ b/14_RADAR_Old_version/Firmware/Microcontroller/parameters.h @@ -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__ */ diff --git a/14_RADAR_Old_version/Firmware/Microcontroller/si5351.cpp b/14_RADAR_Old_version/Firmware/Microcontroller/si5351.cpp new file mode 100644 index 0000000..6253fe7 --- /dev/null +++ b/14_RADAR_Old_version/Firmware/Microcontroller/si5351.cpp @@ -0,0 +1,1808 @@ +/* + * si5351.cpp - Si5351 library for Arduino + * + * Copyright (C) 2015 - 2019 Jason Milldrum + * Dana H. Myers + * + * Some tuning algorithms derived from clk-si5351.c in the Linux kernel. + * Sebastian Hesselbarth + * Rabeeh Khoury + * + * 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 . + */ + +#include + +#include "main.h" +#include "stm32f7xx_hal.h" +#include "stm32f7xx_hal_i2c.h" +#include "si5351.h" + +extern I2C_HandleTypeDef hi2c1; + + +/********************/ +/* Public functions */ +/********************/ + +Si5351::Si5351(uint8_t i2c_addr): + i2c_bus_addr(i2c_addr) +{ + xtal_freq[0] = SI5351_XTAL_FREQ; + + // Start by using XO ref osc as default for each PLL + plla_ref_osc = SI5351_PLL_INPUT_XO; + pllb_ref_osc = SI5351_PLL_INPUT_XO; + clkin_div = SI5351_CLKIN_DIV_1; +} + +/* + * init(uint8_t xtal_load_c, uint32_t ref_osc_freq, int32_t corr) + * + * Setup communications to the Si5351 and set the crystal + * load capacitance. + * + * xtal_load_c - Crystal load capacitance. Use the SI5351_CRYSTAL_LOAD_*PF + * defines in the header file + * xo_freq - Crystal/reference oscillator frequency in 1 Hz increments. + * Defaults to 25000000 if a 0 is used here. + * corr - Frequency correction constant in parts-per-billion + * + * Returns a boolean that indicates whether a device was found on the desired + * I2C address. + * + */ +bool Si5351::init(uint8_t xtal_load_c, uint32_t xo_freq, int32_t corr) +{ + // Start I2C comms + + //MX_I2C1_Init(); + + // Check for a device on the bus, bail out if it is not there + uint8_t res = HAL_I2C_IsDeviceReady(&hi2c1, i2c_bus_addr << 1, 1, 10); + if(res == HAL_OK) + { + // Wait for SYS_INIT flag to be clear, indicating that device is ready + uint8_t status_reg = 0; + do + { + status_reg = si5351_read(SI5351_DEVICE_STATUS); + } while (status_reg >> 7 == 1); + + // Set crystal load capacitance + si5351_write(SI5351_CRYSTAL_LOAD, (xtal_load_c & SI5351_CRYSTAL_LOAD_MASK) | 0b00010010); + + // Set up the XO and CLKIN reference frequencies + if (xo_freq != 0) + { + set_ref_freq(xo_freq, SI5351_PLL_INPUT_XO); + set_ref_freq(xo_freq, SI5351_PLL_INPUT_CLKIN); //Also CLKIN + } + else + { + set_ref_freq(SI5351_XTAL_FREQ, SI5351_PLL_INPUT_XO); + set_ref_freq(SI5351_XTAL_FREQ, SI5351_PLL_INPUT_CLKIN); //Also CLKIN + } + + // Set the frequency calibrations for the XO and CLKIN + set_correction(corr, SI5351_PLL_INPUT_XO); + set_correction(corr, SI5351_PLL_INPUT_CLKIN); + + reset(); + + return true; + } + else + { + return false; + } +} + +/* + * reset(void) + * + * Call to reset the Si5351 to the state initialized by the library. + * + */ +void Si5351::reset(void) +{ + // Initialize the CLK outputs according to flowchart in datasheet + // First, turn them off + si5351_write(16, 0x80); + si5351_write(17, 0x80); + si5351_write(18, 0x80); + si5351_write(19, 0x80); + si5351_write(20, 0x80); + si5351_write(21, 0x80); + si5351_write(22, 0x80); + si5351_write(23, 0x80); + + // Turn the clocks back on... + si5351_write(16, 0x0c); + si5351_write(17, 0x0c); + si5351_write(18, 0x0c); + si5351_write(19, 0x0c); + si5351_write(20, 0x0c); + si5351_write(21, 0x0c); + si5351_write(22, 0x0c); + si5351_write(23, 0x0c); + + // Set PLLA and PLLB to 800 MHz for automatic tuning + set_pll(SI5351_PLL_FIXED, SI5351_PLLA); + set_pll(SI5351_PLL_FIXED, SI5351_PLLB); + + // Make PLL to CLK assignments for automatic tuning + pll_assignment[0] = SI5351_PLLA; + pll_assignment[1] = SI5351_PLLA; + pll_assignment[2] = SI5351_PLLA; + pll_assignment[3] = SI5351_PLLA; + pll_assignment[4] = SI5351_PLLA; + pll_assignment[5] = SI5351_PLLA; + pll_assignment[6] = SI5351_PLLB; + pll_assignment[7] = SI5351_PLLB; + + set_ms_source(SI5351_CLK0, SI5351_PLLA); + set_ms_source(SI5351_CLK1, SI5351_PLLA); + set_ms_source(SI5351_CLK2, SI5351_PLLA); + set_ms_source(SI5351_CLK3, SI5351_PLLA); + set_ms_source(SI5351_CLK4, SI5351_PLLA); + set_ms_source(SI5351_CLK5, SI5351_PLLA); + set_ms_source(SI5351_CLK6, SI5351_PLLB); + set_ms_source(SI5351_CLK7, SI5351_PLLB); + + // Reset the VCXO param + si5351_write(SI5351_VXCO_PARAMETERS_LOW, 0); + si5351_write(SI5351_VXCO_PARAMETERS_MID, 0); + si5351_write(SI5351_VXCO_PARAMETERS_HIGH, 0); + + // Then reset the PLLs + pll_reset(SI5351_PLLA); + pll_reset(SI5351_PLLB); + + // Set initial frequencies + uint8_t i; + for(i = 0; i < 8; i++) + { + clk_freq[i] = 0; + output_enable((enum si5351_clock)i, 0); + clk_first_set[i] = false; + } +} + +/* + * set_freq(uint64_t freq, enum si5351_clock clk) + * + * Sets the clock frequency of the specified CLK output. + * Frequency range of 8 kHz to 150 MHz + * + * freq - Output frequency in Hz + * clk - Clock output + * (use the si5351_clock enum) + */ +uint8_t Si5351::set_freq(uint64_t freq, enum si5351_clock clk) +{ + struct Si5351RegSet ms_reg; + uint64_t pll_freq; + uint8_t int_mode = 0; + uint8_t div_by_4 = 0; + uint8_t r_div = 0; + + // Check which Multisynth is being set + if((uint8_t)clk <= (uint8_t)SI5351_CLK5) + { + // MS0 through MS5 logic + // --------------------- + + // Lower bounds check + if(freq > 0 && freq < SI5351_CLKOUT_MIN_FREQ * SI5351_FREQ_MULT) + { + freq = SI5351_CLKOUT_MIN_FREQ * SI5351_FREQ_MULT; + } + + // Upper bounds check + if(freq > SI5351_MULTISYNTH_MAX_FREQ * SI5351_FREQ_MULT) + { + freq = SI5351_MULTISYNTH_MAX_FREQ * SI5351_FREQ_MULT; + } + + // If requested freq >100 MHz and no other outputs are already >100 MHz, + // we need to recalculate PLLA and then recalculate all other CLK outputs + // on same PLL + if(freq > (SI5351_MULTISYNTH_SHARE_MAX * SI5351_FREQ_MULT)) + { + // Check other clocks on same PLL + uint8_t i; + for(i = 0; i < 6; i++) + { + if(clk_freq[i] > (SI5351_MULTISYNTH_SHARE_MAX * SI5351_FREQ_MULT)) + { + if(i != (uint8_t)clk && pll_assignment[i] == pll_assignment[clk]) + { + return 1; // won't set if any other clks already >100 MHz + } + } + } + + // Enable the output on first set_freq only + if(clk_first_set[(uint8_t)clk] == false) + { + output_enable(clk, 1); + clk_first_set[(uint8_t)clk] = true; + } + + // Set the freq in memory + clk_freq[(uint8_t)clk] = freq; + + // Calculate the proper PLL frequency + pll_freq = multisynth_calc(freq, 0, &ms_reg); + + // Set PLL + set_pll(pll_freq, pll_assignment[clk]); + + // Recalculate params for other synths on same PLL + for(i = 0; i < 6; i++) + { + if(clk_freq[i] != 0) + { + if(pll_assignment[i] == pll_assignment[clk]) + { + struct Si5351RegSet temp_reg; + uint64_t temp_freq; + + // Select the proper R div value + temp_freq = clk_freq[i]; + r_div = select_r_div(&temp_freq); + + multisynth_calc(temp_freq, pll_freq, &temp_reg); + + // If freq > 150 MHz, we need to use DIVBY4 and integer mode + if(temp_freq >= SI5351_MULTISYNTH_DIVBY4_FREQ * SI5351_FREQ_MULT) + { + div_by_4 = 1; + int_mode = 1; + } + else + { + div_by_4 = 0; + int_mode = 0; + } + + // Set multisynth registers + set_ms((enum si5351_clock)i, temp_reg, int_mode, r_div, div_by_4); + } + } + } + + // Reset the PLL + pll_reset(pll_assignment[clk]); + } + else + { + clk_freq[(uint8_t)clk] = freq; + + // Enable the output on first set_freq only + if(clk_first_set[(uint8_t)clk] == false) + { + output_enable(clk, 1); + clk_first_set[(uint8_t)clk] = true; + } + + // Select the proper R div value + r_div = select_r_div(&freq); + + // Calculate the synth parameters + if(pll_assignment[clk] == SI5351_PLLA) + { + multisynth_calc(freq, plla_freq, &ms_reg); + } + else + { + multisynth_calc(freq, pllb_freq, &ms_reg); + } + + // Set multisynth registers + set_ms(clk, ms_reg, int_mode, r_div, div_by_4); + + // Reset the PLL + //pll_reset(pll_assignment[clk]); + } + + return 0; + } + else + { + // MS6 and MS7 logic + // ----------------- + + // Lower bounds check + if(freq > 0 && freq < SI5351_CLKOUT67_MIN_FREQ * SI5351_FREQ_MULT) + { + freq = SI5351_CLKOUT_MIN_FREQ * SI5351_FREQ_MULT; + } + + // Upper bounds check + if(freq >= SI5351_MULTISYNTH_DIVBY4_FREQ * SI5351_FREQ_MULT) + { + freq = SI5351_MULTISYNTH_DIVBY4_FREQ * SI5351_FREQ_MULT - 1; + } + + // If one of CLK6 or CLK7 is already set when trying to set the other, + // we have to ensure that it will also have an integer division ratio + // with the same PLL, otherwise do not set it. + if(clk == SI5351_CLK6) + { + if(clk_freq[7] != 0) + { + if(pllb_freq % freq == 0) + { + if((pllb_freq / freq) % 2 != 0) + { + // Not an even divide ratio, no bueno + return 1; + } + else + { + // Set the freq in memory + clk_freq[(uint8_t)clk] = freq; + + // Select the proper R div value + r_div = select_r_div_ms67(&freq); + + multisynth67_calc(freq, pllb_freq, &ms_reg); + } + } + else + { + // Not an integer divide ratio, no good + return 1; + } + } + else + { + // No previous assignment, so set PLLB based on CLK6 + + // Set the freq in memory + clk_freq[(uint8_t)clk] = freq; + + // Select the proper R div value + r_div = select_r_div_ms67(&freq); + + pll_freq = multisynth67_calc(freq, 0, &ms_reg); + //pllb_freq = pll_freq; + set_pll(pll_freq, SI5351_PLLB); + } + } + else + { + if(clk_freq[6] != 0) + { + if(pllb_freq % freq == 0) + { + if((pllb_freq / freq) % 2 != 0) + { + // Not an even divide ratio, no bueno + return 1; + } + else + { + // Set the freq in memory + clk_freq[(uint8_t)clk] = freq; + + // Select the proper R div value + r_div = select_r_div_ms67(&freq); + + multisynth67_calc(freq, pllb_freq, &ms_reg); + } + } + else + { + // Not an integer divide ratio, no good + return 1; + } + } + else + { + // No previous assignment, so set PLLB based on CLK7 + + // Set the freq in memory + clk_freq[(uint8_t)clk] = freq; + + // Select the proper R div value + r_div = select_r_div_ms67(&freq); + + pll_freq = multisynth67_calc(freq, 0, &ms_reg); + //pllb_freq = pll_freq; + set_pll(pll_freq, pll_assignment[clk]); + } + } + + div_by_4 = 0; + int_mode = 0; + + // Set multisynth registers (MS must be set before PLL) + set_ms(clk, ms_reg, int_mode, r_div, div_by_4); + + return 0; + } +} + +/* + * set_freq_manual(uint64_t freq, uint64_t pll_freq, enum si5351_clock clk) + * + * Sets the clock frequency of the specified CLK output using the given PLL + * frequency. You must ensure that the MS is assigned to the correct PLL and + * that the PLL is set to the correct frequency before using this method. + * + * It is important to note that if you use this method, you will have to + * track that all settings are sane yourself. + * + * freq - Output frequency in Hz + * pll_freq - Frequency of the PLL driving the Multisynth in Hz * 100 + * clk - Clock output + * (use the si5351_clock enum) + */ +uint8_t Si5351::set_freq_manual(uint64_t freq, uint64_t pll_freq, enum si5351_clock clk) +{ + struct Si5351RegSet ms_reg; + uint8_t int_mode = 0; + uint8_t div_by_4 = 0; + + // Lower bounds check + if(freq > 0 && freq < SI5351_CLKOUT_MIN_FREQ * SI5351_FREQ_MULT) + { + freq = SI5351_CLKOUT_MIN_FREQ * SI5351_FREQ_MULT; + } + + // Upper bounds check + if(freq > SI5351_CLKOUT_MAX_FREQ * SI5351_FREQ_MULT) + { + freq = SI5351_CLKOUT_MAX_FREQ * SI5351_FREQ_MULT; + } + + uint8_t r_div; + + clk_freq[(uint8_t)clk] = freq; + + set_pll(pll_freq, pll_assignment[clk]); + + // Enable the output + output_enable(clk, 1); + + // Select the proper R div value + r_div = select_r_div(&freq); + + // Calculate the synth parameters + multisynth_calc(freq, pll_freq, &ms_reg); + + // If freq > 150 MHz, we need to use DIVBY4 and integer mode + if(freq >= SI5351_MULTISYNTH_DIVBY4_FREQ * SI5351_FREQ_MULT) + { + div_by_4 = 1; + int_mode = 1; + } + + // Set multisynth registers (MS must be set before PLL) + set_ms(clk, ms_reg, int_mode, r_div, div_by_4); + + return 0; +} + +/* + * set_pll(uint64_t pll_freq, enum si5351_pll target_pll) + * + * Set the specified PLL to a specific oscillation frequency + * + * pll_freq - Desired PLL frequency in Hz * 100 + * target_pll - Which PLL to set + * (use the si5351_pll enum) + */ +void Si5351::set_pll(uint64_t pll_freq, enum si5351_pll target_pll) +{ + struct Si5351RegSet pll_reg; + + if(target_pll == SI5351_PLLA) + { + pll_calc(SI5351_PLLA, pll_freq, &pll_reg, ref_correction[plla_ref_osc], 0); + } + else + { + pll_calc(SI5351_PLLB, pll_freq, &pll_reg, ref_correction[pllb_ref_osc], 0); + } + + // Derive the register values to write + + // Prepare an array for parameters to be written to + uint8_t *params = new uint8_t[20]; + uint8_t i = 0; + uint8_t temp; + + // Registers 26-27 + temp = ((pll_reg.p3 >> 8) & 0xFF); + params[i++] = temp; + + temp = (uint8_t)(pll_reg.p3 & 0xFF); + params[i++] = temp; + + // Register 28 + temp = (uint8_t)((pll_reg.p1 >> 16) & 0x03); + params[i++] = temp; + + // Registers 29-30 + temp = (uint8_t)((pll_reg.p1 >> 8) & 0xFF); + params[i++] = temp; + + temp = (uint8_t)(pll_reg.p1 & 0xFF); + params[i++] = temp; + + // Register 31 + temp = (uint8_t)((pll_reg.p3 >> 12) & 0xF0); + temp += (uint8_t)((pll_reg.p2 >> 16) & 0x0F); + params[i++] = temp; + + // Registers 32-33 + temp = (uint8_t)((pll_reg.p2 >> 8) & 0xFF); + params[i++] = temp; + + temp = (uint8_t)(pll_reg.p2 & 0xFF); + params[i++] = temp; + + // Write the parameters + if(target_pll == SI5351_PLLA) + { + si5351_write_bulk(SI5351_PLLA_PARAMETERS, i, params); + plla_freq = pll_freq; + } + else if(target_pll == SI5351_PLLB) + { + si5351_write_bulk(SI5351_PLLB_PARAMETERS, i, params); + pllb_freq = pll_freq; + } + + delete params; +} + +/* + * set_ms(enum si5351_clock clk, struct Si5351RegSet ms_reg, uint8_t int_mode, uint8_t r_div, uint8_t div_by_4) + * + * Set the specified multisynth parameters. Not normally needed, but public for advanced users. + * + * clk - Clock output + * (use the si5351_clock enum) + * int_mode - Set integer mode + * Set to 1 to enable, 0 to disable + * r_div - Desired r_div ratio + * div_by_4 - Set Divide By 4 mode + * Set to 1 to enable, 0 to disable + */ +void Si5351::set_ms(enum si5351_clock clk, struct Si5351RegSet ms_reg, uint8_t int_mode, uint8_t r_div, uint8_t div_by_4) +{ + uint8_t *params = new uint8_t[20]; + uint8_t i = 0; + uint8_t temp; + uint8_t reg_val; + + + if((uint8_t)clk <= (uint8_t)SI5351_CLK5) + { + // Registers 42-43 for CLK0 + temp = (uint8_t)((ms_reg.p3 >> 8) & 0xFF); + params[i++] = temp; + + temp = (uint8_t)(ms_reg.p3 & 0xFF); + params[i++] = temp; + + // Register 44 for CLK0 + reg_val = si5351_read((SI5351_CLK0_PARAMETERS + 2) + (clk * 8)); + reg_val &= ~(0x03); + temp = reg_val | ((uint8_t)((ms_reg.p1 >> 16) & 0x03)); + params[i++] = temp; + + // Registers 45-46 for CLK0 + temp = (uint8_t)((ms_reg.p1 >> 8) & 0xFF); + params[i++] = temp; + + temp = (uint8_t)(ms_reg.p1 & 0xFF); + params[i++] = temp; + + // Register 47 for CLK0 + temp = (uint8_t)((ms_reg.p3 >> 12) & 0xF0); + temp += (uint8_t)((ms_reg.p2 >> 16) & 0x0F); + params[i++] = temp; + + // Registers 48-49 for CLK0 + temp = (uint8_t)((ms_reg.p2 >> 8) & 0xFF); + params[i++] = temp; + + temp = (uint8_t)(ms_reg.p2 & 0xFF); + params[i++] = temp; + } + else + { + // MS6 and MS7 only use one register + temp = ms_reg.p1; + } + + // Write the parameters + switch(clk) + { + case SI5351_CLK0: + si5351_write_bulk(SI5351_CLK0_PARAMETERS, i, params); + set_int(clk, int_mode); + ms_div(clk, r_div, div_by_4); + break; + case SI5351_CLK1: + si5351_write_bulk(SI5351_CLK1_PARAMETERS, i, params); + set_int(clk, int_mode); + ms_div(clk, r_div, div_by_4); + break; + case SI5351_CLK2: + si5351_write_bulk(SI5351_CLK2_PARAMETERS, i, params); + set_int(clk, int_mode); + ms_div(clk, r_div, div_by_4); + break; + case SI5351_CLK3: + si5351_write_bulk(SI5351_CLK3_PARAMETERS, i, params); + set_int(clk, int_mode); + ms_div(clk, r_div, div_by_4); + break; + case SI5351_CLK4: + si5351_write_bulk(SI5351_CLK4_PARAMETERS, i, params); + set_int(clk, int_mode); + ms_div(clk, r_div, div_by_4); + break; + case SI5351_CLK5: + si5351_write_bulk(SI5351_CLK5_PARAMETERS, i, params); + set_int(clk, int_mode); + ms_div(clk, r_div, div_by_4); + break; + case SI5351_CLK6: + si5351_write(SI5351_CLK6_PARAMETERS, temp); + ms_div(clk, r_div, div_by_4); + break; + case SI5351_CLK7: + si5351_write(SI5351_CLK7_PARAMETERS, temp); + ms_div(clk, r_div, div_by_4); + break; + } + + delete params; +} + +/* + * output_enable(enum si5351_clock clk, uint8_t enable) + * + * Enable or disable a chosen output + * clk - Clock output + * (use the si5351_clock enum) + * enable - Set to 1 to enable, 0 to disable + */ +void Si5351::output_enable(enum si5351_clock clk, uint8_t enable) +{ + uint8_t reg_val; + + reg_val = si5351_read(SI5351_OUTPUT_ENABLE_CTRL); + + if(enable == 1) + { + reg_val &= ~(1<<(uint8_t)clk); + } + else + { + reg_val |= (1<<(uint8_t)clk); + } + + si5351_write(SI5351_OUTPUT_ENABLE_CTRL, reg_val); +} + +/* + * drive_strength(enum si5351_clock clk, enum si5351_drive drive) + * + * Sets the drive strength of the specified clock output + * + * clk - Clock output + * (use the si5351_clock enum) + * drive - Desired drive level + * (use the si5351_drive enum) + */ +void Si5351::drive_strength(enum si5351_clock clk, enum si5351_drive drive) +{ + uint8_t reg_val; + const uint8_t mask = 0x03; + + reg_val = si5351_read(SI5351_CLK0_CTRL + (uint8_t)clk); + reg_val &= ~(mask); + + switch(drive) + { + case SI5351_DRIVE_2MA: + reg_val |= 0x00; + break; + case SI5351_DRIVE_4MA: + reg_val |= 0x01; + break; + case SI5351_DRIVE_6MA: + reg_val |= 0x02; + break; + case SI5351_DRIVE_8MA: + reg_val |= 0x03; + break; + default: + break; + } + + si5351_write(SI5351_CLK0_CTRL + (uint8_t)clk, reg_val); +} + +/* + * update_status(void) + * + * Call this to update the status structs, then access them + * via the dev_status and dev_int_status global members. + * + * See the header file for the struct definitions. These + * correspond to the flag names for registers 0 and 1 in + * the Si5351 datasheet. + */ +void Si5351::update_status(void) +{ + update_sys_status(&dev_status); + update_int_status(&dev_int_status); +} + +/* + * set_correction(int32_t corr, enum si5351_pll_input ref_osc) + * + * corr - Correction factor in ppb + * ref_osc - Desired reference oscillator + * (use the si5351_pll_input enum) + * + * Use this to set the oscillator correction factor. + * This value is a signed 32-bit integer of the + * parts-per-billion value that the actual oscillation + * frequency deviates from the specified frequency. + * + * The frequency calibration is done as a one-time procedure. + * Any desired test frequency within the normal range of the + * Si5351 should be set, then the actual output frequency + * should be measured as accurately as possible. The + * difference between the measured and specified frequencies + * should be calculated in Hertz, then multiplied by 10 in + * order to get the parts-per-billion value. + * + * Since the Si5351 itself has an intrinsic 0 PPM error, this + * correction factor is good across the entire tuning range of + * the Si5351. Once this calibration is done accurately, it + * should not have to be done again for the same Si5351 and + * crystal. + */ +void Si5351::set_correction(int32_t corr, enum si5351_pll_input ref_osc) +{ + ref_correction[(uint8_t)ref_osc] = corr; + + // Recalculate and set PLL freqs based on correction value + set_pll(plla_freq, SI5351_PLLA); + set_pll(pllb_freq, SI5351_PLLB); +} + +/* + * set_phase(enum si5351_clock clk, uint8_t phase) + * + * clk - Clock output + * (use the si5351_clock enum) + * phase - 7-bit phase word + * (in units of VCO/4 period) + * + * Write the 7-bit phase register. This must be used + * with a user-set PLL frequency so that the user can + * calculate the proper tuning word based on the PLL period. + */ +void Si5351::set_phase(enum si5351_clock clk, uint8_t phase) +{ + // Mask off the upper bit since it is reserved + phase = phase & 0b01111111; + + si5351_write(SI5351_CLK0_PHASE_OFFSET + (uint8_t)clk, phase); +} + +/* + * get_correction(enum si5351_pll_input ref_osc) + * + * ref_osc - Desired reference oscillator + * 0: crystal oscillator (XO) + * 1: external clock input (CLKIN) + * + * Returns the oscillator correction factor stored + * in RAM. + */ +int32_t Si5351::get_correction(enum si5351_pll_input ref_osc) +{ + return ref_correction[(uint8_t)ref_osc]; +} + +/* + * pll_reset(enum si5351_pll target_pll) + * + * target_pll - Which PLL to reset + * (use the si5351_pll enum) + * + * Apply a reset to the indicated PLL. + */ +void Si5351::pll_reset(enum si5351_pll target_pll) +{ + if(target_pll == SI5351_PLLA) + { + si5351_write(SI5351_PLL_RESET, SI5351_PLL_RESET_A); + } + else if(target_pll == SI5351_PLLB) + { + si5351_write(SI5351_PLL_RESET, SI5351_PLL_RESET_B); + } +} + +/* + * set_ms_source(enum si5351_clock clk, enum si5351_pll pll) + * + * clk - Clock output + * (use the si5351_clock enum) + * pll - Which PLL to use as the source + * (use the si5351_pll enum) + * + * Set the desired PLL source for a multisynth. + */ +void Si5351::set_ms_source(enum si5351_clock clk, enum si5351_pll pll) +{ + uint8_t reg_val; + + reg_val = si5351_read(SI5351_CLK0_CTRL + (uint8_t)clk); + + if(pll == SI5351_PLLA) + { + reg_val &= ~(SI5351_CLK_PLL_SELECT); + } + else if(pll == SI5351_PLLB) + { + reg_val |= SI5351_CLK_PLL_SELECT; + } + + si5351_write(SI5351_CLK0_CTRL + (uint8_t)clk, reg_val); + + pll_assignment[(uint8_t)clk] = pll; +} + +/* + * set_int(enum si5351_clock clk, uint8_t int_mode) + * + * clk - Clock output + * (use the si5351_clock enum) + * enable - Set to 1 to enable, 0 to disable + * + * Set the indicated multisynth into integer mode. + */ +void Si5351::set_int(enum si5351_clock clk, uint8_t enable) +{ + uint8_t reg_val; + reg_val = si5351_read(SI5351_CLK0_CTRL + (uint8_t)clk); + + if(enable == 1) + { + reg_val |= (SI5351_CLK_INTEGER_MODE); + } + else + { + reg_val &= ~(SI5351_CLK_INTEGER_MODE); + } + + si5351_write(SI5351_CLK0_CTRL + (uint8_t)clk, reg_val); + + // Integer mode indication + /* + switch(clk) + { + case SI5351_CLK0: + clk0_int_mode = enable; + break; + case SI5351_CLK1: + clk1_int_mode = enable; + break; + case SI5351_CLK2: + clk2_int_mode = enable; + break; + default: + break; + } + */ +} + +/* + * set_clock_pwr(enum si5351_clock clk, uint8_t pwr) + * + * clk - Clock output + * (use the si5351_clock enum) + * pwr - Set to 1 to enable, 0 to disable + * + * Enable or disable power to a clock output (a power + * saving feature). + */ +void Si5351::set_clock_pwr(enum si5351_clock clk, uint8_t pwr) +{ + uint8_t reg_val; //, reg; + reg_val = si5351_read(SI5351_CLK0_CTRL + (uint8_t)clk); + + if(pwr == 1) + { + reg_val &= 0b01111111; + } + else + { + reg_val |= 0b10000000; + } + + si5351_write(SI5351_CLK0_CTRL + (uint8_t)clk, reg_val); +} + +/* + * set_clock_invert(enum si5351_clock clk, uint8_t inv) + * + * clk - Clock output + * (use the si5351_clock enum) + * inv - Set to 1 to enable, 0 to disable + * + * Enable to invert the clock output waveform. + */ +void Si5351::set_clock_invert(enum si5351_clock clk, uint8_t inv) +{ + uint8_t reg_val; + reg_val = si5351_read(SI5351_CLK0_CTRL + (uint8_t)clk); + + if(inv == 1) + { + reg_val |= (SI5351_CLK_INVERT); + } + else + { + reg_val &= ~(SI5351_CLK_INVERT); + } + + si5351_write(SI5351_CLK0_CTRL + (uint8_t)clk, reg_val); +} + +/* + * set_clock_source(enum si5351_clock clk, enum si5351_clock_source src) + * + * clk - Clock output + * (use the si5351_clock enum) + * src - Which clock source to use for the multisynth + * (use the si5351_clock_source enum) + * + * Set the clock source for a multisynth (based on the options + * presented for Registers 16-23 in the Silicon Labs AN619 document). + * Choices are XTAL, CLKIN, MS0, or the multisynth associated with + * the clock output. + */ +void Si5351::set_clock_source(enum si5351_clock clk, enum si5351_clock_source src) +{ + uint8_t reg_val; + reg_val = si5351_read(SI5351_CLK0_CTRL + (uint8_t)clk); + + // Clear the bits first + reg_val &= ~(SI5351_CLK_INPUT_MASK); + + switch(src) + { + case SI5351_CLK_SRC_XTAL: + reg_val |= (SI5351_CLK_INPUT_XTAL); + break; + case SI5351_CLK_SRC_CLKIN: + reg_val |= (SI5351_CLK_INPUT_CLKIN); + break; + case SI5351_CLK_SRC_MS0: + if(clk == SI5351_CLK0) + { + return; + } + + reg_val |= (SI5351_CLK_INPUT_MULTISYNTH_0_4); + break; + case SI5351_CLK_SRC_MS: + reg_val |= (SI5351_CLK_INPUT_MULTISYNTH_N); + break; + default: + return; + } + + si5351_write(SI5351_CLK0_CTRL + (uint8_t)clk, reg_val); +} + +/* + * set_clock_disable(enum si5351_clock clk, enum si5351_clock_disable dis_state) + * + * clk - Clock output + * (use the si5351_clock enum) + * dis_state - Desired state of the output upon disable + * (use the si5351_clock_disable enum) + * + * Set the state of the clock output when it is disabled. Per page 27 + * of AN619 (Registers 24 and 25), there are four possible values: low, + * high, high impedance, and never disabled. + */ +void Si5351::set_clock_disable(enum si5351_clock clk, enum si5351_clock_disable dis_state) +{ + uint8_t reg_val, reg; + + if (clk >= SI5351_CLK0 && clk <= SI5351_CLK3) + { + reg = SI5351_CLK3_0_DISABLE_STATE; + } + else if(clk >= SI5351_CLK4 && clk <= SI5351_CLK7) + { + reg = SI5351_CLK7_4_DISABLE_STATE; + } + else return; + + reg_val = si5351_read(reg); + + if (clk >= SI5351_CLK0 && clk <= SI5351_CLK3) + { + reg_val &= ~(0b11 << (clk * 2)); + reg_val |= dis_state << (clk * 2); + } + else if(clk >= SI5351_CLK4 && clk <= SI5351_CLK7) + { + reg_val &= ~(0b11 << ((clk - 4) * 2)); + reg_val |= dis_state << ((clk - 4) * 2); + } + + si5351_write(reg, reg_val); +} + +/* + * set_clock_fanout(enum si5351_clock_fanout fanout, uint8_t enable) + * + * fanout - Desired clock fanout + * (use the si5351_clock_fanout enum) + * enable - Set to 1 to enable, 0 to disable + * + * Use this function to enable or disable the clock fanout options + * for individual clock outputs. If you intend to output the XO or + * CLKIN on the clock outputs, enable this first. + * + * By default, only the Multisynth fanout is enabled at startup. + */ +void Si5351::set_clock_fanout(enum si5351_clock_fanout fanout, uint8_t enable) +{ + uint8_t reg_val; + reg_val = si5351_read(SI5351_FANOUT_ENABLE); + + switch(fanout) + { + case SI5351_FANOUT_CLKIN: + if(enable) + { + reg_val |= SI5351_CLKIN_ENABLE; + } + else + { + reg_val &= ~(SI5351_CLKIN_ENABLE); + } + break; + case SI5351_FANOUT_XO: + if(enable) + { + reg_val |= SI5351_XTAL_ENABLE; + } + else + { + reg_val &= ~(SI5351_XTAL_ENABLE); + } + break; + case SI5351_FANOUT_MS: + if(enable) + { + reg_val |= SI5351_MULTISYNTH_ENABLE; + } + else + { + reg_val &= ~(SI5351_MULTISYNTH_ENABLE); + } + break; + } + + si5351_write(SI5351_FANOUT_ENABLE, reg_val); +} + +/* + * set_pll_input(enum si5351_pll pll, enum si5351_pll_input input) + * + * pll - Which PLL to use as the source + * (use the si5351_pll enum) + * input - Which reference oscillator to use as PLL input + * (use the si5351_pll_input enum) + * + * Set the desired reference oscillator source for the given PLL. + */ +void Si5351::set_pll_input(enum si5351_pll pll, enum si5351_pll_input input) +{ + uint8_t reg_val; + reg_val = si5351_read(SI5351_PLL_INPUT_SOURCE); + + // Clear the bits first + //reg_val &= ~(SI5351_CLKIN_DIV_MASK); + + switch(pll) + { + case SI5351_PLLA: + if(input == SI5351_PLL_INPUT_CLKIN) + { + reg_val |= SI5351_PLLA_SOURCE; + reg_val |= clkin_div; + plla_ref_osc = SI5351_PLL_INPUT_CLKIN; + } + else + { + reg_val &= ~(SI5351_PLLA_SOURCE); + plla_ref_osc = SI5351_PLL_INPUT_XO; + } + break; + case SI5351_PLLB: + if(input == SI5351_PLL_INPUT_CLKIN) + { + reg_val |= SI5351_PLLB_SOURCE; + reg_val |= clkin_div; + pllb_ref_osc = SI5351_PLL_INPUT_CLKIN; + } + else + { + reg_val &= ~(SI5351_PLLB_SOURCE); + pllb_ref_osc = SI5351_PLL_INPUT_XO; + } + break; + default: + return; + } + + si5351_write(SI5351_PLL_INPUT_SOURCE, reg_val); + + set_pll(plla_freq, SI5351_PLLA); + set_pll(pllb_freq, SI5351_PLLB); +} + +/* + * set_vcxo(uint64_t pll_freq, uint8_t ppm) + * + * pll_freq - Desired PLL base frequency in Hz * 100 + * ppm - VCXO pull limit in ppm + * + * Set the parameters for the VCXO on the Si5351B. + */ +void Si5351::set_vcxo(uint64_t pll_freq, uint8_t ppm) +{ + struct Si5351RegSet pll_reg; + uint64_t vcxo_param; + + // Bounds check + if(ppm < SI5351_VCXO_PULL_MIN) + { + ppm = SI5351_VCXO_PULL_MIN; + } + + if(ppm > SI5351_VCXO_PULL_MAX) + { + ppm = SI5351_VCXO_PULL_MAX; + } + + // Set PLLB params + vcxo_param = pll_calc(SI5351_PLLB, pll_freq, &pll_reg, ref_correction[pllb_ref_osc], 1); + + // Derive the register values to write + + // Prepare an array for parameters to be written to + uint8_t *params = new uint8_t[20]; + uint8_t i = 0; + uint8_t temp; + + // Registers 26-27 + temp = ((pll_reg.p3 >> 8) & 0xFF); + params[i++] = temp; + + temp = (uint8_t)(pll_reg.p3 & 0xFF); + params[i++] = temp; + + // Register 28 + temp = (uint8_t)((pll_reg.p1 >> 16) & 0x03); + params[i++] = temp; + + // Registers 29-30 + temp = (uint8_t)((pll_reg.p1 >> 8) & 0xFF); + params[i++] = temp; + + temp = (uint8_t)(pll_reg.p1 & 0xFF); + params[i++] = temp; + + // Register 31 + temp = (uint8_t)((pll_reg.p3 >> 12) & 0xF0); + temp += (uint8_t)((pll_reg.p2 >> 16) & 0x0F); + params[i++] = temp; + + // Registers 32-33 + temp = (uint8_t)((pll_reg.p2 >> 8) & 0xFF); + params[i++] = temp; + + temp = (uint8_t)(pll_reg.p2 & 0xFF); + params[i++] = temp; + + // Write the parameters + si5351_write_bulk(SI5351_PLLB_PARAMETERS, i, params); + + delete params; + + // Write the VCXO parameters + vcxo_param = ((vcxo_param * ppm * SI5351_VCXO_MARGIN) / 100ULL) / 1000000ULL; + + temp = (uint8_t)(vcxo_param & 0xFF); + si5351_write(SI5351_VXCO_PARAMETERS_LOW, temp); + + temp = (uint8_t)((vcxo_param >> 8) & 0xFF); + si5351_write(SI5351_VXCO_PARAMETERS_MID, temp); + + temp = (uint8_t)((vcxo_param >> 16) & 0x3F); + si5351_write(SI5351_VXCO_PARAMETERS_HIGH, temp); +} + +/* + * set_ref_freq(uint32_t ref_freq, enum si5351_pll_input ref_osc) + * + * ref_freq - Reference oscillator frequency in Hz + * ref_osc - Which reference oscillator frequency to set + * (use the si5351_pll_input enum) + * + * Set the reference frequency value for the desired reference oscillator + */ +void Si5351::set_ref_freq(uint32_t ref_freq, enum si5351_pll_input ref_osc) +{ + // uint8_t reg_val; + //reg_val = si5351_read(SI5351_PLL_INPUT_SOURCE); + + // Clear the bits first + //reg_val &= ~(SI5351_CLKIN_DIV_MASK); + + if(ref_freq <= 30000000UL) + { + xtal_freq[(uint8_t)ref_osc] = ref_freq; + //reg_val |= SI5351_CLKIN_DIV_1; + if(ref_osc == SI5351_PLL_INPUT_CLKIN) + { + clkin_div = SI5351_CLKIN_DIV_1; + } + } + else if(ref_freq > 30000000UL && ref_freq <= 60000000UL) + { + xtal_freq[(uint8_t)ref_osc] = ref_freq / 2; + //reg_val |= SI5351_CLKIN_DIV_2; + if(ref_osc == SI5351_PLL_INPUT_CLKIN) + { + clkin_div = SI5351_CLKIN_DIV_2; + } + } + else if(ref_freq > 60000000UL && ref_freq <= 100000000UL) + { + xtal_freq[(uint8_t)ref_osc] = ref_freq / 4; + //reg_val |= SI5351_CLKIN_DIV_4; + if(ref_osc == SI5351_PLL_INPUT_CLKIN) + { + clkin_div = SI5351_CLKIN_DIV_4; + } + } + else + { + //reg_val |= SI5351_CLKIN_DIV_1; + } + + //si5351_write(SI5351_PLL_INPUT_SOURCE, reg_val); +} + +uint8_t Si5351::si5351_write_bulk(uint8_t addr, uint8_t bytes, uint8_t *data) +{ + + uint8_t ret = HAL_I2C_Mem_Write(&hi2c1,(i2c_bus_addr<<1),addr, 1, (uint8_t*)data,bytes,50); + + if (ret != HAL_OK) + { + return ret; + } + else { + return HAL_OK; + } + +} + +uint8_t Si5351::si5351_write(uint8_t addr, uint8_t data) +{ + uint8_t ret = HAL_I2C_Mem_Write(&hi2c1,(i2c_bus_addr<<1),addr, 1, &data,1,10); + + if (ret != HAL_OK) + { + return ret; + } + else { + return HAL_OK; + } +} + +uint8_t Si5351::si5351_read(uint8_t addr) +{ + uint8_t reg_val = 0; + HAL_I2C_Mem_Read(&hi2c1,((i2c_bus_addr<<1)|0x01),addr, 1, ®_val,1,10); + return reg_val; +} + +/*********************/ +/* Private functions */ +/*********************/ + +uint64_t Si5351::pll_calc(enum si5351_pll pll, uint64_t freq, struct Si5351RegSet *reg, int32_t correction, uint8_t vcxo) +{ + uint64_t ref_freq; + if(pll == SI5351_PLLA) + { + ref_freq = xtal_freq[(uint8_t)plla_ref_osc] * SI5351_FREQ_MULT; + } + else + { + ref_freq = xtal_freq[(uint8_t)pllb_ref_osc] * SI5351_FREQ_MULT; + } + //ref_freq = 15974400ULL * SI5351_FREQ_MULT; + uint32_t a, b, c, p1, p2, p3; + uint64_t lltmp; //, denom; + + // Factor calibration value into nominal crystal frequency + // Measured in parts-per-billion + + ref_freq = ref_freq + (int32_t)((((((int64_t)correction) << 31) / 1000000000LL) * ref_freq) >> 31); + + // PLL bounds checking + if (freq < SI5351_PLL_VCO_MIN * SI5351_FREQ_MULT) + { + freq = SI5351_PLL_VCO_MIN * SI5351_FREQ_MULT; + } + if (freq > SI5351_PLL_VCO_MAX * SI5351_FREQ_MULT) + { + freq = SI5351_PLL_VCO_MAX * SI5351_FREQ_MULT; + } + + // Determine integer part of feedback equation + a = freq / ref_freq; + + if (a < SI5351_PLL_A_MIN) + { + freq = ref_freq * SI5351_PLL_A_MIN; + } + if (a > SI5351_PLL_A_MAX) + { + freq = ref_freq * SI5351_PLL_A_MAX; + } + + // Find best approximation for b/c = fVCO mod fIN + // denom = 1000ULL * 1000ULL; + // lltmp = freq % ref_freq; + // lltmp *= denom; + // do_div(lltmp, ref_freq); + + //b = (((uint64_t)(freq % ref_freq)) * RFRAC_DENOM) / ref_freq; + if(vcxo) + { + b = (((uint64_t)(freq % ref_freq)) * 1000000ULL) / ref_freq; + c = 1000000ULL; + } + else + { + b = (((uint64_t)(freq % ref_freq)) * RFRAC_DENOM) / ref_freq; + c = b ? RFRAC_DENOM : 1; + } + + // Calculate parameters + p1 = 128 * a + ((128 * b) / c) - 512; + p2 = 128 * b - c * ((128 * b) / c); + p3 = c; + + // Recalculate frequency as fIN * (a + b/c) + lltmp = ref_freq; + lltmp *= b; + do_div(lltmp, c); + freq = lltmp; + freq += ref_freq * a; + + reg->p1 = p1; + reg->p2 = p2; + reg->p3 = p3; + + if(vcxo) + { + return (uint64_t)(128 * a * 1000000ULL + b); + } + else + { + return freq; + } +} + +uint64_t Si5351::multisynth_calc(uint64_t freq, uint64_t pll_freq, struct Si5351RegSet *reg) +{ + uint64_t lltmp; + uint32_t a, b, c, p1, p2, p3; + uint8_t divby4 = 0; + uint8_t ret_val = 0; + + // Multisynth bounds checking + if (freq > SI5351_MULTISYNTH_MAX_FREQ * SI5351_FREQ_MULT) + { + freq = SI5351_MULTISYNTH_MAX_FREQ * SI5351_FREQ_MULT; + } + if (freq < SI5351_MULTISYNTH_MIN_FREQ * SI5351_FREQ_MULT) + { + freq = SI5351_MULTISYNTH_MIN_FREQ * SI5351_FREQ_MULT; + } + + if (freq >= SI5351_MULTISYNTH_DIVBY4_FREQ * SI5351_FREQ_MULT) + { + divby4 = 1; + } + + if(pll_freq == 0) + { + // Find largest integer divider for max + // VCO frequency and given target frequency + if(divby4 == 0) + { + lltmp = SI5351_PLL_VCO_MAX * SI5351_FREQ_MULT; // margin needed? + do_div(lltmp, freq); + if(lltmp == 5) + { + lltmp = 4; + } + else if(lltmp == 7) + { + lltmp = 6; + } + a = (uint32_t)lltmp; + } + else + { + a = 4; + } + + b = 0; + c = 1; + pll_freq = a * freq; + } + else + { + // Preset PLL, so return the actual freq for these params instead of PLL freq + ret_val = 1; + + // Determine integer part of feedback equation + a = pll_freq / freq; + + if (a < SI5351_MULTISYNTH_A_MIN) + { + freq = pll_freq / SI5351_MULTISYNTH_A_MIN; + } + if (a > SI5351_MULTISYNTH_A_MAX) + { + freq = pll_freq / SI5351_MULTISYNTH_A_MAX; + } + + b = (pll_freq % freq * RFRAC_DENOM) / freq; + c = b ? RFRAC_DENOM : 1; + } + + // Calculate parameters + if (divby4 == 1) + { + p3 = 1; + p2 = 0; + p1 = 0; + } + else + { + p1 = 128 * a + ((128 * b) / c) - 512; + p2 = 128 * b - c * ((128 * b) / c); + p3 = c; + } + + reg->p1 = p1; + reg->p2 = p2; + reg->p3 = p3; + + if(ret_val == 0) + { + return pll_freq; + } + else + { + return freq; + } +} + +uint64_t Si5351::multisynth67_calc(uint64_t freq, uint64_t pll_freq, struct Si5351RegSet *reg) +{ + //uint8_t p1; + // uint8_t ret_val = 0; + uint32_t a; + uint64_t lltmp; + + // Multisynth bounds checking + if(freq > SI5351_MULTISYNTH67_MAX_FREQ * SI5351_FREQ_MULT) + { + freq = SI5351_MULTISYNTH67_MAX_FREQ * SI5351_FREQ_MULT; + } + if(freq < SI5351_MULTISYNTH_MIN_FREQ * SI5351_FREQ_MULT) + { + freq = SI5351_MULTISYNTH_MIN_FREQ * SI5351_FREQ_MULT; + } + + if(pll_freq == 0) + { + // Find largest integer divider for max + // VCO frequency and given target frequency + lltmp = (SI5351_PLL_VCO_MAX * SI5351_FREQ_MULT) - 100000000UL; // margin needed? + do_div(lltmp, freq); + a = (uint32_t)lltmp; + + // Divisor has to be even + if(a % 2 != 0) + { + a++; + } + + // Divisor bounds check + if(a < SI5351_MULTISYNTH_A_MIN) + { + a = SI5351_MULTISYNTH_A_MIN; + } + if(a > SI5351_MULTISYNTH67_A_MAX) + { + a = SI5351_MULTISYNTH67_A_MAX; + } + + pll_freq = a * freq; + + // PLL bounds checking + if(pll_freq > (SI5351_PLL_VCO_MAX * SI5351_FREQ_MULT)) + { + a -= 2; + pll_freq = a * freq; + } + else if(pll_freq < (SI5351_PLL_VCO_MIN * SI5351_FREQ_MULT)) + { + a += 2; + pll_freq = a * freq; + } + + reg->p1 = (uint8_t)a; + reg->p2 = 0; + reg->p3 = 0; + return pll_freq; + } + else + { + // Multisynth frequency must be integer division of PLL + if(pll_freq % freq) + { + // No good + return 0; + } + else + { + a = pll_freq / freq; + + // Division ratio bounds check + if(a < SI5351_MULTISYNTH_A_MIN || a > SI5351_MULTISYNTH67_A_MAX) + { + // No bueno + return 0; + } + else + { + reg->p1 = (uint8_t)a; + reg->p2 = 0; + reg->p3 = 0; + return 1; + } + } + } +} + +void Si5351::update_sys_status(struct Si5351Status *status) +{ + uint8_t reg_val = 0; + + reg_val = si5351_read(SI5351_DEVICE_STATUS); + + // Parse the register + status->SYS_INIT = (reg_val >> 7) & 0x01; + status->LOL_B = (reg_val >> 6) & 0x01; + status->LOL_A = (reg_val >> 5) & 0x01; + status->LOS = (reg_val >> 4) & 0x01; + status->REVID = reg_val & 0x03; +} + +void Si5351::update_int_status(struct Si5351IntStatus *int_status) +{ + uint8_t reg_val = 0; + + reg_val = si5351_read(SI5351_INTERRUPT_STATUS); + + // Parse the register + int_status->SYS_INIT_STKY = (reg_val >> 7) & 0x01; + int_status->LOL_B_STKY = (reg_val >> 6) & 0x01; + int_status->LOL_A_STKY = (reg_val >> 5) & 0x01; + int_status->LOS_STKY = (reg_val >> 4) & 0x01; +} + +void Si5351::ms_div(enum si5351_clock clk, uint8_t r_div, uint8_t div_by_4) +{ + uint8_t reg_val = 0; + uint8_t reg_addr = 0; + + switch(clk) + { + case SI5351_CLK0: + reg_addr = SI5351_CLK0_PARAMETERS + 2; + break; + case SI5351_CLK1: + reg_addr = SI5351_CLK1_PARAMETERS + 2; + break; + case SI5351_CLK2: + reg_addr = SI5351_CLK2_PARAMETERS + 2; + break; + case SI5351_CLK3: + reg_addr = SI5351_CLK3_PARAMETERS + 2; + break; + case SI5351_CLK4: + reg_addr = SI5351_CLK4_PARAMETERS + 2; + break; + case SI5351_CLK5: + reg_addr = SI5351_CLK5_PARAMETERS + 2; + break; + case SI5351_CLK6: + reg_addr = SI5351_CLK6_7_OUTPUT_DIVIDER; + break; + case SI5351_CLK7: + reg_addr = SI5351_CLK6_7_OUTPUT_DIVIDER; + break; + } + + reg_val = si5351_read(reg_addr); + + if(clk <= (uint8_t)SI5351_CLK5) + { + // Clear the relevant bits + reg_val &= ~(0x7c); + + if(div_by_4 == 0) + { + reg_val &= ~(SI5351_OUTPUT_CLK_DIVBY4); + } + else + { + reg_val |= (SI5351_OUTPUT_CLK_DIVBY4); + } + + reg_val |= (r_div << SI5351_OUTPUT_CLK_DIV_SHIFT); + } + else if(clk == SI5351_CLK6) + { + // Clear the relevant bits + reg_val &= ~(0x07); + + reg_val |= r_div; + } + else if(clk == SI5351_CLK7) + { + // Clear the relevant bits + reg_val &= ~(0x70); + + reg_val |= (r_div << SI5351_OUTPUT_CLK_DIV_SHIFT); + } + + si5351_write(reg_addr, reg_val); +} + +uint8_t Si5351::select_r_div(uint64_t *freq) +{ + uint8_t r_div = SI5351_OUTPUT_CLK_DIV_1; + + // Choose the correct R divider + if((*freq >= SI5351_CLKOUT_MIN_FREQ * SI5351_FREQ_MULT) && (*freq < SI5351_CLKOUT_MIN_FREQ * SI5351_FREQ_MULT * 2)) + { + r_div = SI5351_OUTPUT_CLK_DIV_128; + *freq *= 128ULL; + } + else if((*freq >= SI5351_CLKOUT_MIN_FREQ * SI5351_FREQ_MULT * 2) && (*freq < SI5351_CLKOUT_MIN_FREQ * SI5351_FREQ_MULT * 4)) + { + r_div = SI5351_OUTPUT_CLK_DIV_64; + *freq *= 64ULL; + } + else if((*freq >= SI5351_CLKOUT_MIN_FREQ * SI5351_FREQ_MULT * 4) && (*freq < SI5351_CLKOUT_MIN_FREQ * SI5351_FREQ_MULT * 8)) + { + r_div = SI5351_OUTPUT_CLK_DIV_32; + *freq *= 32ULL; + } + else if((*freq >= SI5351_CLKOUT_MIN_FREQ * SI5351_FREQ_MULT * 8) && (*freq < SI5351_CLKOUT_MIN_FREQ * SI5351_FREQ_MULT * 16)) + { + r_div = SI5351_OUTPUT_CLK_DIV_16; + *freq *= 16ULL; + } + else if((*freq >= SI5351_CLKOUT_MIN_FREQ * SI5351_FREQ_MULT * 16) && (*freq < SI5351_CLKOUT_MIN_FREQ * SI5351_FREQ_MULT * 32)) + { + r_div = SI5351_OUTPUT_CLK_DIV_8; + *freq *= 8ULL; + } + else if((*freq >= SI5351_CLKOUT_MIN_FREQ * SI5351_FREQ_MULT * 32) && (*freq < SI5351_CLKOUT_MIN_FREQ * SI5351_FREQ_MULT * 64)) + { + r_div = SI5351_OUTPUT_CLK_DIV_4; + *freq *= 4ULL; + } + else if((*freq >= SI5351_CLKOUT_MIN_FREQ * SI5351_FREQ_MULT * 64) && (*freq < SI5351_CLKOUT_MIN_FREQ * SI5351_FREQ_MULT * 128)) + { + r_div = SI5351_OUTPUT_CLK_DIV_2; + *freq *= 2ULL; + } + + return r_div; +} + +uint8_t Si5351::select_r_div_ms67(uint64_t *freq) +{ + uint8_t r_div = SI5351_OUTPUT_CLK_DIV_1; + + // Choose the correct R divider + if((*freq >= SI5351_CLKOUT67_MIN_FREQ * SI5351_FREQ_MULT) && (*freq < SI5351_CLKOUT67_MIN_FREQ * SI5351_FREQ_MULT * 2)) + { + r_div = SI5351_OUTPUT_CLK_DIV_128; + *freq *= 128ULL; + } + else if((*freq >= SI5351_CLKOUT67_MIN_FREQ * SI5351_FREQ_MULT * 2) && (*freq < SI5351_CLKOUT67_MIN_FREQ * SI5351_FREQ_MULT * 4)) + { + r_div = SI5351_OUTPUT_CLK_DIV_64; + *freq *= 64ULL; + } + else if((*freq >= SI5351_CLKOUT67_MIN_FREQ * SI5351_FREQ_MULT * 4) && (*freq < SI5351_CLKOUT67_MIN_FREQ * SI5351_FREQ_MULT * 8)) + { + r_div = SI5351_OUTPUT_CLK_DIV_32; + *freq *= 32ULL; + } + else if((*freq >= SI5351_CLKOUT67_MIN_FREQ * SI5351_FREQ_MULT * 8) && (*freq < SI5351_CLKOUT67_MIN_FREQ * SI5351_FREQ_MULT * 16)) + { + r_div = SI5351_OUTPUT_CLK_DIV_16; + *freq *= 16ULL; + } + else if((*freq >= SI5351_CLKOUT67_MIN_FREQ * SI5351_FREQ_MULT * 16) && (*freq < SI5351_CLKOUT67_MIN_FREQ * SI5351_FREQ_MULT * 32)) + { + r_div = SI5351_OUTPUT_CLK_DIV_8; + *freq *= 8ULL; + } + else if((*freq >= SI5351_CLKOUT67_MIN_FREQ * SI5351_FREQ_MULT * 32) && (*freq < SI5351_CLKOUT67_MIN_FREQ * SI5351_FREQ_MULT * 64)) + { + r_div = SI5351_OUTPUT_CLK_DIV_4; + *freq *= 4ULL; + } + else if((*freq >= SI5351_CLKOUT67_MIN_FREQ * SI5351_FREQ_MULT * 64) && (*freq < SI5351_CLKOUT67_MIN_FREQ * SI5351_FREQ_MULT * 128)) + { + r_div = SI5351_OUTPUT_CLK_DIV_2; + *freq *= 2ULL; + } + + return r_div; +} diff --git a/14_RADAR_Old_version/Firmware/Microcontroller/si5351.h b/14_RADAR_Old_version/Firmware/Microcontroller/si5351.h new file mode 100644 index 0000000..8b59235 --- /dev/null +++ b/14_RADAR_Old_version/Firmware/Microcontroller/si5351.h @@ -0,0 +1,336 @@ +/* + * si5351.h - Si5351 library for Arduino + * + * Copyright (C) 2015 - 2019 Jason Milldrum + * Dana H. Myers + * + * Many defines derived from clk-si5351.h in the Linux kernel. + * Sebastian Hesselbarth + * Rabeeh Khoury + * + * do_div() macro derived from /include/asm-generic/div64.h in + * the Linux kernel. + * Copyright (C) 2003 Bernardo Innocenti + * + * 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 . + */ + +#ifndef SI5351_H_ +#define SI5351_H_ + +#include "main.h" +#include "stm32f7xx_hal.h" +#include "stm32f7xx_hal_i2c.h" +#include + +/* 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_ */