diff --git a/DSTAT1.atsln b/DSTAT1.atsln new file mode 100644 index 0000000000000000000000000000000000000000..c6df6e24e26ad3bfde1ad15a2d2453a4e6ad5975 --- /dev/null +++ b/DSTAT1.atsln @@ -0,0 +1,24 @@ + +Microsoft Visual Studio Solution File, Format Version 11.00 +# Atmel Studio Solution File, Format Version 11.00 +Project("{54F91283-7BC4-4236-8FF9-10F437C3AD48}") = "DSTAT1", "DSTAT1\DSTAT1.cproj", "{38800372-2811-4812-8069-46107EA45AA8}" +EndProject +Global + GlobalSection(SubversionScc) = preSolution + Svn-Managed = True + Manager = AnkhSVN - Subversion Support for Visual Studio + EndGlobalSection + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|AVR = Debug|AVR + Release|AVR = Release|AVR + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {38800372-2811-4812-8069-46107EA45AA8}.Debug|AVR.ActiveCfg = Debug|AVR + {38800372-2811-4812-8069-46107EA45AA8}.Debug|AVR.Build.0 = Debug|AVR + {38800372-2811-4812-8069-46107EA45AA8}.Release|AVR.ActiveCfg = Release|AVR + {38800372-2811-4812-8069-46107EA45AA8}.Release|AVR.Build.0 = Release|AVR + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection +EndGlobal diff --git a/DSTAT1/DSTAT1.cproj b/DSTAT1/DSTAT1.cproj new file mode 100644 index 0000000000000000000000000000000000000000..310ef8639897e880421b7c3340ef13eb15034756 --- /dev/null +++ b/DSTAT1/DSTAT1.cproj @@ -0,0 +1,600 @@ + + + + 2.0 + 6.0 + {38800372-2811-4812-8069-46107ea45aa8} + $(MSBuildProjectName) + $(MSBuildProjectName) + $(MSBuildProjectName) + 3.0.1 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + ATxmega256A3U + xmegaa + C + com.Atmel.AVRGCC8 + + $(MSBuildProjectDirectory)\$(Configuration) + $(MSBuildProjectName) + .elf + Executable + Native + true + false + + 0 + + + + True + True + True + True + + + + + BOARD=USER_BOARD + + + + + ../src + ../src/asf/common/applications/user_application/user_board + ../src/asf/common/boards + ../src/asf/common/boards/user_board + ../src/asf/common/utils + ../src/asf/xmega/utils + ../src/asf/xmega/utils/preprocessor + ../src/config + ../src/asf/common/services/usb/class/cdc/device + ../src/asf/xmega/drivers/cpu + ../src/asf/xmega/drivers/ioport + ../src/asf/xmega/drivers/nvm + ../src/asf/xmega/drivers/sleep + ../src/asf/common/services/clock + ../src/asf/common/services/delay + ../src/asf/common/services/sleepmgr + ../src/asf/common/services/usb + ../src/asf/common/services/usb/class/cdc + ../src/asf/common/services/usb/udc + ../src/asf/xmega/drivers/usb + ../src/asf/common/utils/stdio/stdio_usb + ../src/asf/xmega/drivers/spi + ../src/asf/common/services/spi/xmega_spi + ../src/asf/common/services/spi + ../src/asf/xmega/drivers/pmic + ../src/asf/xmega/drivers/tc + ../src/asf/xmega/drivers/rtc + + + -fdata-sections + True + True + -Werror-implicit-function-declaration -Wmissing-prototypes -Wpointer-arith -Wstrict-prototypes -mrelax -std=gnu99 + + + libprintf_flt.a + libm.a + libc.a + + + True + True + -Wl,-u,vfprintf -lm + -DBOARD=USER_BOARD -mrelax + + + ../src + ../src/asf/common/applications/user_application/user_board + ../src/asf/common/boards + ../src/asf/common/boards/user_board + ../src/asf/common/utils + ../src/asf/xmega/utils + ../src/asf/xmega/utils/preprocessor + ../src/config + ../src/asf/common/services/usb/class/cdc/device + ../src/asf/xmega/drivers/cpu + ../src/asf/xmega/drivers/ioport + ../src/asf/xmega/drivers/nvm + ../src/asf/xmega/drivers/sleep + ../src/asf/common/services/clock + ../src/asf/common/services/delay + ../src/asf/common/services/sleepmgr + ../src/asf/common/services/usb + ../src/asf/common/services/usb/class/cdc + ../src/asf/common/services/usb/udc + ../src/asf/xmega/drivers/usb + ../src/asf/common/utils/stdio/stdio_usb + ../src/asf/xmega/drivers/spi + ../src/asf/common/services/spi/xmega_spi + ../src/asf/common/services/spi + ../src/asf/xmega/drivers/pmic + ../src/asf/xmega/drivers/tc + ../src/asf/xmega/drivers/rtc + + + + + + + + True + True + True + True + + + + + BOARD=USER_BOARD + + + + + ../src + ../src/asf/common/applications/user_application/user_board + ../src/asf/common/boards + ../src/asf/common/boards/user_board + ../src/asf/common/utils + ../src/asf/xmega/utils + ../src/asf/xmega/utils/preprocessor + ../src/config + ../src/asf/common/services/usb/class/cdc/device + ../src/asf/xmega/drivers/cpu + ../src/asf/xmega/drivers/ioport + ../src/asf/xmega/drivers/nvm + ../src/asf/xmega/drivers/sleep + ../src/asf/common/services/clock + ../src/asf/common/services/delay + ../src/asf/common/services/sleepmgr + ../src/asf/common/services/usb + ../src/asf/common/services/usb/class/cdc + ../src/asf/common/services/usb/udc + ../src/asf/xmega/drivers/usb + ../src/asf/common/utils/stdio/stdio_usb + ../src/asf/xmega/drivers/spi + ../src/asf/common/services/spi/xmega_spi + ../src/asf/common/services/spi + ../src/asf/xmega/drivers/pmic + ../src/asf/xmega/drivers/tc + ../src/asf/xmega/drivers/rtc + + + Optimize (-O1) + -fdata-sections + True + Maximum (-g3) + True + -Werror-implicit-function-declaration -Wmissing-prototypes -Wpointer-arith -Wstrict-prototypes -mrelax -std=gnu99 + + + + True + True + -Wl,--relax + -DBOARD=USER_BOARD -mrelax + + + ../src + ../src/asf/common/applications/user_application/user_board + ../src/asf/common/boards + ../src/asf/common/boards/user_board + ../src/asf/common/utils + ../src/asf/xmega/utils + ../src/asf/xmega/utils/preprocessor + ../src/config + ../src/asf/common/services/usb/class/cdc/device + ../src/asf/xmega/drivers/cpu + ../src/asf/xmega/drivers/ioport + ../src/asf/xmega/drivers/nvm + ../src/asf/xmega/drivers/sleep + ../src/asf/common/services/clock + ../src/asf/common/services/delay + ../src/asf/common/services/sleepmgr + ../src/asf/common/services/usb + ../src/asf/common/services/usb/class/cdc + ../src/asf/common/services/usb/udc + ../src/asf/xmega/drivers/usb + ../src/asf/common/utils/stdio/stdio_usb + ../src/asf/xmega/drivers/spi + ../src/asf/common/services/spi/xmega_spi + ../src/asf/common/services/spi + ../src/asf/xmega/drivers/pmic + ../src/asf/xmega/drivers/tc + ../src/asf/xmega/drivers/rtc + + + + + + + + compile + + + compile + + + compile + + + compile + + + compile + + + compile + + + compile + + + compile + + + compile + + + compile + + + compile + + + compile + + + compile + + + compile + + + compile + + + compile + + + compile + + + compile + + + compile + + + compile + + + compile + + + compile + + + compile + + + compile + + + compile + + + compile + + + compile + + + compile + + + compile + + + compile + + + compile + + + compile + + + compile + + + compile + + + compile + + + compile + + + compile + + + compile + + + compile + + + compile + + + compile + + + compile + + + compile + + + compile + + + compile + + + compile + + + compile + + + compile + + + compile + + + compile + + + compile + + + compile + + + compile + + + compile + + + compile + + + compile + + + compile + + + compile + + + compile + + + compile + + + compile + + + compile + + + compile + + + compile + + + compile + + + compile + + + compile + + + compile + + + compile + + + compile + + + compile + + + compile + + + compile + + + compile + + + compile + + + compile + + + compile + + + compile + + + compile + + + compile + + + compile + + + compile + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/DSTAT1/atmel_devices_cdc.inf b/DSTAT1/atmel_devices_cdc.inf new file mode 100644 index 0000000000000000000000000000000000000000..f9ac73bf954a5a1e88a49e3a2cd213d6418e2d88 --- /dev/null +++ b/DSTAT1/atmel_devices_cdc.inf @@ -0,0 +1,119 @@ +; Windows 2000, XP, Vista and 7 (x32 and x64) setup file for Atmel CDC Devices + +; Copyright (c) 2000 Microsoft Corporation +; Copyright (C) 2000-2011 ATMEL, Inc. + +[Version] +Signature="$Windows NT$" +Class=Ports +ClassGuid={4D36E978-E325-11CE-BFC1-08002BE10318} + +Provider=%ATMEL% +LayoutFile=layout.inf +DriverVer=10/15/1999,5.0.2153.1 + +;---------------------------------------------------------- +; Targets +;---------------------------------------------------------- +[Manufacturer] +%ATMEL%=ATMEL, NTamd64 + +[ATMEL] +%ATMEL_CDC_XPLAINED%=Reader, USB\VID_03EB&PID_2122 +%ATMEL_CDC_SFW_EXAMPLE%=Reader, USB\VID_03EB&PID_2307 +%ATMEL_CDC_EVK1XXX%=Reader, USB\VID_03EB&PID_2310 +%ATMEL_CDC_ASF_EXAMPLE%=Reader, USB\VID_03EB&PID_2404 +%ATMEL_CDC_ASF_COMPOSITE_EXAMPLE2%=Reader, USB\VID_03EB&PID_2421&MI_00 +%ATMEL_CDC_ASF_COMPOSITE_EXAMPLE4%=Reader, USB\VID_03EB&PID_2424&MI_00 +%ATMEL_CDC_ASF_EXAMPLE2_COM1%=Reader, USB\VID_03EB&PID_2425&MI_00 +%ATMEL_CDC_ASF_EXAMPLE2_COM2%=Reader, USB\VID_03EB&PID_2425&MI_02 + +[ATMEL.NTamd64] +%ATMEL_CDC_XPLAINED%=DriverInstall, USB\VID_03EB&PID_2122 +%ATMEL_CDC_SFW_EXAMPLE%=DriverInstall, USB\VID_03EB&PID_2307 +%ATMEL_CDC_EVK1XXX%=DriverInstall, USB\VID_03EB&PID_2310 +%ATMEL_CDC_ASF_EXAMPLE%=DriverInstall, USB\VID_03EB&PID_2404 +%ATMEL_CDC_ASF_COMPOSITE_EXAMPLE2%=DriverInstall, USB\VID_03EB&PID_2421&MI_00 +%ATMEL_CDC_ASF_COMPOSITE_EXAMPLE4%=DriverInstall, USB\VID_03EB&PID_2424&MI_00 +%ATMEL_CDC_ASF_EXAMPLE2_COM1%=DriverInstall, USB\VID_03EB&PID_2425&MI_00 +%ATMEL_CDC_ASF_EXAMPLE2_COM2%=DriverInstall, USB\VID_03EB&PID_2425&MI_02 + +;---------------------------------------------------------- +; Windows 2K, XP, and Vista32 +;---------------------------------------------------------- +[Reader_Install.NTx86] + + +[DestinationDirs] +DefaultDestDir=12 +Reader.NT.Copy=12 + +[Reader.NT] +include=mdmcpq.inf +CopyFiles=Reader.NT.Copy +AddReg=Reader.NT.AddReg + +[Reader.NT.Copy] +usbser.sys + +[Reader.NT.AddReg] +HKR,,DevLoader,,*ntkern +HKR,,NTMPDriver,,usbser.sys +HKR,,EnumPropPages32,,"MsPorts.dll,SerialPortPropPageProvider" + +[Reader.NT.Services] +AddService = usbser, 0x00000002, Service_Inst + +[Service_Inst] +DisplayName = %Serial.SvcDesc% +ServiceType = 1 ; SERVICE_KERNEL_DRIVER +StartType = 3 ; SERVICE_DEMAND_START +ErrorControl = 1 ; SERVICE_ERROR_NORMAL +ServiceBinary = %12%\usbser.sys +LoadOrderGroup = Base + + +;---------------------------------------------------------- +; Vista64 +;---------------------------------------------------------- + +[DriverInstall.NTamd64] +include=mdmcpq.inf +CopyFiles=DriverCopyFiles.NTamd64 +AddReg=DriverInstall.NTamd64.AddReg + +[DriverCopyFiles.NTamd64] +usbser.sys,,,0x20 + +[DriverInstall.NTamd64.AddReg] +HKR,,DevLoader,,*ntkern +HKR,,NTMPDriver,,usbser.sys +HKR,,EnumPropPages32,,"MsPorts.dll,SerialPortPropPageProvider" + +[DriverInstall.NTamd64.Services] +AddService=usbser, 0x00000002, DriverService.NTamd64 + +[DriverService.NTamd64] +DisplayName=%Serial.SvcDesc% +ServiceType=1 +StartType=3 +ErrorControl=1 +ServiceBinary=%12%\usbser.sys + +;---------------------------------------------------------- +; String +;---------------------------------------------------------- + +[Strings] +ATMEL = "ATMEL, Inc." +ATMEL_CDC_XPLAINED = "XPLAINED Virtual Com Port" +ATMEL_CDC_SFW_EXAMPLE = "Communication Device Class SFW example" +ATMEL_CDC_EVK1XXX = "EVK1XXX Virtual Com Port" +ATMEL_CDC_ASF_EXAMPLE = "Communication Device Class ASF example" +ATMEL_CDC_ASF_COMPOSITE_EXAMPLE2 = "Communication Device Class ASF composite example 2" +ATMEL_CDC_ASF_COMPOSITE_EXAMPLE4 = "Communication Device Class ASF composite example 4" +ATMEL_CDC_ASF_EXAMPLE2_COM1 = "Communication Device Class ASF example2, COM1" +ATMEL_CDC_ASF_EXAMPLE2_COM2 = "Communication Device Class ASF example2, COM2" + +Serial.SvcDesc = "USB Serial emulation driver" + diff --git a/DSTAT1/src/ads1255.c b/DSTAT1/src/ads1255.c new file mode 100644 index 0000000000000000000000000000000000000000..bcc75861ead98a733198306cd06d35c9ad44a3dd --- /dev/null +++ b/DSTAT1/src/ads1255.c @@ -0,0 +1,423 @@ +/* + * ads1255.c + * + * Created: 04/04/2012 2:13:47 PM + * Author: mdryden + */ + + +#include +#include + +uint8_t buffer_iter = 0; + +struct spi_device spi_device_conf = { + .id = IOPORT_CREATE_PIN(PORTE, 4) + }; + + +void ads1255_init_pins(void) + { + ioport_configure_port_pin(&PORTE, PIN4_bm, IOPORT_INIT_HIGH | IOPORT_DIR_OUTPUT); + ioport_configure_port_pin(&PORTE, PIN5_bm, IOPORT_INIT_HIGH | IOPORT_DIR_OUTPUT); + ioport_configure_port_pin(&PORTE, PIN6_bm, IOPORT_DIR_INPUT /*| IOPORT_PULL_UP*/); + ioport_configure_port_pin(&PORTE, PIN7_bm, IOPORT_INIT_HIGH | IOPORT_DIR_OUTPUT); + //DRDY + ioport_configure_port_pin(&PORTE, PIN3_bm, IOPORT_DIR_INPUT | IOPORT_FALLING); + } + + void ads1255_init_module(void) + { + spi_master_init(&SPIE); + spi_master_setup_device(&SPIE, &spi_device_conf, SPI_MODE_1, 2300000, 0); + spi_enable(&SPIE); + } + +void ads1255_sync(void){ + uint8_t ctrlbuffer = ADS_SYNC; + + spi_select_device(&SPIE, &spi_device_conf); + spi_write_packet(&SPIE, &ctrlbuffer, 1); + spi_deselect_device(&SPIE, &spi_device_conf); + return; +} + + +int32_t ads1255_single_read(void){ + + union{ + uint8_t uint[4]; + int32_t int32; + } input_buffer; + + spi_select_device(&SPIE, &spi_device_conf); + while (ioport_pin_is_high(IOPORT_CREATE_PIN(PORTE, 3))); + spi_write_single(&SPIE, ADS_RDATA); + delay_us(6.5); + spi_write_single(&SPIE, CONFIG_SPI_MASTER_DUMMY); + while(!spi_is_rx_full(&SPIE)); + input_buffer.uint[2] = spi_get(&SPIE); + spi_write_single(&SPIE, CONFIG_SPI_MASTER_DUMMY); + while(!spi_is_rx_full(&SPIE)); + input_buffer.uint[1] = spi_get(&SPIE); + spi_write_single(&SPIE, CONFIG_SPI_MASTER_DUMMY); + while(!spi_is_rx_full(&SPIE)); + input_buffer.uint[0] = spi_get(&SPIE); + spi_write_single(&SPIE, ADS_STANDBY); + + spi_deselect_device(&SPIE, &spi_device_conf); + + ads1255_standby(); + + if (input_buffer.uint[2] > 0x7F) + input_buffer.uint[3] = 0xFF; + else + input_buffer.uint[3] = 0x0; + + #ifdef ADS1255_DBG + printf(logstr1, "ADS1255 result=%li\n\r",input_buffer.int32); + #endif + + if (input_buffer.int32 > ADS_OVERCURRENT_THRESHOLD || (-1*input_buffer.int32) > (ADS_OVERCURRENT_THRESHOLD)) + { + over_under[buffer_iter] = 1; + if (buffer_iter == (ADS_OVER_UNDER_SAMPLES - 1)) + buffer_iter = 0; + else + buffer_iter++; + } + else if (input_buffer.int32 < ADS_UNDERCURRENT_THRESHOLD && (input_buffer.int32*-1) < (ADS_UNDERCURRENT_THRESHOLD)) + { + over_under[buffer_iter] = -1; + if (buffer_iter == (ADS_OVER_UNDER_SAMPLES - 1)) + buffer_iter = 0; + else + buffer_iter++; + } + else + { + over_under[buffer_iter] = 0; + if (buffer_iter == (ADS_OVER_UNDER_SAMPLES - 1)) + buffer_iter = 0; + else + buffer_iter++; + } + + return input_buffer.int32; +} +int16_t ads1255_read_fast(void){ + + + union{ + uint8_t uint[2]; + int16_t int16; + } input_buffer; + +// while (ioport_pin_is_high(IOPORT_CREATE_PIN(PORTE, 3))); + spi_select_device(&SPIE, &spi_device_conf); + spi_write_single(&SPIE, CONFIG_SPI_MASTER_DUMMY); + while(!spi_is_rx_full(&SPIE)); + input_buffer.uint[1] = spi_get(&SPIE); + spi_write_single(&SPIE, CONFIG_SPI_MASTER_DUMMY); + while(!spi_is_rx_full(&SPIE)); + input_buffer.uint[0] = spi_get(&SPIE); + spi_deselect_device(&SPIE, &spi_device_conf); + + #ifdef ADS1255_DBG + printf("ADS1255 result=%li\n\r", input_buffer.int16); + #endif + +// if (input_buffer.int32 > ADS_OVERCURRENT_THRESHOLD || (-1*input_buffer.int32) > (ADS_OVERCURRENT_THRESHOLD)) +// { +// over_under[buffer_iter] = 1; +// if (buffer_iter == (ADS_OVER_UNDER_SAMPLES - 1)) +// buffer_iter = 0; +// else +// buffer_iter++; +// } +// else if (input_buffer.int32 < ADS_UNDERCURRENT_THRESHOLD && (input_buffer.int32*-1) < (ADS_UNDERCURRENT_THRESHOLD)) +// { +// over_under[buffer_iter] = -1; +// if (buffer_iter == (ADS_OVER_UNDER_SAMPLES - 1)) +// buffer_iter = 0; +// else +// buffer_iter++; +// } +// else +// { +// over_under[buffer_iter] = 0; +// if (buffer_iter == (ADS_OVER_UNDER_SAMPLES - 1)) +// buffer_iter = 0; +// else +// buffer_iter++; +// } + + return input_buffer.int16; +} + +int16_t ads1255_read_fast_single(void){ + + + union{ + uint8_t uint[2]; + int16_t int16; + } input_buffer; + + uint8_t commandbuffer = ADS_RDATA; + + spi_select_device(&SPIE, &spi_device_conf); + spi_write_packet(&SPIE, &commandbuffer,1); + delay_us(6.5); + spi_write_single(&SPIE, CONFIG_SPI_MASTER_DUMMY); + while(!spi_is_rx_full(&SPIE)); + input_buffer.uint[1] = spi_get(&SPIE); + spi_write_single(&SPIE, CONFIG_SPI_MASTER_DUMMY); + while(!spi_is_rx_full(&SPIE)); + input_buffer.uint[0] = spi_get(&SPIE); + spi_deselect_device(&SPIE, &spi_device_conf); + + ads1255_standby(); + + #ifdef ADS1255_DBG + printf("ADS1255 result=%li\n\r", input_buffer.int16); + #endif + +// if (input_buffer.int32 > ADS_OVERCURRENT_THRESHOLD || (-1*input_buffer.int32) > (ADS_OVERCURRENT_THRESHOLD)) +// { +// over_under[buffer_iter] = 1; +// if (buffer_iter == (ADS_OVER_UNDER_SAMPLES - 1)) +// buffer_iter = 0; +// else +// buffer_iter++; +// } +// else if (input_buffer.int32 < ADS_UNDERCURRENT_THRESHOLD && (input_buffer.int32*-1) < (ADS_UNDERCURRENT_THRESHOLD)) +// { +// over_under[buffer_iter] = -1; +// if (buffer_iter == (ADS_OVER_UNDER_SAMPLES - 1)) +// buffer_iter = 0; +// else +// buffer_iter++; +// } +// else +// { +// over_under[buffer_iter] = 0; +// if (buffer_iter == (ADS_OVER_UNDER_SAMPLES - 1)) +// buffer_iter = 0; +// else +// buffer_iter++; +// } + + return input_buffer.int16; +} + +int32_t ads1255_read(void){ + +/* irqflags_t flags;*/ + union{ + uint8_t uint[4]; + int32_t int32; + } input_buffer; + + //int32_t returnvalue = 0; + +/* while (ioport_pin_is_high(IOPORT_CREATE_PIN(PORTE, 3)));*/ + +/* flags = cpu_irq_save();*/ + + spi_select_device(&SPIE, &spi_device_conf); + spi_write_single(&SPIE, CONFIG_SPI_MASTER_DUMMY); + while(!spi_is_rx_full(&SPIE)); + input_buffer.uint[2] = spi_get(&SPIE); + spi_write_single(&SPIE, CONFIG_SPI_MASTER_DUMMY); + while(!spi_is_rx_full(&SPIE)); + input_buffer.uint[1] = spi_get(&SPIE); + spi_write_single(&SPIE, CONFIG_SPI_MASTER_DUMMY); + while(!spi_is_rx_full(&SPIE)); + input_buffer.uint[0] = spi_get(&SPIE); + + spi_deselect_device(&SPIE, &spi_device_conf); +/* cpu_irq_restore(flags);*/ + + if (input_buffer.uint[2] > 0x7F) + input_buffer.uint[3] = 0xFF; + else + input_buffer.uint[3] = 0x0; + + #ifdef ADS1255_DBG + printf("ADS1255 result=%li\n\r", input_buffer.int32); + #endif + + if (input_buffer.int32 > ADS_OVERCURRENT_THRESHOLD || (-1*input_buffer.int32) > (ADS_OVERCURRENT_THRESHOLD)) + { + over_under[buffer_iter] = 1; + if (buffer_iter == (ADS_OVER_UNDER_SAMPLES - 1)) + buffer_iter = 0; + else + buffer_iter++; + } + else if (input_buffer.int32 < ADS_UNDERCURRENT_THRESHOLD && (input_buffer.int32*-1) < (ADS_UNDERCURRENT_THRESHOLD)) + { + over_under[buffer_iter] = -1; + if (buffer_iter == (ADS_OVER_UNDER_SAMPLES - 1)) + buffer_iter = 0; + else + buffer_iter++; + } + else + { + over_under[buffer_iter] = 0; + if (buffer_iter == (ADS_OVER_UNDER_SAMPLES - 1)) + buffer_iter = 0; + else + buffer_iter++; + } + + return input_buffer.int32; +} + +int32_t ads1255_read_fast24(void){ + + union{ + uint8_t uint[4]; + int32_t int32; + } input_buffer; + + spi_select_device(&SPIE, &spi_device_conf); + spi_write_single(&SPIE, CONFIG_SPI_MASTER_DUMMY); + while(!spi_is_rx_full(&SPIE)); + input_buffer.uint[2] = spi_get(&SPIE); + spi_write_single(&SPIE, CONFIG_SPI_MASTER_DUMMY); + while(!spi_is_rx_full(&SPIE)); + input_buffer.uint[1] = spi_get(&SPIE); + spi_write_single(&SPIE, CONFIG_SPI_MASTER_DUMMY); + while(!spi_is_rx_full(&SPIE)); + input_buffer.uint[0] = spi_get(&SPIE); + + spi_deselect_device(&SPIE, &spi_device_conf); + + if (input_buffer.uint[2] > 0x7F) + input_buffer.uint[3] = 0xFF; + else + input_buffer.uint[3] = 0x0; + + return input_buffer.int32; +} + + +void ads1255_reg_read(uint8_t address){ + uint8_t command_buffer[2]; + command_buffer[0] = address; + command_buffer[0] |= (1 << 4); + command_buffer[1] = 4; + uint8_t input_buffer[5]; + + spi_select_device(&SPIE, &spi_device_conf); + //delay_us(50); + + while (ioport_pin_is_high(IOPORT_CREATE_PIN(PORTE, 3))); + + spi_write_packet(&SPIE, &command_buffer[0], 2); + + /*spi_put(&SPIE,command_buffer[0]); + while (!spi_is_tx_ok(&SPIE)); + spi_put(&SPIE,command_buffer[1]); + while (!spi_is_tx_ok(&SPIE));*/ + + delay_us(10); + spi_read_packet(&SPIE, (uint8_t*) &input_buffer, 5); + /*for (int i = 0; i<5; i++) + { + spi_put(&SPIE, 0xdd); + while (!spi_is_tx_ok(&SPIE)); + input_buffer[i] = spi_get(&SPIE); + }*/ + + + + spi_deselect_device(&SPIE, &spi_device_conf); + + for (int i=0;i<5;i++) + { + printf("ADS1255: Register %u=%.2x\n\r",i+1,input_buffer[i]); + } + + return; +} + +void ads1255_reset(){ + uint8_t command_buffer = ADS_RESET; + + spi_select_device(&SPIE, &spi_device_conf); + //delay_us(50); + + while (ioport_pin_is_high(IOPORT_CREATE_PIN(PORTE, 3))); + spi_write_packet(&SPIE, (uint8_t*) &command_buffer, 1); + + #ifdef ADS1255_DBG + printf("ADS1255: Sending RESET\n\r"); + printf("ADS1255: Waiting for calibration\n\r"); + #endif + while (ioport_pin_is_high(IOPORT_CREATE_PIN(PORTE, 3))); + + spi_deselect_device(&SPIE, &spi_device_conf); + + return; +} + +void ads1255_setup(uint8_t buff, uint8_t rate, uint8_t pga){ + uint8_t ctrlbuffer = ADS_SDATAC; + uint8_t command_buffer[6] = {0x50,0x03,buff,0x01,pga,rate}; + + spi_select_device(&SPIE, &spi_device_conf); + //delay_us(50); + + //while (ioport_pin_is_high(IOPORT_CREATE_PIN(PORTE, 3))); + + spi_write_packet(&SPIE, &ctrlbuffer, 1); + //while (ioport_pin_is_high(IOPORT_CREATE_PIN(PORTE, 3))); + + spi_write_packet(&SPIE, (uint8_t*)&command_buffer, 6); + + ctrlbuffer = ADS_SYNC; + spi_write_packet(&SPIE, &ctrlbuffer, 1); + ctrlbuffer = ADS_SELFCAL; + spi_write_packet(&SPIE, &ctrlbuffer, 1); + while (ioport_pin_is_high(IOPORT_CREATE_PIN(PORTE, 3))); + + + spi_deselect_device(&SPIE, &spi_device_conf); + + return; +} + +void ads1255_standby(void){ + uint8_t ctrlbuffer = ADS_STANDBY; + + spi_select_device(&SPIE, &spi_device_conf); + spi_write_packet(&SPIE, &ctrlbuffer, 1); + spi_deselect_device(&SPIE, &spi_device_conf); + return; +} + +void ads1255_wakeup(void){ + uint8_t ctrlbuffer = ADS_WAKEUP; + + spi_select_device(&SPIE, &spi_device_conf); + spi_write_packet(&SPIE, &ctrlbuffer, 1); + spi_deselect_device(&SPIE, &spi_device_conf); + return; +} + +void ads1255_rdatac(void){ + uint8_t ctrlbuffer = ADS_RDATAC; + + spi_select_device(&SPIE, &spi_device_conf); + //delay_us(50); + + spi_write_packet(&SPIE, &ctrlbuffer, 1); + while (ioport_pin_is_high(IOPORT_CREATE_PIN(PORTE, 3))); + + spi_deselect_device(&SPIE, &spi_device_conf); + + return; +} \ No newline at end of file diff --git a/DSTAT1/src/ads1255.h b/DSTAT1/src/ads1255.h new file mode 100644 index 0000000000000000000000000000000000000000..e65e4a790d3a6596968ecfad174ca85c50d7458a --- /dev/null +++ b/DSTAT1/src/ads1255.h @@ -0,0 +1,82 @@ +/* + * ads1255.h + * + * Created: 05/03/2012 12:19:33 AM + * Author: mdryden + */ + + +#ifndef ADS1255_H_ +#define ADS1255_H_ + +//#define ADS1255_DBG + +#define ADS_WAKEUP 0x0 +#define ADS_RDATA 0x01 +#define ADS_RDATAC 0x03 +#define ADS_SDATAC 0x0f +#define ADS_SELFCAL 0xf0 +#define ADS_SELFOCAL 0xf1 +#define ADS_SELFGCAL 0xf2 +#define ADS_SYSOCAL 0xf3 +#define ADS_SYSGCAL 0xf4 +#define ADS_SYNC 0xfc +#define ADS_STANDBY 0xfd +#define ADS_RESET 0xfe + +#define ADS_DR_2_5 0b00000011 +#define ADS_DR_5 0b00010011 +#define ADS_DR_10 0b00100011 +#define ADS_DR_15 0b00110011 +#define ADS_DR_25 0b01000011 +#define ADS_DR_30 0b01010011 +#define ADS_DR_50 0b01100011 +#define ADS_DR_60 0b01110010 +#define ADS_DR_100 0b10000010 +#define ADS_DR_500 0b10010010 +#define ADS_DR_1000 0b10100001 +#define ADS_DR_2000 0b10110000 +#define ADS_DR_3750 0b11000000 +#define ADS_DR_7500 0b11010000 +#define ADS_DR_15000 0b11100000 +#define ADS_DR_30000 0b11110000 + +#define ADS_PGA_1 0b000 +#define ADS_PGA_2 0b001 +#define ADS_PGA_4 0b010 +#define ADS_PGA_8 0b011 +#define ADS_PGA_16 0b100 +#define ADS_PGA_32 0b101 +#define ADS_PGA_64 0b110 + +#define ADS_BUFF_OFF 0b0000 +#define ADS_BUFF_ON 0b0010 + +#define ADS_OVERCURRENT_THRESHOLD 7000000L +#define ADS_UNDERCURRENT_THRESHOLD 45000L +#define ADS_OVER_UNDER_SAMPLES 4 + +#include +#include + +int8_t over_under[ADS_OVER_UNDER_SAMPLES]; + +void ads1255_sync(void); +void ads1255_init_pins(void); +void ads1255_init_module(void); +int32_t ads1255_single_read(void); +int32_t ads1255_read(void); +int16_t ads1255_read_fast(void); +int16_t ads1255_read_fast_single(void); +int32_t ads1255_read_fast24(void); +void ads1255_reg_read(uint8_t address); +void ads1255_reset(void); +void ads1255_setup(uint8_t buff, uint8_t rate, uint8_t pga); +void ads1255_standby(void); +void ads1255_wakeup(void); +void ads1255_rdatac(void); + + + +#endif /* ADS1255_H_ */ + diff --git a/DSTAT1/src/asf.h b/DSTAT1/src/asf.h new file mode 100644 index 0000000000000000000000000000000000000000..fa224be1d4e2d9498f951176778a6b4188d3d45a --- /dev/null +++ b/DSTAT1/src/asf.h @@ -0,0 +1,116 @@ +/** + * \file + * + * \brief Autogenerated API include file for the Atmel Software Framework (ASF) + * + * Copyright (c) 2012 Atmel Corporation. All rights reserved. + * + * \asf_license_start + * + * 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. The name of Atmel may not be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * 4. This software may only be redistributed and used in connection with an + * Atmel microcontroller product. + * + * THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE + * EXPRESSLY AND SPECIFICALLY DISCLAIMED. IN NO EVENT SHALL ATMEL 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. + * + * \asf_license_stop + * + */ + +#ifndef ASF_H +#define ASF_H + +/* + * This file includes all API header files for the selected drivers from ASF. + * Note: There might be duplicate includes required by more than one driver. + * + * The file is automatically generated and will be re-written when + * running the ASF driver selector tool. Any changes will be discarded. + */ + +// From module: CPU specific features +#include +#include + +// From module: Generic board support +#include + +// From module: IOPORT - Input/Output Port Controller +#include + +// From module: Interrupt management - XMEGA implementation +#include + +// From module: NVM - Non Volatile Memory +#include + +// From module: PMIC - Programmable Multi-level Interrupt Controller +#include + +// From module: RTC - Real Time Counter +#include + +// From module: SPI - Serial Peripheral Interface +#include + +// From module: SPI - XMEGA implementation +#include +#include + +// From module: Sleep Controller driver +#include + +// From module: Sleep manager - XMEGA A/AU/B/D implementation +#include +#include + +// From module: System Clock Control - XMEGA A1U/A3U/A3BU/A4U implementation +#include + +// From module: TC - Timer Counter +#include + +// From module: TIMING - Delay routines +#include + +// From module: USB CDC Protocol +#include + +// From module: USB Device CDC (Single Interface Device) +#include + +// From module: USB Device Stack Core +#include +#include + +// From module: USB/CDC Standard I/O (stdio) +#include + +// From module: XMEGA compiler driver +#include +#include +#include + +#endif // ASF_H diff --git a/DSTAT1/src/asf/common/boards/board.h b/DSTAT1/src/asf/common/boards/board.h new file mode 100644 index 0000000000000000000000000000000000000000..2ea99622bf73987377ac5f4e966a70b499a62fb9 --- /dev/null +++ b/DSTAT1/src/asf/common/boards/board.h @@ -0,0 +1,264 @@ +/** + * \file + * + * \brief Standard board header file. + * + * This file includes the appropriate board header file according to the + * defined board (parameter BOARD). + * + * Copyright (c) 2009-2011 Atmel Corporation. All rights reserved. + * + * \asf_license_start + * + * 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. The name of Atmel may not be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * 4. This software may only be redistributed and used in connection with an + * Atmel microcontroller product. + * + * THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE + * EXPRESSLY AND SPECIFICALLY DISCLAIMED. IN NO EVENT SHALL ATMEL 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. + * + * \asf_license_stop + * + */ + +#ifndef _BOARD_H_ +#define _BOARD_H_ + +/** + * \defgroup group_common_boards Generic board support + * + * The generic board support module includes board-specific definitions + * and function prototypes, such as the board initialization function. + * + * \{ + */ + +#include "compiler.h" + +#ifdef __cplusplus +extern "C" { +#endif + + +/*! \name Base Boards + */ +//! @{ +#define EVK1100 1 //!< AT32UC3A EVK1100 board. +#define EVK1101 2 //!< AT32UC3B EVK1101 board. +#define UC3C_EK 3 //!< AT32UC3C UC3C_EK board. +#define EVK1104 4 //!< AT32UC3A3 EVK1104 board. +#define EVK1105 5 //!< AT32UC3A EVK1105 board. +#define STK600_RCUC3L0 6 //!< STK600 RCUC3L0 board. +#define UC3L_EK 7 //!< AT32UC3L-EK board. +#define XPLAIN 8 //!< ATxmega128A1 Xplain board. +#define STK600_RC064X 10 //!< ATxmega256A3 STK600 board. +#define STK600_RC100X 11 //!< ATxmega128A1 STK600 board. +#define UC3_A3_XPLAINED 13 //!< ATUC3A3 UC3-A3 Xplained board. +#define UC3_C2_XPLAINED 14 //!< ATUC3A3 UC3-C2 Xplained board. +#define UC3_L0_XPLAINED 15 //!< ATUC3L0 UC3-L0 Xplained board. +#define STK600_RCUC3D 16 //!< STK600 RCUC3D board. +#define STK600_RCUC3C0 17 //!< STK600 RCUC3C board. +#define XMEGA_B1_XPLAINED 18 //!< ATxmega128B1 Xplained board. +#define XMEGA_A1_XPLAINED 19 //!< ATxmega128A1 Xplain-A1 board. +#define STK600_RCUC3L4 21 //!< ATUCL4 STK600 board +#define UC3_L0_XPLAINED_BC 22 //!< ATUC3L0 UC3-L0 Xplained board controller board +#define MEGA1284P_XPLAINED_BC 23 //!< ATmega1284P-Xplained board controller board +#define STK600_RC044X 24 //!< STK600 with RC044X routing card board. +#define STK600_RCUC3B 25 //!< STK600 RCUC3B board. +#define UC3_L0_QT600 26 //!< QT600 UC3L0 MCU board. +#define XMEGA_A3BU_XPLAINED 27 //!< ATxmega256A3BU Xplained board. +#define STK600_RC064X_LCDX 28 //!< XMEGAB3 STK600 RC064X LCDX board. +#define STK600_RC100X_LCDX 29 //!< XMEGAB1 STK600 RC100X LCDX board. +#define UC3B_BOARD_CONTROLLER 30 //!< AT32UC3B1 board controller for Atmel boards +#define RZ600 31 //!< AT32UC3A RZ600 MCU board. +#define SAM3S_EK 32 //!< SAM3S-EK board. +#define SAM3U_EK 33 //!< SAM3U-EK board. +#define SAM3X_EK 34 //!< SAM3X-EK board. +#define SAM3N_EK 35 //!< SAM3N-EK board. +#define SAM3S_EK2 36 //!< SAM3S-EK2 board. +#define SAM4S_EK 37 //!< SAM4S-EK board. +#define SIMULATOR_XMEGA_A1 97 //!< Simulator for XMEGA A1 devices +#define AVR_SIMULATOR_UC3 98 //!< AVR SIMULATOR for AVR UC3 device family. +#define USER_BOARD 99 //!< User-reserved board (if any). +#define DUMMY_BOARD 100 //!< Dummy board to support board-independent applications (e.g. bootloader) +//! @} + +/*! \name Extension Boards + */ +//! @{ +#define EXT1102 1 //!< AT32UC3B EXT1102 board +#define MC300 2 //!< AT32UC3 MC300 board +#define SENSORS_XPLAINED_INERTIAL_1 3 //!< Xplained inertial sensor board 1 +#define SENSORS_XPLAINED_INERTIAL_2 4 //!< Xplained inertial sensor board 2 +#define SENSORS_XPLAINED_PRESSURE_1 5 //!< Xplained pressure sensor board +#define SENSORS_XPLAINED_LIGHTPROX_1 6 //!< Xplained light & proximity sensor board +#define SENSORS_XPLAINED_INERTIAL_A1 7 //!< Xplained inertial sensor board "A" +#define RZ600_AT86RF231 8 //!< AT86RF231 RF board in RZ600 +#define RZ600_AT86RF230B 9 //!< AT86RF231 RF board in RZ600 +#define RZ600_AT86RF212 10 //!< AT86RF231 RF board in RZ600 +#define SENSORS_XPLAINED_BREADBOARD 11 //!< Xplained sensor development breadboard + +#define USER_EXT_BOARD 99 //!< User-reserved extension board (if any). +//! @} + +#if BOARD == EVK1100 + #include "evk1100/evk1100.h" +#elif BOARD == EVK1101 + #include "evk1101/evk1101.h" +#elif BOARD == UC3C_EK + #include "uc3c_ek/uc3c_ek.h" +#elif BOARD == EVK1104 + #include "evk1104/evk1104.h" +#elif BOARD == EVK1105 + #include "evk1105/evk1105.h" +#elif BOARD == STK600_RCUC3L0 + #include "stk600/rcuc3l0/stk600_rcuc3l0.h" +#elif BOARD == UC3L_EK + #include "uc3l_ek/uc3l_ek.h" +#elif BOARD == STK600_RCUC3L4 + #include "stk600/rcuc3l4/stk600_rcuc3l4.h" +#elif BOARD == XPLAIN + #include "xplain/xplain.h" +#elif BOARD == STK600_RC044X + #include "stk600/rc044x/stk600_rc044x.h" +#elif BOARD == STK600_RC064X + #include "stk600/rc064x/stk600_rc064x.h" +#elif BOARD == STK600_RC100X + #include "stk600/rc100x/stk600_rc100x.h" +#elif BOARD == UC3_A3_XPLAINED + #include "uc3_a3_xplained/uc3_a3_xplained.h" +#elif BOARD == UC3_C2_XPLAINED + #include "uc3_c2_xplained/uc3_c2_xplained.h" + #elif BOARD == UC3_L0_XPLAINED + #include "uc3_l0_xplained/uc3_l0_xplained.h" +#elif BOARD == STK600_RCUC3B + #include "stk600/rcuc3b/stk600_rcuc3b.h" +#elif BOARD == STK600_RCUC3D + #include "stk600/rcuc3d/stk600_rcuc3d.h" +#elif BOARD == STK600_RCUC3C0 + #include "stk600/rcuc3c0/stk600_rcuc3c0.h" +#elif BOARD == XMEGA_B1_XPLAINED + #include "xmega_b1_xplained/xmega_b1_xplained.h" +#elif BOARD == STK600_RC064X_LCDX + #include "stk600/rc064x_lcdx/stk600_rc064x_lcdx.h" +#elif BOARD == STK600_RC100X_LCDX + #include "stk600/rc100x_lcdx/stk600_rc100x_lcdx.h" +#elif BOARD == XMEGA_A1_XPLAINED + #include "xmega_a1_xplained/xmega_a1_xplained.h" +#elif BOARD == UC3_L0_XPLAINED_BC + #include "uc3_l0_xplained_bc/uc3_l0_xplained_bc.h" +#elif BOARD == SAM3S_EK + #include "sam3s_ek/sam3s_ek.h" + #include "system_sam3s.h" +#elif BOARD == SAM3S_EK2 + #include "sam3s_ek2/sam3s_ek2.h" + #include "system_sam3sd8.h" +#elif BOARD == SAM3U_EK + #include "sam3u_ek/sam3u_ek.h" + #include "system_sam3u.h" +#elif BOARD == SAM3X_EK + #include "sam3x_ek/sam3x_ek.h" + #include "system_sam3x.h" +#elif BOARD == SAM3N_EK + #include "sam3n_ek/sam3n_ek.h" + #include "system_sam3n.h" +#elif BOARD == SAM4S_EK + #include "sam4s_ek/sam4s_ek.h" + #include "system_sam4s.h" +#elif BOARD == MEGA1284P_XPLAINED_BC + #include "mega1284p_xplained_bc/mega1284p_xplained_bc.h" +#elif BOARD == UC3_L0_QT600 + #include "uc3_l0_qt600/uc3_l0_qt600.h" +#elif BOARD == XMEGA_A3BU_XPLAINED + #include "xmega_a3bu_xplained/xmega_a3bu_xplained.h" +#elif BOARD == UC3B_BOARD_CONTROLLER + #include "uc3b_board_controller/uc3b_board_controller.h" +#elif BOARD == RZ600 + #include "rz600/rz600.h" +#elif BOARD == SIMULATOR_XMEGA_A1 + #include "simulator/xmega_a1/simulator_xmega_a1.h" +#elif BOARD == AVR_SIMULATOR_UC3 + #include "avr_simulator_uc3/avr_simulator_uc3.h" +#elif BOARD == USER_BOARD + // User-reserved area: #include the header file of your board here (if any). + #include "user_board.h" +#elif BOARD == DUMMY_BOARD + #include "dummy/dummy_board.h" +#else + #error No known AVR board defined +#endif + +#if (defined EXT_BOARD) + #if EXT_BOARD == MC300 + #include "mc300/mc300.h" + #elif (EXT_BOARD == SENSORS_XPLAINED_INERTIAL_1) || \ + (EXT_BOARD == SENSORS_XPLAINED_INERTIAL_2) || \ + (EXT_BOARD == SENSORS_XPLAINED_INERTIAL_A1) || \ + (EXT_BOARD == SENSORS_XPLAINED_PRESSURE_1) || \ + (EXT_BOARD == SENSORS_XPLAINED_LIGHTPROX_1) || \ + (EXT_BOARD == SENSORS_XPLAINED_BREADBOARD) + #include "sensors_xplained/sensors_xplained.h" + #elif EXT_BOARD == RZ600_AT86RF231 + #include "at86rf231/at86rf231.h" + #elif EXT_BOARD == RZ600_AT86RF230B + #include "at86rf230b/at86rf230b.h" + #elif EXT_BOARD == RZ600_AT86RF212 + #include "at86rf212/at86rf212.h" + #elif EXT_BOARD == USER_EXT_BOARD + // User-reserved area: #include the header file of your extension board here + // (if any). + #endif +#endif + + +#if (defined(__GNUC__) && defined(__AVR32__)) || (defined(__ICCAVR32__) || defined(__AAVR32__)) +#ifdef __AVR32_ABI_COMPILER__ // Automatically defined when compiling for AVR32, not when assembling. + +/*! \brief This function initializes the board target resources + * + * This function should be called to ensure proper initialization of the target + * board hardware connected to the part. + */ +extern void board_init(void); + +#endif // #ifdef __AVR32_ABI_COMPILER__ +#else +/*! \brief This function initializes the board target resources + * + * This function should be called to ensure proper initialization of the target + * board hardware connected to the part. + */ +extern void board_init(void); +#endif + + +#ifdef __cplusplus +} +#endif + +/** + * \} + */ + +#endif // _BOARD_H_ diff --git a/DSTAT1/src/asf/common/boards/user_board/init.c b/DSTAT1/src/asf/common/boards/user_board/init.c new file mode 100644 index 0000000000000000000000000000000000000000..d849882c284604102bab1f3ef9adcee09cc8e86c --- /dev/null +++ b/DSTAT1/src/asf/common/boards/user_board/init.c @@ -0,0 +1,17 @@ +/** + * \file + * + * \brief User board initialization template + * + */ + +#include +#include + +void board_init(void) +{ + /* This function is meant to contain board-specific initialization code + * for, e.g., the I/O pins. The initialization can rely on application- + * specific board configuration, found in conf_board.h. + */ +} diff --git a/DSTAT1/src/asf/common/boards/user_board/user_board.h b/DSTAT1/src/asf/common/boards/user_board/user_board.h new file mode 100644 index 0000000000000000000000000000000000000000..84b3c243a221c2657cb0120a331f42807cf2f7eb --- /dev/null +++ b/DSTAT1/src/asf/common/boards/user_board/user_board.h @@ -0,0 +1,17 @@ +/** + * \file + * + * \brief User board definition template + * + */ + +#ifndef USER_BOARD_H +#define USER_BOARD_H + +/* This file is intended to contain definitions and configuration details for + * features and devices that are available on the board, e.g., frequency and + * startup time for an external crystal, external memory devices, LED and USART + * pins. + */ + +#endif // USER_BOARD_H diff --git a/DSTAT1/src/asf/common/services/clock/genclk.h b/DSTAT1/src/asf/common/services/clock/genclk.h new file mode 100644 index 0000000000000000000000000000000000000000..d8f1f623eb6dc7dfa839bc745fe57de553629583 --- /dev/null +++ b/DSTAT1/src/asf/common/services/clock/genclk.h @@ -0,0 +1,172 @@ +/** + * \file + * + * \brief Generic clock management + * + * Copyright (c) 2010-2011 Atmel Corporation. All rights reserved. + * + * \asf_license_start + * + * 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. The name of Atmel may not be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * 4. This software may only be redistributed and used in connection with an + * Atmel microcontroller product. + * + * THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE + * EXPRESSLY AND SPECIFICALLY DISCLAIMED. IN NO EVENT SHALL ATMEL 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. + * + * \asf_license_stop + * + */ +#ifndef CLK_GENCLK_H_INCLUDED +#define CLK_GENCLK_H_INCLUDED + +#include "parts.h" + +#if SAM3S +# include "sam3s/genclk.h" +#elif SAM3U +# include "sam3u/genclk.h" +#elif SAM3N +# include "sam3n/genclk.h" +#elif SAM3XA +# include "sam3x/genclk.h" +#elif SAM4S +# include "sam4s/genclk.h" +#elif (UC3A0 || UC3A1) +# include "uc3a0_a1/genclk.h" +#elif UC3A3 +# include "uc3a3_a4/genclk.h" +#elif UC3B +# include "uc3b0_b1/genclk.h" +#elif UC3C +# include "uc3c/genclk.h" +#elif UC3D +# include "uc3d/genclk.h" +#elif UC3L +# include "uc3l/genclk.h" +#else +# error Unsupported chip type +#endif + +/** + * \ingroup clk_group + * \defgroup genclk_group Generic Clock Management + * + * Generic clocks are configurable clocks which run outside the system + * clock domain. They are often connected to peripherals which have an + * asynchronous component running independently of the bus clock, e.g. + * USB controllers, low-power timers and RTCs, etc. + * + * Note that not all platforms have support for generic clocks; on such + * platforms, this API will not be available. + * + * @{ + */ + +/** + * \def GENCLK_DIV_MAX + * \brief Maximum divider supported by the generic clock implementation + */ +/** + * \enum genclk_source + * \brief Generic clock source ID + * + * Each generic clock may be generated from a different clock source. + * These are the available alternatives provided by the chip. + */ + +//! \name Generic clock configuration +//@{ +/** + * \struct genclk_config + * \brief Hardware representation of a set of generic clock parameters + */ +/** + * \fn void genclk_config_defaults(struct genclk_config *cfg, + * unsigned int id) + * \brief Initialize \a cfg to the default configuration for the clock + * identified by \a id. + */ +/** + * \fn void genclk_config_read(struct genclk_config *cfg, unsigned int id) + * \brief Read the currently active configuration of the clock + * identified by \a id into \a cfg. + */ +/** + * \fn void genclk_config_write(const struct genclk_config *cfg, + * unsigned int id) + * \brief Activate the configuration \a cfg on the clock identified by + * \a id. + */ +/** + * \fn void genclk_config_set_source(struct genclk_config *cfg, + * enum genclk_source src) + * \brief Select a new source clock \a src in configuration \a cfg. + */ +/** + * \fn void genclk_config_set_divider(struct genclk_config *cfg, + * unsigned int divider) + * \brief Set a new \a divider in configuration \a cfg. + */ +/** + * \fn void genclk_enable_source(enum genclk_source src) + * \brief Enable the source clock \a src used by a generic clock. + */ + //@} + +//! \name Enabling and disabling Generic Clocks +//@{ +/** + * \fn void genclk_enable(const struct genclk_config *cfg, unsigned int id) + * \brief Activate the configuration \a cfg on the clock identified by + * \a id and enable it. + */ +/** + * \fn void genclk_disable(unsigned int id) + * \brief Disable the generic clock identified by \a id. + */ +//@} + +/** + * \brief Enable the configuration defined by \a src and \a divider + * for the generic clock identified by \a id. + * + * \param id The ID of the generic clock. + * \param src The source clock of the generic clock. + * \param divider The divider used to generate the generic clock. + */ +static inline void genclk_enable_config(unsigned int id, enum genclk_source src, unsigned int divider) +{ + struct genclk_config gcfg; + + genclk_config_defaults(&gcfg, id); + genclk_enable_source(src); + genclk_config_set_source(&gcfg, src); + genclk_config_set_divider(&gcfg, divider); + genclk_enable(&gcfg, id); +} + +//! @} + +#endif /* CLK_GENCLK_H_INCLUDED */ diff --git a/DSTAT1/src/asf/common/services/clock/osc.h b/DSTAT1/src/asf/common/services/clock/osc.h new file mode 100644 index 0000000000000000000000000000000000000000..7dc331b24d78ba69e10cf2ddb5ba457beb2bbca7 --- /dev/null +++ b/DSTAT1/src/asf/common/services/clock/osc.h @@ -0,0 +1,158 @@ +/** + * \file + * + * \brief Oscillator management + * + * Copyright (c) 2010 Atmel Corporation. All rights reserved. + * + * \asf_license_start + * + * 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. The name of Atmel may not be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * 4. This software may only be redistributed and used in connection with an + * Atmel microcontroller product. + * + * THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE + * EXPRESSLY AND SPECIFICALLY DISCLAIMED. IN NO EVENT SHALL ATMEL 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. + * + * \asf_license_stop + * + */ +#ifndef OSC_H_INCLUDED +#define OSC_H_INCLUDED + +#include "parts.h" +#include "conf_clock.h" + +#if SAM3S +# include "sam3s/osc.h" +#elif SAM3XA +# include "sam3x/osc.h" +#elif SAM3U +# include "sam3u/osc.h" +#elif SAM3N +# include "sam3n/osc.h" +#elif SAM4S +# include "sam4s/osc.h" +#elif (UC3A0 || UC3A1) +# include "uc3a0_a1/osc.h" +#elif UC3A3 +# include "uc3a3_a4/osc.h" +#elif UC3B +# include "uc3b0_b1/osc.h" +#elif UC3C +# include "uc3c/osc.h" +#elif UC3D +# include "uc3d/osc.h" +#elif UC3L +# include "uc3l/osc.h" +#elif XMEGA +# include "xmega/osc.h" +#else +# error Unsupported chip type +#endif + +/** + * \ingroup clk_group + * \defgroup osc_group Oscillator Management + * + * This group contains functions and definitions related to configuring + * and enabling/disabling on-chip oscillators. Internal RC-oscillators, + * external crystal oscillators and external clock generators are + * supported by this module. What all of these have in common is that + * they swing at a fixed, nominal frequency which is normally not + * adjustable. + * + * \par Example: Enabling an oscillator + * + * The following example demonstrates how to enable the external + * oscillator on XMEGA A and wait for it to be ready to use. The + * oscillator identifiers are platform-specific, so while the same + * procedure is used on all platforms, the parameter to osc_enable() + * will be different from device to device. + * \code + osc_enable(OSC_ID_XOSC); + osc_wait_ready(OSC_ID_XOSC); \endcode + * + * \section osc_group_board Board-specific Definitions + * If external oscillators are used, the board code must provide the + * following definitions for each of those: + * - \b BOARD__HZ: The nominal frequency of the oscillator. + * - \b BOARD__STARTUP_US: The startup time of the + * oscillator in microseconds. + * - \b BOARD__TYPE: The type of oscillator connected, i.e. + * whether it's a crystal or external clock, and sometimes what kind + * of crystal it is. The meaning of this value is platform-specific. + * + * @{ + */ + +//! \name Oscillator Management +//@{ +/** + * \fn void osc_enable(uint8_t id) + * \brief Enable oscillator \a id + * + * The startup time and mode value is automatically determined based on + * definitions in the board code. + */ +/** + * \fn void osc_disable(uint8_t id) + * \brief Disable oscillator \a id + */ +/** + * \fn osc_is_ready(uint8_t id) + * \brief Determine whether oscillator \a id is ready. + * \retval true Oscillator \a id is running and ready to use as a clock + * source. + * \retval false Oscillator \a id is not running. + */ +/** + * \fn uint32_t osc_get_rate(uint8_t id) + * \brief Return the frequency of oscillator \a id in Hz + */ + +#ifndef __ASSEMBLY__ + +/** + * \brief Wait until the oscillator identified by \a id is ready + * + * This function will busy-wait for the oscillator identified by \a id + * to become stable and ready to use as a clock source. + * + * \param id A number identifying the oscillator to wait for. + */ +static inline void osc_wait_ready(uint8_t id) +{ + while (!osc_is_ready(id)) { + /* Do nothing */ + } +} + +#endif /* __ASSEMBLY__ */ + +//@} + +//! @} + +#endif /* OSC_H_INCLUDED */ diff --git a/DSTAT1/src/asf/common/services/clock/pll.h b/DSTAT1/src/asf/common/services/clock/pll.h new file mode 100644 index 0000000000000000000000000000000000000000..1e700c3a3fb4b4c6ff72491068a75ddb5e18b547 --- /dev/null +++ b/DSTAT1/src/asf/common/services/clock/pll.h @@ -0,0 +1,314 @@ +/** + * \file + * + * \brief PLL management + * + * Copyright (c) 2010-2011 Atmel Corporation. All rights reserved. + * + * \asf_license_start + * + * 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. The name of Atmel may not be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * 4. This software may only be redistributed and used in connection with an + * Atmel microcontroller product. + * + * THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE + * EXPRESSLY AND SPECIFICALLY DISCLAIMED. IN NO EVENT SHALL ATMEL 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. + * + * \asf_license_stop + * + */ +#ifndef CLK_PLL_H_INCLUDED +#define CLK_PLL_H_INCLUDED + +#include "parts.h" +#include "conf_clock.h" + +#if SAM3S +# include "sam3s/pll.h" +#elif SAM3XA +# include "sam3x/pll.h" +#elif SAM3U +# include "sam3u/pll.h" +#elif SAM3N +# include "sam3n/pll.h" +#elif SAM4S +# include "sam4s/pll.h" +#elif (UC3A0 || UC3A1) +# include "uc3a0_a1/pll.h" +#elif UC3A3 +# include "uc3a3_a4/pll.h" +#elif UC3B +# include "uc3b0_b1/pll.h" +#elif UC3C +# include "uc3c/pll.h" +#elif UC3D +# include "uc3d/pll.h" +#elif (UC3L0128 || UC3L0256 || UC3L3_L4) +# include "uc3l/pll.h" +#elif XMEGA +# include "xmega/pll.h" +#else +# error Unsupported chip type +#endif + +/** + * \ingroup clk_group + * \defgroup pll_group PLL Management + * + * This group contains functions and definitions related to configuring + * and enabling/disabling on-chip PLLs. A PLL will take an input signal + * (the \em source), optionally divide the frequency by a configurable + * \em divider, and then multiply the frequency by a configurable \em + * multiplier. + * + * Some devices don't support input dividers; specifying any other + * divisor than 1 on these devices will result in an assertion failure. + * Other devices may have various restrictions to the frequency range of + * the input and output signals. + * + * \par Example: Setting up PLL0 with default parameters + * + * The following example shows how to configure and enable PLL0 using + * the default parameters specified using the configuration symbols + * listed above. + * \code + pll_enable_config_defaults(0); \endcode + * + * To configure, enable PLL0 using the default parameters and to disable + * a specific feature like Wide Bandwidth Mode (a UC3A3-specific + * PLL option.), you can use this initialization process. + * \code + struct pll_config pllcfg; + if (pll_is_locked(pll_id)) { + return; // Pll already running + } + pll_enable_source(CONFIG_PLL0_SOURCE); + pll_config_defaults(&pllcfg, 0); + pll_config_set_option(&pllcfg, PLL_OPT_WBM_DISABLE); + pll_enable(&pllcfg, 0); + pll_wait_for_lock(0); \endcode + * + * When the last function call returns, PLL0 is ready to be used as the + * main system clock source. + * + * \section pll_group_config Configuration Symbols + * + * Each PLL has a set of default parameters determined by the following + * configuration symbols in the application's configuration file: + * - \b CONFIG_PLLn_SOURCE: The default clock source connected to the + * input of PLL \a n. Must be one of the values defined by the + * #pll_source enum. + * - \b CONFIG_PLLn_MUL: The default multiplier (loop divider) of PLL + * \a n. + * - \b CONFIG_PLLn_DIV: The default input divider of PLL \a n. + * + * These configuration symbols determine the result of calling + * pll_config_defaults() and pll_get_default_rate(). + * + * @{ + */ + +//! \name Chip-specific PLL characteristics +//@{ +/** + * \def PLL_MAX_STARTUP_CYCLES + * \brief Maximum PLL startup time in number of slow clock cycles + */ +/** + * \def NR_PLLS + * \brief Number of on-chip PLLs + */ + +/** + * \def PLL_MIN_HZ + * \brief Minimum frequency that the PLL can generate + */ +/** + * \def PLL_MAX_HZ + * \brief Maximum frequency that the PLL can generate + */ +/** + * \def PLL_NR_OPTIONS + * \brief Number of PLL option bits + */ +//@} + +/** + * \enum pll_source + * \brief PLL clock source + */ + +//! \name PLL configuration +//@{ + +/** + * \struct pll_config + * \brief Hardware-specific representation of PLL configuration. + * + * This structure contains one or more device-specific values + * representing the current PLL configuration. The contents of this + * structure is typically different from platform to platform, and the + * user should not access any fields except through the PLL + * configuration API. + */ + +/** + * \fn void pll_config_init(struct pll_config *cfg, + * enum pll_source src, unsigned int div, unsigned int mul) + * \brief Initialize PLL configuration from standard parameters. + * + * \note This function may be defined inline because it is assumed to be + * called very few times, and usually with constant parameters. Inlining + * it will in such cases reduce the code size significantly. + * + * \param cfg The PLL configuration to be initialized. + * \param src The oscillator to be used as input to the PLL. + * \param div PLL input divider. + * \param mul PLL loop divider (i.e. multiplier). + * + * \return A configuration which will make the PLL run at + * (\a mul / \a div) times the frequency of \a src + */ +/** + * \def pll_config_defaults(cfg, pll_id) + * \brief Initialize PLL configuration using default parameters. + * + * After this function returns, \a cfg will contain a configuration + * which will make the PLL run at (CONFIG_PLLx_MUL / CONFIG_PLLx_DIV) + * times the frequency of CONFIG_PLLx_SOURCE. + * + * \param cfg The PLL configuration to be initialized. + * \param pll_id Use defaults for this PLL. + */ +/** + * \def pll_get_default_rate(pll_id) + * \brief Get the default rate in Hz of \a pll_id + */ +/** + * \fn void pll_config_set_option(struct pll_config *cfg, + * unsigned int option) + * \brief Set the PLL option bit \a option in the configuration \a cfg. + * + * \param cfg The PLL configuration to be changed. + * \param option The PLL option bit to be set. + */ +/** + * \fn void pll_config_clear_option(struct pll_config *cfg, + * unsigned int option) + * \brief Clear the PLL option bit \a option in the configuration \a cfg. + * + * \param cfg The PLL configuration to be changed. + * \param option The PLL option bit to be cleared. + */ +/** + * \fn void pll_config_read(struct pll_config *cfg, unsigned int pll_id) + * \brief Read the currently active configuration of \a pll_id. + * + * \param cfg The configuration object into which to store the currently + * active configuration. + * \param pll_id The ID of the PLL to be accessed. + */ +/** + * \fn void pll_config_write(const struct pll_config *cfg, + * unsigned int pll_id) + * \brief Activate the configuration \a cfg on \a pll_id + * + * \param cfg The configuration object representing the PLL + * configuration to be activated. + * \param pll_id The ID of the PLL to be updated. + */ + +//@} + +//! \name Interaction with the PLL hardware +//@{ +/** + * \fn void pll_enable(const struct pll_config *cfg, + * unsigned int pll_id) + * \brief Activate the configuration \a cfg and enable PLL \a pll_id. + * + * \param cfg The PLL configuration to be activated. + * \param pll_id The ID of the PLL to be enabled. + */ +/** + * \fn void pll_disable(unsigned int pll_id) + * \brief Disable the PLL identified by \a pll_id. + * + * After this function is called, the PLL identified by \a pll_id will + * be disabled. The PLL configuration stored in hardware may be affected + * by this, so if the caller needs to restore the same configuration + * later, it should either do a pll_config_read() before disabling the + * PLL, or remember the last configuration written to the PLL. + * + * \param pll_id The ID of the PLL to be disabled. + */ +/** + * \fn bool pll_is_locked(unsigned int pll_id) + * \brief Determine whether the PLL is locked or not. + * + * \param pll_id The ID of the PLL to check. + * + * \retval true The PLL is locked and ready to use as a clock source + * \retval false The PLL is not yet locked, or has not been enabled. + */ +/** + * \fn void pll_enable_source(enum pll_source src) + * \brief Enable the source of the pll. + * The source is enabled, if the source is not already running. + * + * \param src The ID of the PLL source to enable. + */ +/** + * \fn void pll_enable_config_defaults(unsigned int pll_id) + * \brief Enable the pll with the default configuration. + * PLL is enabled, if the PLL is not already locked. + * + * \param pll_id The ID of the PLL to enable. + */ + +/** + * \brief Wait for PLL \a pll_id to become locked + * + * \todo Use a timeout to avoid waiting forever and hanging the system + * + * \param pll_id The ID of the PLL to wait for. + * + * \retval STATUS_OK The PLL is now locked. + * \retval ERR_TIMEOUT Timed out waiting for PLL to become locked. + */ +static inline int pll_wait_for_lock(unsigned int pll_id) +{ + Assert(pll_id < NR_PLLS); + + while (!pll_is_locked(pll_id)) { + /* Do nothing */ + } + + return 0; +} + +//@} +//! @} + +#endif /* CLK_PLL_H_INCLUDED */ diff --git a/DSTAT1/src/asf/common/services/clock/sysclk.h b/DSTAT1/src/asf/common/services/clock/sysclk.h new file mode 100644 index 0000000000000000000000000000000000000000..6930f3b445cb6c5ea91c5fb9887c8ca83e42a352 --- /dev/null +++ b/DSTAT1/src/asf/common/services/clock/sysclk.h @@ -0,0 +1,163 @@ +/** + * \file + * + * \brief System clock management + * + * Copyright (c) 2010 Atmel Corporation. All rights reserved. + * + * \asf_license_start + * + * 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. The name of Atmel may not be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * 4. This software may only be redistributed and used in connection with an + * Atmel microcontroller product. + * + * THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE + * EXPRESSLY AND SPECIFICALLY DISCLAIMED. IN NO EVENT SHALL ATMEL 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. + * + * \asf_license_stop + * + */ +#ifndef SYSCLK_H_INCLUDED +#define SYSCLK_H_INCLUDED + +#include "parts.h" +#include "conf_clock.h" + +#if SAM3S +# include "sam3s/sysclk.h" +#elif SAM3U +# include "sam3u/sysclk.h" +#elif SAM3N +# include "sam3n/sysclk.h" +#elif SAM3XA +# include "sam3x/sysclk.h" +#elif SAM4S +# include "sam4s/sysclk.h" +#elif (UC3A0 || UC3A1) +# include "uc3a0_a1/sysclk.h" +#elif UC3A3 +# include "uc3a3_a4/sysclk.h" +#elif UC3B +# include "uc3b0_b1/sysclk.h" +#elif UC3C +# include "uc3c/sysclk.h" +#elif UC3D +# include "uc3d/sysclk.h" +#elif UC3L +# include "uc3l/sysclk.h" +#elif XMEGA +# include "xmega/sysclk.h" +#else +# error Unsupported chip type +#endif + +/** + * \defgroup clk_group Clock Management + */ + +/** + * \ingroup clk_group + * \defgroup sysclk_group System Clock Management + * + * The sysclk API covers the system clock and all + * clocks derived from it. The system clock is a chip-internal clock on + * which all synchronous clocks, i.e. CPU and bus/peripheral + * clocks, are based. The system clock is typically generated from one + * of a variety of sources, which may include crystal and RC oscillators + * as well as PLLs. The clocks derived from the system clock are + * sometimes also known as synchronous clocks, since they + * always run synchronously with respect to each other, as opposed to + * generic clocks which may run from different oscillators or + * PLLs. + * + * Most applications should simply call sysclk_init() to initialize + * everything related to the system clock and its source (oscillator, + * PLL or DFLL), and leave it at that. More advanced applications, and + * platform-specific drivers, may require additional services from the + * clock system, some of which may be platform-specific. + * + * \section sysclk_group_platform Platform Dependencies + * + * The sysclk API is partially chip- or platform-specific. While all + * platforms provide mostly the same functionality, there are some + * variations around how different bus types and clock tree structures + * are handled. + * + * The following functions are available on all platforms with the same + * parameters and functionality. These functions may be called freely by + * portable applications, drivers and services: + * - sysclk_init() + * - sysclk_set_source() + * - sysclk_get_main_hz() + * - sysclk_get_cpu_hz() + * - sysclk_get_peripheral_bus_hz() + * + * The following functions are available on all platforms, but there may + * be variations in the function signature (i.e. parameters) and + * behaviour. These functions are typically called by platform-specific + * parts of drivers, and applications that aren't intended to be + * portable: + * - sysclk_enable_peripheral_clock() + * - sysclk_disable_peripheral_clock() + * - sysclk_enable_module() + * - sysclk_disable_module() + * - sysclk_module_is_enabled() + * - sysclk_set_prescalers() + * + * All other functions should be considered platform-specific. + * Enabling/disabling clocks to specific peripherals as well as + * determining the speed of these clocks should be done by calling + * functions provided by the driver for that peripheral. + * + * @{ + */ + +//! \name System Clock Initialization +//@{ +/** + * \fn void sysclk_init(void) + * \brief Initialize the synchronous clock system. + * + * This function will initialize the system clock and its source. This + * includes: + * - Mask all synchronous clocks except for any clocks which are + * essential for normal operation (for example internal memory + * clocks). + * - Set up the system clock prescalers as specified by the + * application's configuration file. + * - Enable the clock source specified by the application's + * configuration file (oscillator or PLL) and wait for it to become + * stable. + * - Set the main system clock source to the clock specified by the + * application's configuration file. + * + * Since all non-essential peripheral clocks are initially disabled, it + * is the responsibility of the peripheral driver to re-enable any + * clocks that are needed for normal operation. + */ +//@} + +//! @} + +#endif /* SYSCLK_H_INCLUDED */ diff --git a/DSTAT1/src/asf/common/services/clock/xmega/osc.h b/DSTAT1/src/asf/common/services/clock/xmega/osc.h new file mode 100644 index 0000000000000000000000000000000000000000..c6b6c22e0de44cada07123ff07bf5c8d3c2deab9 --- /dev/null +++ b/DSTAT1/src/asf/common/services/clock/xmega/osc.h @@ -0,0 +1,462 @@ +/** + * \file + * + * \brief Chip-specific oscillator management functions + * + * Copyright (c) 2010-2011 Atmel Corporation. All rights reserved. + * + * \asf_license_start + * + * 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. The name of Atmel may not be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * 4. This software may only be redistributed and used in connection with an + * Atmel microcontroller product. + * + * THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE + * EXPRESSLY AND SPECIFICALLY DISCLAIMED. IN NO EVENT SHALL ATMEL 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. + * + * \asf_license_stop + * + */ +#ifndef XMEGA_OSC_H_INCLUDED +#define XMEGA_OSC_H_INCLUDED + +#include +#include + +/** + * \weakgroup osc_group + * + * \section osc_group_errata Errata + * - Auto-calibration does not work on XMEGA A1 revision H and + * earlier. + * @{ + */ + +//! \name Oscillator identifiers +//@{ +//! 2 MHz Internal RC Oscillator +#define OSC_ID_RC2MHZ OSC_RC2MEN_bm +//! 32 MHz Internal RC Oscillator +#define OSC_ID_RC32MHZ OSC_RC32MEN_bm +//! 32 KHz Internal RC Oscillator +#define OSC_ID_RC32KHZ OSC_RC32KEN_bm +//! External Oscillator +#define OSC_ID_XOSC OSC_XOSCEN_bm +/** + * \brief Reference from USB Start Of Frame + * \note This cannot be enabled or disabled, but can be used as a reference for + * the autocalibration (DFLL). + */ +#define OSC_ID_USBSOF 0xff +//@} + +//! \name External oscillator types +//@{ +#define XOSC_TYPE_EXTERNAL 0 //!< External clock signal +#define XOSC_TYPE_32KHZ 2 //!< 32.768 kHz resonator on TOSC +#define XOSC_TYPE_XTAL 3 //!< 0.4 to 16 MHz resonator on XTAL +//@} + +/** + * \def CONFIG_XOSC_32KHZ_LPM + * \brief Define for enabling Low Power Mode for 32 kHz external oscillator. + */ +#ifdef __DOXYGEN__ +# define CONFIG_XOSC_32KHZ_LPM +#endif /* __DOXYGEN__ */ + +/** + * \def CONFIG_XOSC_STARTUP + * \brief Board-dependent value that determines the number of start-up cycles + * for external resonators, based on BOARD_XOSC_STARTUP_US. This is written to + * the two MSB of the XOSCSEL field of OSC.XOSCCTRL. + * + * \note This is automatically computed from BOARD_XOSC_HZ and + * BOARD_XOSC_STARTUP_US if it is not manually set. + */ + +//! \name XTAL resonator start-up cycles +//@{ +#define XOSC_STARTUP_256 0 //!< 256 cycle start-up time +#define XOSC_STARTUP_1024 1 //!< 1 k cycle start-up time +#define XOSC_STARTUP_16384 2 //!< 16 k cycle start-up time +//@} + +/** + * \def CONFIG_XOSC_RANGE + * \brief Board-dependent value that sets the frequencye range of the external + * oscillator. This is written to the FRQRANGE field of OSC.XOSCCTRL. + * + * \note This is automatically computed from BOARD_XOSC_HZ if it is not manually + * set. + */ + +//! \name XTAL resonator frequency range +//@{ +//! 0.4 to 2 MHz frequency range +#define XOSC_RANGE_04TO2 OSC_FRQRANGE_04TO2_gc +//! 2 to 9 MHz frequency range +#define XOSC_RANGE_2TO9 OSC_FRQRANGE_2TO9_gc +//! 9 to 12 MHz frequency range +#define XOSC_RANGE_9TO12 OSC_FRQRANGE_9TO12_gc +//! 12 to 16 MHz frequency range +#define XOSC_RANGE_12TO16 OSC_FRQRANGE_12TO16_gc +//@} + +/** + * \def XOSC_STARTUP_TIMEOUT + * \brief Number of us to wait for XOSC to start + * + * This is the number of slow clock cycles corresponding to + * OSC0_STARTUP_VALUE with an additional 25% safety margin. If the + * oscillator isn't running when this timeout has expired, it is assumed + * to have failed to start. + */ + +// If application intends to use XOSC. +#ifdef BOARD_XOSC_HZ +// Get start-up config for XOSC, if not manually set. +# ifndef CONFIG_XOSC_STARTUP +# ifndef BOARD_XOSC_STARTUP_US +# error BOARD_XOSC_STARTUP_US must be configured. +# else +//! \internal Number of start-up cycles for the board's XOSC. +# define BOARD_XOSC_STARTUP_CYCLES \ + (BOARD_XOSC_HZ / 1000000 * BOARD_XOSC_STARTUP_US) + +# if (BOARD_XOSC_TYPE == XOSC_TYPE_XTAL) +# if (BOARD_XOSC_STARTUP_CYCLES > 16384) +# error BOARD_XOSC_STARTUP_US is too high for current BOARD_XOSC_HZ. + +# elif (BOARD_XOSC_STARTUP_CYCLES > 1024) +# define CONFIG_XOSC_STARTUP XOSC_STARTUP_16384 +# define XOSC_STARTUP_TIMEOUT (16384*(1000000/BOARD_XOSC_HZ)) + +# elif (BOARD_XOSC_STARTUP_CYCLES > 256) +# define CONFIG_XOSC_STARTUP XOSC_STARTUP_1024 +# define XOSC_STARTUP_TIMEOUT (1024*(1000000/BOARD_XOSC_HZ)) + +# else +# define CONFIG_XOSC_STARTUP XOSC_STARTUP_256 +# define XOSC_STARTUP_TIMEOUT (256*(1000000/BOARD_XOSC_HZ)) +# endif +# else /* BOARD_XOSC_TYPE == XOSC_TYPE_XTAL */ +# define CONFIG_XOSC_STARTUP 0 +# endif +# endif /* BOARD_XOSC_STARTUP_US */ +# endif /* CONFIG_XOSC_STARTUP */ + +// Get frequency range setting for XOSC, if not manually set. +# ifndef CONFIG_XOSC_RANGE +# if (BOARD_XOSC_TYPE == XOSC_TYPE_XTAL) +# if (BOARD_XOSC_HZ < 400000) +# error BOARD_XOSC_HZ is below minimum frequency of 400 kHz. + +# elif (BOARD_XOSC_HZ < 2000000) +# define CONFIG_XOSC_RANGE XOSC_RANGE_04TO2 + +# elif (BOARD_XOSC_HZ < 9000000) +# define CONFIG_XOSC_RANGE XOSC_RANGE_2TO9 + +# elif (BOARD_XOSC_HZ < 12000000) +# define CONFIG_XOSC_RANGE XOSC_RANGE_9TO12 + +# elif (BOARD_XOSC_HZ <= 16000000) +# define CONFIG_XOSC_RANGE XOSC_RANGE_12TO16 + +# else +# error BOARD_XOSC_HZ is above maximum frequency of 16 MHz. +# endif +# else /* BOARD_XOSC_TYPE == XOSC_TYPE_XTAL */ +# define CONFIG_XOSC_RANGE 0 +# endif +# endif /* CONFIG_XOSC_RANGE */ +#endif /* BOARD_XOSC_HZ */ + +#ifndef __ASSEMBLY__ + +/** + * \internal + * \brief Enable internal oscillator \a id + * + * Do not call this function directly. Use osc_enable() instead. + */ +static inline void osc_enable_internal(uint8_t id) +{ + irqflags_t flags; + + Assert(id != OSC_ID_USBSOF); + + flags = cpu_irq_save(); + OSC.CTRL |= id; + cpu_irq_restore(flags); +} + +#if defined(BOARD_XOSC_HZ) || defined(__DOXYGEN__) + +/** + * \internal + * \brief Enable external oscillator \a id + * + * Do not call this function directly. Use osc_enable() instead. Also + * note that this function is only available if the board actually has + * an external oscillator crystal. + */ +static inline void osc_enable_external(uint8_t id) +{ + irqflags_t flags; + + Assert(id == OSC_ID_XOSC); + +#ifndef CONFIG_XOSC_32KHZ_LPM + OSC.XOSCCTRL = BOARD_XOSC_TYPE | (CONFIG_XOSC_STARTUP << 2) | + CONFIG_XOSC_RANGE; +#else + OSC.XOSCCTRL = BOARD_XOSC_TYPE | (CONFIG_XOSC_STARTUP << 2) | + CONFIG_XOSC_RANGE | OSC_X32KLPM_bm; +#endif /* CONFIG_XOSC_32KHZ_LPM */ + + flags = cpu_irq_save(); + OSC.CTRL |= id; + cpu_irq_restore(flags); +} +#else + +static inline void osc_enable_external(uint8_t id) +{ + Assert(false); // No external oscillator on the selected board +} +#endif + +static inline void osc_disable(uint8_t id) +{ + irqflags_t flags; + + Assert(id != OSC_ID_USBSOF); + + flags = cpu_irq_save(); + OSC.CTRL &= ~id; + cpu_irq_restore(flags); +} + +static inline void osc_enable(uint8_t id) +{ + if (id != OSC_ID_XOSC) { + osc_enable_internal(id); + } else { + osc_enable_external(id); + } +} + +static inline bool osc_is_ready(uint8_t id) +{ + Assert(id != OSC_ID_USBSOF); + + return OSC.STATUS & id; +} + +//! \name XMEGA-Specific Oscillator Features +//@{ + +/** + * \brief Enable DFLL-based automatic calibration of an internal + * oscillator. + * + * The XMEGA features two Digital Frequency Locked Loops (DFLLs) which + * can be used to improve the accuracy of the 2 MHz and 32 MHz internal + * RC oscillators. The DFLL compares the oscillator frequency with a + * more accurate reference clock to do automatic run-time calibration of + * the oscillator. + * + * This function enables auto-calibration for either the 2 MHz or 32 MHz + * internal oscillator using either the 32.768 kHz calibrated internal + * oscillator or an external crystal oscillator as a reference. If the + * latter option is used, the crystal must be connected to the TOSC pins + * and run at 32.768 kHz. + * + * \param id The ID of the oscillator for which to enable + * auto-calibration: + * \arg \c OSC_ID_RC2MHZ or \c OSC_ID_RC32MHZ. + * \param ref_id The ID of the oscillator to use as a reference: + * \arg \c OSC_ID_RC32KHZ or \c OSC_ID_XOSC for internal or external 32 kHz + * reference, respectively. + * \arg \c OSC_ID_USBSOF for 32 MHz only when USB is available and running. + */ +static inline void osc_enable_autocalibration(uint8_t id, uint8_t ref_id) +{ + irqflags_t flags; + + flags = cpu_irq_save(); + switch (id) { + case OSC_ID_RC2MHZ: + Assert((ref_id == OSC_ID_RC32KHZ) || (ref_id == OSC_ID_XOSC)); + + if (ref_id == OSC_ID_XOSC) { + OSC.DFLLCTRL |= OSC_RC2MCREF_bm; + } else { + OSC.DFLLCTRL &= ~(OSC_RC2MCREF_bm); + } + DFLLRC2M.CTRL |= DFLL_ENABLE_bm; + break; + + case OSC_ID_RC32MHZ: +#if XMEGA_AU || XMEGA_B || XMEGA_C + Assert((ref_id == OSC_ID_RC32KHZ) + || (ref_id == OSC_ID_XOSC) + || (ref_id == OSC_ID_USBSOF)); + + OSC.DFLLCTRL &= ~(OSC_RC32MCREF_gm); + + if (ref_id == OSC_ID_XOSC) { + OSC.DFLLCTRL |= OSC_RC32MCREF_XOSC32K_gc; + } + else if (ref_id == OSC_ID_USBSOF) { + /* + * Calibrate 32MRC at 48MHz using USB SOF + * 48MHz / 1kHz = 0xBB80 + */ + DFLLRC32M.COMP1 = 0x80; + DFLLRC32M.COMP2 = 0xBB; + OSC.DFLLCTRL |= OSC_RC32MCREF_USBSOF_gc; + } + else if (ref_id == OSC_ID_RC32KHZ) { + /* + * Calibrate 32MRC at 48MHz using USB SOF + * 48MHz / 1kHz = 0xBB80 + */ + DFLLRC32M.COMP1 = 0x80; + DFLLRC32M.COMP2 = 0xBB; + osc_enable(OSC_ID_RC32KHZ); + OSC.DFLLCTRL |= OSC_RC32MCREF_RC32K_gc; + } +#else + Assert((ref_id == OSC_ID_RC32KHZ) || (ref_id == OSC_ID_XOSC)); + + if (ref_id == OSC_ID_XOSC) { + OSC.DFLLCTRL |= OSC_RC32MCREF_bm; + } + else { + OSC.DFLLCTRL &= ~(OSC_RC32MCREF_bm); + } +#endif + DFLLRC32M.CTRL |= DFLL_ENABLE_bm; + break; + + default: + Assert(false); + break; + } + cpu_irq_restore(flags); +} + +/** + * \brief Disable DFLL-based automatic calibration of an internal + * oscillator. + * + * \see osc_enable_autocalibration + * + * \param id The ID of the oscillator for which to disable + * auto-calibration: + * \arg \c OSC_ID_RC2MHZ or \c OSC_ID_RC32MHZ. + */ +static inline void osc_disable_autocalibration(uint8_t id) +{ + switch (id) { + case OSC_ID_RC2MHZ: + DFLLRC2M.CTRL = 0; + break; + + case OSC_ID_RC32MHZ: + DFLLRC32M.CTRL = 0; + break; + + default: + Assert(false); + break; + } +} + +/** + * \brief Load a specific calibration value for the specified oscillator. + * + * \param id The ID of the oscillator for which to disable + * auto-calibration: + * \arg \c OSC_ID_RC2MHZ or \c OSC_ID_RC32MHZ. + * \param calib The specific calibration value required: + * + */ +static inline void osc_user_calibration(uint8_t id, uint16_t calib) +{ + switch (id) { + case OSC_ID_RC2MHZ: + DFLLRC2M.CALA=LSB(calib); + DFLLRC2M.CALB=MSB(calib); + break; + + case OSC_ID_RC32MHZ: + DFLLRC32M.CALA=LSB(calib); + DFLLRC32M.CALB=MSB(calib); + break; + + default: + Assert(false); + break; + } +} +//@} + +static inline uint32_t osc_get_rate(uint8_t id) +{ + Assert(id != OSC_ID_USBSOF); + + switch (id) { + case OSC_ID_RC2MHZ: + return 2000000UL; + + case OSC_ID_RC32MHZ: +#ifdef CONFIG_OSC_RC32_CAL + return CONFIG_OSC_RC32_CAL; +#else + return 32000000UL; +#endif + + case OSC_ID_RC32KHZ: + return 32768UL; + +#ifdef BOARD_XOSC_HZ + case OSC_ID_XOSC: + return BOARD_XOSC_HZ; +#endif + + default: + Assert(false); + return 0; + } +} + +#endif /* __ASSEMBLY__ */ + +//! @} + +#endif /* XMEGA_OSC_H_INCLUDED */ diff --git a/DSTAT1/src/asf/common/services/clock/xmega/pll.h b/DSTAT1/src/asf/common/services/clock/xmega/pll.h new file mode 100644 index 0000000000000000000000000000000000000000..e046c80e94bee89668a89579373ad4e03da43f65 --- /dev/null +++ b/DSTAT1/src/asf/common/services/clock/xmega/pll.h @@ -0,0 +1,260 @@ +/** + * \file + * + * \brief Chip-specific PLL management functions + * + * Copyright (c) 2010-2012 Atmel Corporation. All rights reserved. + * + * \asf_license_start + * + * 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. The name of Atmel may not be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * 4. This software may only be redistributed and used in connection with an + * Atmel microcontroller product. + * + * THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE + * EXPRESSLY AND SPECIFICALLY DISCLAIMED. IN NO EVENT SHALL ATMEL 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. + * + * \asf_license_stop + * + */ +#ifndef XMEGA_PLL_H_INCLUDED +#define XMEGA_PLL_H_INCLUDED + +#include + +/** + * \weakgroup pll_group + * @{ + */ + +#define NR_PLLS 1 +#define PLL_MIN_HZ 10000000UL +#define PLL_MAX_HZ 200000000UL +#define PLL_NR_OPTIONS 0 + +enum pll_source { + //! 2 MHz Internal RC Oscillator + PLL_SRC_RC2MHZ = OSC_PLLSRC_RC2M_gc, + //! 32 MHz Internal RC Oscillator + PLL_SRC_RC32MHZ = OSC_PLLSRC_RC32M_gc, + //! External Clock Source + PLL_SRC_XOSC = OSC_PLLSRC_XOSC_gc, +}; + +#define pll_get_default_rate(pll_id) \ + pll_get_default_rate_priv(CONFIG_PLL##pll_id##_SOURCE, \ + CONFIG_PLL##pll_id##_MUL, \ + CONFIG_PLL##pll_id##_DIV) + +/** + * \internal + * \brief Return clock rate for specified PLL settings. + * + * \note Due to the hardware implementation of the PLL, \a div must be 4 if the + * 32 MHz RC oscillator is used as reference and 1 otherwise. The reference must + * be above 440 kHz, and the output between 10 and 200 MHz. + * + * \param src ID of the PLL's reference source oscillator. + * \param mul Multiplier for the PLL. + * \param div Divisor for the PLL. + * + * \retval Output clock rate from PLL. + */ +static inline uint32_t pll_get_default_rate_priv(enum pll_source src, + unsigned int mul, unsigned int div) +{ + uint32_t rate; + + switch (src) { + case PLL_SRC_RC2MHZ: + rate = 2000000UL; + Assert(div == 1); + break; + + case PLL_SRC_RC32MHZ: +#ifdef CONFIG_OSC_RC32_CAL //32MHz oscillator is calibrated to another frequency + rate = CONFIG_OSC_RC32_CAL / 4; +#else + rate = 8000000UL; + #endif + Assert(div == 4); + break; + + case PLL_SRC_XOSC: + rate = osc_get_rate(OSC_ID_XOSC); + Assert(div == 1); + break; + + default: + break; + } + + Assert(rate >= 440000UL); + + rate *= mul; + + Assert(rate >= PLL_MIN_HZ); + Assert(rate <= PLL_MAX_HZ); + + return rate; +} + +struct pll_config { + uint8_t ctrl; +}; + +/** + * \note The XMEGA PLL hardware uses hard-wired input dividers, so the + * user must ensure that \a div is set as follows: + * - If \a src is PLL_SRC_32MHZ, \a div must be set to 4. + * - Otherwise, \a div must be set to 1. + */ +static inline void pll_config_init(struct pll_config *cfg, enum pll_source src, + unsigned int div, unsigned int mul) +{ + Assert(mul >= 1 && mul <= 31); + + if (src == PLL_SRC_RC32MHZ) { + Assert(div == 4); + } else { + Assert(div == 1); + } + + /* Initialize the configuration */ + cfg->ctrl = src | (mul << OSC_PLLFAC_gp); +} + +#define pll_config_defaults(cfg, pll_id) \ + pll_config_init(cfg, \ + CONFIG_PLL##pll_id##_SOURCE, \ + CONFIG_PLL##pll_id##_DIV, \ + CONFIG_PLL##pll_id##_MUL) + +static inline void pll_config_read(struct pll_config *cfg, unsigned int pll_id) +{ + Assert(pll_id < NR_PLLS); + + cfg->ctrl = OSC.PLLCTRL; +} + +static inline void pll_config_write(const struct pll_config *cfg, + unsigned int pll_id) +{ + Assert(pll_id < NR_PLLS); + + OSC.PLLCTRL = cfg->ctrl; +} + +/** + * \note If a different PLL reference oscillator than those enabled by + * \ref sysclk_init() is used, the user must ensure that the desired reference + * is enabled prior to calling this function. + */ +static inline void pll_enable(const struct pll_config *cfg, + unsigned int pll_id) +{ + irqflags_t flags; + + Assert(pll_id < NR_PLLS); + + flags = cpu_irq_save(); + pll_config_write(cfg, pll_id); + OSC.CTRL |= OSC_PLLEN_bm; + cpu_irq_restore(flags); +} + +/*! \note This will not automatically disable the reference oscillator that is + * configured for the PLL. + */ +static inline void pll_disable(unsigned int pll_id) +{ + irqflags_t flags; + + Assert(pll_id < NR_PLLS); + + flags = cpu_irq_save(); + OSC.CTRL &= ~OSC_PLLEN_bm; + cpu_irq_restore(flags); +} + +static inline bool pll_is_locked(unsigned int pll_id) +{ + Assert(pll_id < NR_PLLS); + + return OSC.STATUS & OSC_PLLRDY_bm; +} + +static inline void pll_enable_source(enum pll_source src) +{ + switch (src) { + case PLL_SRC_RC2MHZ: + break; + + case PLL_SRC_RC32MHZ: + if (!osc_is_ready(OSC_ID_RC32MHZ)) { + osc_enable(OSC_ID_RC32MHZ); + osc_wait_ready(OSC_ID_RC32MHZ); + } + break; + + case PLL_SRC_XOSC: + if (!osc_is_ready(OSC_ID_XOSC)) { + osc_enable(OSC_ID_XOSC); + osc_wait_ready(OSC_ID_XOSC); + } + break; + default: + Assert(false); + break; + } +} + +static inline void pll_enable_config_defaults(unsigned int pll_id) +{ + struct pll_config pllcfg; + + if (pll_is_locked(pll_id)) { + return; // Pll already running + } + switch (pll_id) { +#ifdef CONFIG_PLL0_SOURCE + case 0: + pll_enable_source(CONFIG_PLL0_SOURCE); + pll_config_init(&pllcfg, + CONFIG_PLL0_SOURCE, + CONFIG_PLL0_DIV, + CONFIG_PLL0_MUL); + break; +#endif + default: + Assert(false); + break; + } + pll_enable(&pllcfg, pll_id); + while (!pll_is_locked(pll_id)); +} + +//! @} + +#endif /* XMEGA_PLL_H_INCLUDED */ diff --git a/DSTAT1/src/asf/common/services/clock/xmega/sysclk.c b/DSTAT1/src/asf/common/services/clock/xmega/sysclk.c new file mode 100644 index 0000000000000000000000000000000000000000..42c6e84133975e2e830fd9ad13c55ce6d652688e --- /dev/null +++ b/DSTAT1/src/asf/common/services/clock/xmega/sysclk.c @@ -0,0 +1,227 @@ +/** + * \file + * + * \brief Chip-specific system clock management functions + * + * Copyright (c) 2010-2012 Atmel Corporation. All rights reserved. + * + * \asf_license_start + * + * 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. The name of Atmel may not be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * 4. This software may only be redistributed and used in connection with an + * Atmel microcontroller product. + * + * THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE + * EXPRESSLY AND SPECIFICALLY DISCLAIMED. IN NO EVENT SHALL ATMEL 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. + * + * \asf_license_stop + * + */ + +#include + +#include +#include +#include + +#if XMEGA_AU || XMEGA_B || XMEGA_C +# include +#endif + + +void sysclk_init(void) +{ + uint8_t *reg = (uint8_t *)&PR.PRGEN; + uint8_t i; +#ifdef CONFIG_OSC_RC32_CAL + uint16_t cal; +#endif + /* Turn off all peripheral clocks that can be turned off. */ + for (i = 0; i <= SYSCLK_PORT_F; i++) { + *(reg++) = 0xff; + } + + /* Set up system clock prescalers if different from defaults */ + if ((CONFIG_SYSCLK_PSADIV != SYSCLK_PSADIV_1) + || (CONFIG_SYSCLK_PSBCDIV != SYSCLK_PSBCDIV_1_1)) { + sysclk_set_prescalers(CONFIG_SYSCLK_PSADIV, + CONFIG_SYSCLK_PSBCDIV); + } +#if (CONFIG_OSC_RC32_CAL==48000000UL) + MSB(cal) = nvm_read_production_signature_row( + nvm_get_production_signature_row_offset(USBRCOSC)); + LSB(cal) = nvm_read_production_signature_row( + nvm_get_production_signature_row_offset(USBRCOSCA)); + /* + * If a device has an uncalibrated value in the + * production signature row (early sample part), load a + * sane default calibration value. + */ + if (cal == 0xFFFF) { + cal = 0x2340; + } + osc_user_calibration(OSC_ID_RC32MHZ,cal); +#endif + /* + * Switch to the selected initial system clock source, unless + * the default internal 2 MHz oscillator is selected. + */ + if (CONFIG_SYSCLK_SOURCE != SYSCLK_SRC_RC2MHZ) { + bool need_rc2mhz = false; + + switch (CONFIG_SYSCLK_SOURCE) { + case SYSCLK_SRC_RC32MHZ: + osc_enable(OSC_ID_RC32MHZ); + osc_wait_ready(OSC_ID_RC32MHZ); + break; + + case SYSCLK_SRC_RC32KHZ: + osc_enable(OSC_ID_RC32KHZ); + osc_wait_ready(OSC_ID_RC32KHZ); + break; + + case SYSCLK_SRC_XOSC: + osc_enable(OSC_ID_XOSC); + osc_wait_ready(OSC_ID_XOSC); + break; + +#ifdef CONFIG_PLL0_SOURCE + case SYSCLK_SRC_PLL: + if (CONFIG_PLL0_SOURCE == PLL_SRC_RC2MHZ) { + need_rc2mhz = true; + } + pll_enable_config_defaults(0); + break; +#endif + default: + //unhandled_case(CONFIG_SYSCLK_SOURCE); + return; + } + + ccp_write_io((uint8_t *)&CLK.CTRL, CONFIG_SYSCLK_SOURCE); + Assert(CLK.CTRL == CONFIG_SYSCLK_SOURCE); + +#ifdef CONFIG_OSC_AUTOCAL + osc_enable_autocalibration(CONFIG_OSC_AUTOCAL,CONFIG_OSC_AUTOCAL_REF_OSC); + if (CONFIG_OSC_AUTOCAL == OSC_ID_RC2MHZ + || CONFIG_OSC_AUTOCAL_REF_OSC == OSC_ID_RC2MHZ) { + need_rc2mhz = true; + } +#endif + + if (!need_rc2mhz) { + osc_disable(OSC_ID_RC2MHZ); + } + } +} + +void sysclk_enable_module(enum sysclk_port_id port, uint8_t id) +{ + irqflags_t flags = cpu_irq_save(); + + *((uint8_t *)&PR.PRGEN + port) &= ~id; + + cpu_irq_restore(flags); +} + +void sysclk_disable_module(enum sysclk_port_id port, uint8_t id) +{ + irqflags_t flags = cpu_irq_save(); + + *((uint8_t *)&PR.PRGEN + port) |= id; + + cpu_irq_restore(flags); +} + +#if XMEGA_AU || XMEGA_B || XMEGA_C || defined(__DOXYGEN__) + +/** + * \brief Enable clock for the USB module + * + * \pre CONFIG_USBCLK_SOURCE must be defined. + * + * \param frequency The required USB clock frequency in MHz: + * \arg \c 6 for 6 MHz + * \arg \c 48 for 48 MHz + */ +void sysclk_enable_usb(uint8_t frequency) +{ + uint8_t prescaler; + + Assert((frequency == 6) || (frequency == 48)); + + /* + * Enable or disable prescaler depending on if the USB frequency is 6 + * MHz or 48 MHz. Only 6 MHz USB frequency requires prescaling. + */ + if (frequency == 6) { + prescaler = CLK_USBPSDIV_8_gc; + } + else { + prescaler = 0; + } + + /* + * Switch to the system clock selected by the user. + */ + switch (CONFIG_USBCLK_SOURCE) { + case USBCLK_SRC_RCOSC: + if (!osc_is_ready(OSC_ID_RC32MHZ)) { + osc_enable(OSC_ID_RC32MHZ); + osc_wait_ready(OSC_ID_RC32MHZ); +#ifdef CONFIG_OSC_AUTOCAL + osc_enable_autocalibration(CONFIG_OSC_AUTOCAL,CONFIG_OSC_AUTOCAL_REF_OSC); +#endif + } + ccp_write_io((uint8_t *)&CLK.USBCTRL, (prescaler) + | CLK_USBSRC_RC32M_gc + | CLK_USBSEN_bm); + break; + +#ifdef CONFIG_PLL0_SOURCE + case USBCLK_SRC_PLL: + pll_enable_config_defaults(0); + ccp_write_io((uint8_t *)&CLK.USBCTRL, (prescaler) + | CLK_USBSRC_PLL_gc + | CLK_USBSEN_bm); + break; +#endif + + default: + Assert(false); + break; + } + + sysclk_enable_module(SYSCLK_PORT_GEN, SYSCLK_USB); +} + +/** + * \brief Disable clock for the USB module + */ +void sysclk_disable_usb(void) +{ + sysclk_disable_module(SYSCLK_PORT_GEN, SYSCLK_USB); + ccp_write_io((uint8_t *)&CLK.USBCTRL, 0); +} +#endif // XMEGA_AU || XMEGA_B || XMEGA_C diff --git a/DSTAT1/src/asf/common/services/clock/xmega/sysclk.h b/DSTAT1/src/asf/common/services/clock/xmega/sysclk.h new file mode 100644 index 0000000000000000000000000000000000000000..14bdaf5bae02f6ea3d19c47557571d151c46b333 --- /dev/null +++ b/DSTAT1/src/asf/common/services/clock/xmega/sysclk.h @@ -0,0 +1,1098 @@ +/** + * \file + * + * \brief Chip-specific system clock management functions + * + * Copyright (c) 2010-2011 Atmel Corporation. All rights reserved. + * + * \asf_license_start + * + * 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. The name of Atmel may not be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * 4. This software may only be redistributed and used in connection with an + * Atmel microcontroller product. + * + * THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE + * EXPRESSLY AND SPECIFICALLY DISCLAIMED. IN NO EVENT SHALL ATMEL 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. + * + * \asf_license_stop + * + */ +#ifndef XMEGA_SYSCLK_H_INCLUDED +#define XMEGA_SYSCLK_H_INCLUDED + +#include +#include +#include +#include +#include +#include + +// Include clock configuration for the project. +#include + +#ifdef __cplusplus +extern "C" { +#endif + +// Use 2 MHz with no prescaling if config was empty. +#ifndef CONFIG_SYSCLK_SOURCE +# define CONFIG_SYSCLK_SOURCE SYSCLK_SRC_RC2MHZ +#endif /* CONFIG_SYSCLK_SOURCE */ + +#ifndef CONFIG_SYSCLK_PSADIV +# define CONFIG_SYSCLK_PSADIV SYSCLK_PSADIV_1 +#endif /* CONFIG_SYSCLK_PSADIV */ + +#ifndef CONFIG_SYSCLK_PSBCDIV +# define CONFIG_SYSCLK_PSBCDIV SYSCLK_PSBCDIV_1_1 +#endif /* CONFIG_SYSCLK_PSBCDIV */ + +/** + * \weakgroup sysclk_group + * + * \section sysclk_group_config Configuration Symbols + * + * The following configuration symbols may be used to specify the + * initial system clock configuration. If any of the symbols are not + * set, reasonable defaults will be provided. + * - \b CONFIG_SYSCLK_SOURCE: The initial system clock source. + * - \b CONFIG_SYSCLK_PSADIV: The initial Prescaler A setting. + * - \b CONFIG_SYSCLK_PSBCDIV: The initial Prescaler B setting. + * - \b CONFIG_USBCLK_SOURCE: The initial USB clock source. + * + * @{ + */ + +//! \name System Clock Sources +//@{ +//! Internal 2 MHz RC oscillator +#define SYSCLK_SRC_RC2MHZ CLK_SCLKSEL_RC2M_gc +//! Internal 32 MHz RC oscillator +#define SYSCLK_SRC_RC32MHZ CLK_SCLKSEL_RC32M_gc +//! Internal 32 KHz RC oscillator +#define SYSCLK_SRC_RC32KHZ CLK_SCLKSEL_RC32K_gc +//! External oscillator +#define SYSCLK_SRC_XOSC CLK_SCLKSEL_XOSC_gc +//! Phase-Locked Loop +#define SYSCLK_SRC_PLL CLK_SCLKSEL_PLL_gc +//@} + +//! \name Prescaler A Setting (relative to CLKsys) +//@{ +#define SYSCLK_PSADIV_1 CLK_PSADIV_1_gc //!< Do not prescale +#define SYSCLK_PSADIV_2 CLK_PSADIV_2_gc //!< Prescale CLKper4 by 2 +#define SYSCLK_PSADIV_4 CLK_PSADIV_4_gc //!< Prescale CLKper4 by 4 +#define SYSCLK_PSADIV_8 CLK_PSADIV_8_gc //!< Prescale CLKper4 by 8 +#define SYSCLK_PSADIV_16 CLK_PSADIV_16_gc //!< Prescale CLKper4 by 16 +#define SYSCLK_PSADIV_32 CLK_PSADIV_32_gc //!< Prescale CLKper4 by 32 +#define SYSCLK_PSADIV_64 CLK_PSADIV_64_gc //!< Prescale CLKper4 by 64 +#define SYSCLK_PSADIV_128 CLK_PSADIV_128_gc //!< Prescale CLKper4 by 128 +#define SYSCLK_PSADIV_256 CLK_PSADIV_256_gc //!< Prescale CLKper4 by 256 +#define SYSCLK_PSADIV_512 CLK_PSADIV_512_gc //!< Prescale CLKper4 by 512 +//@} + +//! \name Prescaler B and C Setting (relative to CLKper4) +//@{ +//! Do not prescale +#define SYSCLK_PSBCDIV_1_1 CLK_PSBCDIV_1_1_gc +//! Prescale CLKper and CLKcpu by 2 +#define SYSCLK_PSBCDIV_1_2 CLK_PSBCDIV_1_2_gc +//! Prescale CLKper2, CLKper and CLKcpu by 4 +#define SYSCLK_PSBCDIV_4_1 CLK_PSBCDIV_4_1_gc +//! Prescale CLKper2 by 2, CLKper and CLKcpu by 4 +#define SYSCLK_PSBCDIV_2_2 CLK_PSBCDIV_2_2_gc +//@} + +//! \name System Clock Port Numbers +enum sysclk_port_id { + SYSCLK_PORT_GEN, //!< Devices not associated with a specific port. + SYSCLK_PORT_A, //!< Devices on PORTA + SYSCLK_PORT_B, //!< Devices on PORTB + SYSCLK_PORT_C, //!< Devices on PORTC + SYSCLK_PORT_D, //!< Devices on PORTD + SYSCLK_PORT_E, //!< Devices on PORTE + SYSCLK_PORT_F, //!< Devices on PORTF +}; + +/*! \name Clocks not associated with any port + * + * \note See the datasheet for available modules in the device. + */ +//@{ +#define SYSCLK_DMA PR_DMA_bm //!< DMA Controller +#define SYSCLK_EVSYS PR_EVSYS_bm //!< Event System +#define SYSCLK_RTC PR_RTC_bm //!< Real-Time Counter +#define SYSCLK_EBI PR_EBI_bm //!< Ext Bus Interface +#define SYSCLK_AES PR_AES_bm //!< AES Module +#define SYSCLK_USB PR_USB_bm //!< USB Module +//@} + +/*! \name Clocks on PORTA and PORTB + * + * \note See the datasheet for available modules in the device. + */ +//@{ +#define SYSCLK_AC PR_AC_bm //!< Analog Comparator +#define SYSCLK_ADC PR_ADC_bm //!< A/D Converter +#define SYSCLK_DAC PR_DAC_bm //!< D/A Converter +//@} + +/*! \name Clocks on PORTC, PORTD, PORTE and PORTF + * + * \note See the datasheet for available modules in the device. + */ +//@{ +#define SYSCLK_TC0 PR_TC0_bm //!< Timer/Counter 0 +#define SYSCLK_TC1 PR_TC1_bm //!< Timer/Counter 1 +#define SYSCLK_HIRES PR_HIRES_bm //!< Hi-Res Extension +#define SYSCLK_SPI PR_SPI_bm //!< SPI controller +#define SYSCLK_USART0 PR_USART0_bm //!< USART 0 +#define SYSCLK_USART1 PR_USART1_bm //!< USART 1 +#define SYSCLK_TWI PR_TWI_bm //!< TWI controller +//@} + + +#if XMEGA_AU || XMEGA_B || XMEGA_C +//! \name USB Clock Sources +//@{ +//! Internal 32 MHz RC oscillator +#define USBCLK_SRC_RCOSC 0 +//! Phase-Locked Loop +#define USBCLK_SRC_PLL 1 +//@} + +/** + * \def CONFIG_USBCLK_SOURCE + * \brief Configuration symbol for the USB clock source + * + * If the device features an USB module, and this is intended to be used, this + * symbol must be defined with the clock source configuration. + * + * Define this as one of the \c USBCLK_SRC_xxx definitions. If the PLL is + * selected, it must be configured to run at 48 MHz. If the 32 MHz RC oscillator + * is selected, it must be tuned to 48 MHz by means of the DFLL. + */ +#ifdef __DOXYGEN__ +# define CONFIG_USBCLK_SOURCE +#endif + +#endif // XMEGA_AU || XMEGA_B || XMEGA_C + +#ifndef __ASSEMBLY__ + +/** + * \name Querying the system clock and its derived clocks + */ +//@{ + +/** + * \brief Return the current rate in Hz of the main system clock + * + * \todo This function assumes that the main clock source never changes + * once it's been set up, and that PLL0 always runs at the compile-time + * configured default rate. While this is probably the most common + * configuration, which we want to support as a special case for + * performance reasons, we will at some point need to support more + * dynamic setups as well. + * + * \return Frequency of the main system clock, in Hz. + */ +static inline uint32_t sysclk_get_main_hz(void) +{ + switch (CONFIG_SYSCLK_SOURCE) { + case SYSCLK_SRC_RC2MHZ: + return 2000000UL; + + case SYSCLK_SRC_RC32MHZ: +#ifdef CONFIG_OSC_RC32_CAL + return CONFIG_OSC_RC32_CAL; +#else + return 32000000UL; +#endif + + case SYSCLK_SRC_RC32KHZ: + return 32768UL; + +#ifdef BOARD_XOSC_HZ + case SYSCLK_SRC_XOSC: + return BOARD_XOSC_HZ; +#endif + +#ifdef CONFIG_PLL0_SOURCE + case SYSCLK_SRC_PLL: + return pll_get_default_rate(0); +#endif + + default: + //unhandled_case(CONFIG_SYSCLK_SOURCE); + return 0; + } +} + +/** + * \brief Return the current rate in Hz of clk_PER4. + * + * This clock can run up to four times faster than the CPU clock. + * + * \return Frequency of the clk_PER4 clock, in Hz. + */ +static inline uint32_t sysclk_get_per4_hz(void) +{ + uint8_t shift = 0; + + if (CONFIG_SYSCLK_PSADIV & (1U << CLK_PSADIV_gp)) { + shift = (CONFIG_SYSCLK_PSADIV >> (1 + CLK_PSADIV_gp)) + 1; + } + + return sysclk_get_main_hz() >> shift; +} + +/** + * \brief Return the current rate in Hz of clk_PER2. + * + * This clock can run up to two times faster than the CPU clock. + * + * \return Frequency of the clk_PER2 clock, in Hz. + */ +static inline uint32_t sysclk_get_per2_hz(void) +{ + switch (CONFIG_SYSCLK_PSBCDIV) { + case SYSCLK_PSBCDIV_1_1: /* Fall through */ + case SYSCLK_PSBCDIV_1_2: + return sysclk_get_per4_hz(); + + case SYSCLK_PSBCDIV_4_1: + return sysclk_get_per4_hz() / 4; + + case SYSCLK_PSBCDIV_2_2: + return sysclk_get_per4_hz() / 2; + + default: + //unhandled_case(CONFIG_SYSCLK_PSBCDIV); + return 0; + } +} + +/** + * \brief Return the current rate in Hz of clk_PER. + * + * This clock always runs at the same rate as the CPU clock unless the divider + * is set. + * + * \return Frequency of the clk_PER clock, in Hz. + */ +static inline uint32_t sysclk_get_per_hz(void) +{ + if (CONFIG_SYSCLK_PSBCDIV & (1U << CLK_PSBCDIV_gp)) + return sysclk_get_per2_hz() / 2; + else + return sysclk_get_per2_hz(); +} + +/** + * \brief Return the current rate in Hz of the CPU clock. + * + * \return Frequency of the CPU clock, in Hz. + */ +static inline uint32_t sysclk_get_cpu_hz(void) +{ + return sysclk_get_per_hz(); +} + +/** + * \brief Retrieves the current rate in Hz of the Peripheral Bus clock attached + * to the specified peripheral. + * + * \param module Pointer to the module's base address. + * + * \return Frequency of the bus attached to the specified peripheral, in Hz. + */ +static inline uint32_t sysclk_get_peripheral_bus_hz(const volatile void *module) +{ + if (module == NULL) { + Assert(false); + return 0; + } +#ifdef AES + else if (module == &AES) { + return sysclk_get_per_hz(); + } +#endif +#ifdef EBI + else if (module == &EBI) { + return sysclk_get_per2_hz(); + } +#endif +#ifdef RTC + else if (module == &RTC) { + return sysclk_get_per_hz(); + } +#endif +#ifdef EVSYS + else if (module == &EVSYS) { + return sysclk_get_per_hz(); + } +#endif +#ifdef DMA + else if (module == &DMA) { + return sysclk_get_per_hz(); + } +#endif +#ifdef ACA + else if (module == &ACA) { + return sysclk_get_per_hz(); + } +#endif +#ifdef ACB + else if (module == &ACB) { + return sysclk_get_per_hz(); + } +#endif +#ifdef ADCA + else if (module == &ADCA) { + return sysclk_get_per_hz(); + } +#endif +#ifdef ADCB + else if (module == &ADCB) { + return sysclk_get_per_hz(); + } +#endif +#ifdef DACA + else if (module == &DACA) { + return sysclk_get_per_hz(); + } +#endif +// Workaround for bad XMEGA D header file +#ifndef XMEGA_D +#ifdef DACB + else if (module == &DACB) { + return sysclk_get_per_hz(); + } +#endif +#endif // Workaround end +#ifdef TCC0 + else if (module == &TCC0) { + return sysclk_get_per_hz(); + } +#endif +#ifdef TCD0 + else if (module == &TCD0) { + return sysclk_get_per_hz(); + } +#endif +#ifdef TCE0 + else if (module == &TCE0) { + return sysclk_get_per_hz(); + } +#endif +#ifdef TCF0 + else if (module == &TCF0) { + return sysclk_get_per_hz(); + } +#endif +#ifdef TCC1 + else if (module == &TCC1) { + return sysclk_get_per_hz(); + } +#endif +#ifdef TCD1 + else if (module == &TCD1) { + return sysclk_get_per_hz(); + } +#endif +#ifdef TCE1 + else if (module == &TCE1) { + return sysclk_get_per_hz(); + } +#endif +#ifdef TCF1 + else if (module == &TCF1) { + return sysclk_get_per_hz(); + } +#endif +#ifdef HIRESC + else if (module == &HIRESC) { + return sysclk_get_per4_hz(); + } +#endif +#ifdef HIRESD + else if (module == &HIRESD) { + return sysclk_get_per4_hz(); + } +#endif +#ifdef HIRESE + else if (module == &HIRESE) { + return sysclk_get_per4_hz(); + } +#endif +#ifdef HIRESF + else if (module == &HIRESF) { + return sysclk_get_per4_hz(); + } +#endif +#ifdef SPIC + else if (module == &SPIC) { + return sysclk_get_per_hz(); + } +#endif +#ifdef SPID + else if (module == &SPID) { + return sysclk_get_per_hz(); + } +#endif +#ifdef SPIE + else if (module == &SPIE) { + return sysclk_get_per_hz(); + } +#endif +#ifdef SPIF + else if (module == &SPIF) { + return sysclk_get_per_hz(); + } +#endif +#ifdef USART0C + else if (module == &USART0C) { + return sysclk_get_per_hz(); + } +#endif +#ifdef USART0D + else if (module == &USART0D) { + return sysclk_get_per_hz(); + } +#endif +#ifdef USART0E + else if (module == &USART0E) { + return sysclk_get_per_hz(); + } +#endif +#ifdef USART0F + else if (module == &USART0F) { + return sysclk_get_per_hz(); + } +#endif +#ifdef USART1C + else if (module == &USART1C) { + return sysclk_get_per_hz(); + } +#endif +#ifdef USART1D + else if (module == &USART1D) { + return sysclk_get_per_hz(); + } +#endif +#ifdef USART1E + else if (module == &USART1E) { + return sysclk_get_per_hz(); + } +#endif +#ifdef USART1F + else if (module == &USART1F) { + return sysclk_get_per_hz(); + } +#endif +#ifdef TWIC + else if (module == &TWIC) { + return sysclk_get_per_hz(); + } +#endif +#ifdef TWID + else if (module == &TWID) { + return sysclk_get_per_hz(); + } +#endif +#ifdef TWIE + else if (module == &TWIE) { + return sysclk_get_per_hz(); + } +#endif +#ifdef TWIF + else if (module == &TWIF) { + return sysclk_get_per_hz(); + } +#endif + else { + Assert(false); + return 0; + } +} + +//@} + +//! \name Enabling and disabling synchronous clocks +//@{ + +/** + * \brief Enable the clock to peripheral \a id on port \a port + * + * \param port ID of the port to which the module is connected (one of + * the \c SYSCLK_PORT_* definitions). + * \param id The ID (bitmask) of the peripheral module to be enabled. + */ +extern void sysclk_enable_module(enum sysclk_port_id port, uint8_t id); + +/** + * \brief Disable the clock to peripheral \a id on port \a port + * + * \param port ID of the port to which the module is connected (one of + * the \c SYSCLK_PORT_* definitions). + * \param id The ID (bitmask) of the peripheral module to be disabled. + */ +extern void sysclk_disable_module(enum sysclk_port_id port, uint8_t id); + +/** + * \brief Enable a peripheral's clock from its base address. + * + * Enables the clock to a peripheral, given its base address. If the peripheral + * has an associated clock on the HSB bus, this will be enabled also. + * + * \param module Pointer to the module's base address. + */ +static inline void sysclk_enable_peripheral_clock(const volatile void *module) +{ + if (module == NULL) { + Assert(false); + } +#ifdef AES + else if (module == &AES) { + sysclk_enable_module(SYSCLK_PORT_GEN, SYSCLK_AES); + } +#endif +#ifdef EBI + else if (module == &EBI) { + sysclk_enable_module(SYSCLK_PORT_GEN, SYSCLK_EBI); + } +#endif +#ifdef RTC + else if (module == &RTC) { + sysclk_enable_module(SYSCLK_PORT_GEN, SYSCLK_RTC); + } +#endif +#ifdef EVSYS + else if (module == &EVSYS) { + sysclk_enable_module(SYSCLK_PORT_GEN, SYSCLK_EVSYS); + } +#endif +#ifdef DMA + else if (module == &DMA) { + sysclk_enable_module(SYSCLK_PORT_GEN, SYSCLK_DMA); + } +#endif +#ifdef ACA + else if (module == &ACA) { + sysclk_enable_module(SYSCLK_PORT_A, SYSCLK_AC); + } +#endif +#ifdef ACB + else if (module == &ACB) { + sysclk_enable_module(SYSCLK_PORT_B, SYSCLK_AC); + } +#endif +#ifdef ADCA + else if (module == &ADCA) { + sysclk_enable_module(SYSCLK_PORT_A, SYSCLK_ADC); + } +#endif +#ifdef ADCB + else if (module == &ADCB) { + sysclk_enable_module(SYSCLK_PORT_B, SYSCLK_ADC); + } +#endif +#ifdef DACA + else if (module == &DACA) { + sysclk_enable_module(SYSCLK_PORT_A, SYSCLK_DAC); + } +#endif +// Workaround for bad XMEGA D header file +#ifndef XMEGA_D +#ifdef DACB + else if (module == &DACB) { + sysclk_enable_module(SYSCLK_PORT_B, SYSCLK_DAC); + } +#endif +#endif // Workaround end +#ifdef TCC0 + else if (module == &TCC0) { + sysclk_enable_module(SYSCLK_PORT_C, SYSCLK_TC0); + } +#endif +#ifdef TCD0 + else if (module == &TCD0) { + sysclk_enable_module(SYSCLK_PORT_D, SYSCLK_TC0); + } +#endif +#ifdef TCE0 + else if (module == &TCE0) { + sysclk_enable_module(SYSCLK_PORT_E, SYSCLK_TC0); + } +#endif +#ifdef TCF0 + else if (module == &TCF0) { + sysclk_enable_module(SYSCLK_PORT_F, SYSCLK_TC0); + } +#endif +#ifdef TCC1 + else if (module == &TCC1) { + sysclk_enable_module(SYSCLK_PORT_C, SYSCLK_TC1); + } +#endif +#ifdef TCD1 + else if (module == &TCD1) { + sysclk_enable_module(SYSCLK_PORT_D, SYSCLK_TC1); + } +#endif +#ifdef TCE1 + else if (module == &TCE1) { + sysclk_enable_module(SYSCLK_PORT_E, SYSCLK_TC1); + } +#endif +#ifdef TCF1 + else if (module == &TCF1) { + sysclk_enable_module(SYSCLK_PORT_F, SYSCLK_TC1); + } +#endif +#ifdef HIRESC + else if (module == &HIRESC) { + sysclk_enable_module(SYSCLK_PORT_C, SYSCLK_HIRES); + } +#endif +#ifdef HIRESD + else if (module == &HIRESD) { + sysclk_enable_module(SYSCLK_PORT_D, SYSCLK_HIRES); + } +#endif +#ifdef HIRESE + else if (module == &HIRESE) { + sysclk_enable_module(SYSCLK_PORT_E, SYSCLK_HIRES); + } +#endif +#ifdef HIRESF + else if (module == &HIRESF) { + sysclk_enable_module(SYSCLK_PORT_F, SYSCLK_HIRES); + } +#endif +#ifdef SPIC + else if (module == &SPIC) { + sysclk_enable_module(SYSCLK_PORT_C, SYSCLK_SPI); + } +#endif +#ifdef SPID + else if (module == &SPID) { + sysclk_enable_module(SYSCLK_PORT_D, SYSCLK_SPI); + } +#endif +#ifdef SPIE + else if (module == &SPIE) { + sysclk_enable_module(SYSCLK_PORT_E, SYSCLK_SPI); + } +#endif +#ifdef SPIF + else if (module == &SPIF) { + sysclk_enable_module(SYSCLK_PORT_F, SYSCLK_SPI); + } +#endif +#ifdef USARTC0 + else if (module == &USARTC0) { + sysclk_enable_module(SYSCLK_PORT_C, SYSCLK_USART0); + } +#endif +#ifdef USARTD0 + else if (module == &USARTD0) { + sysclk_enable_module(SYSCLK_PORT_D, SYSCLK_USART0); + } +#endif +#ifdef USARTE0 + else if (module == &USARTE0) { + sysclk_enable_module(SYSCLK_PORT_E, SYSCLK_USART0); + } +#endif +#ifdef USARTF0 + else if (module == &USARTF0) { + sysclk_enable_module(SYSCLK_PORT_F, SYSCLK_USART0); + } +#endif +#ifdef USARTC1 + else if (module == &USARTC1) { + sysclk_enable_module(SYSCLK_PORT_C, SYSCLK_USART1); + } +#endif +#ifdef USARTD1 + else if (module == &USARTD1) { + sysclk_enable_module(SYSCLK_PORT_D, SYSCLK_USART1); + } +#endif +#ifdef USARTE1 + else if (module == &USARTE1) { + sysclk_enable_module(SYSCLK_PORT_E, SYSCLK_USART1); + } +#endif +#ifdef USARTF1 + else if (module == &USARTF1) { + sysclk_enable_module(SYSCLK_PORT_F, SYSCLK_USART1); + } +#endif +#ifdef TWIC + else if (module == &TWIC) { + sysclk_enable_module(SYSCLK_PORT_C, SYSCLK_TWI); + } +#endif +#ifdef TWID + else if (module == &TWID) { + sysclk_enable_module(SYSCLK_PORT_D, SYSCLK_TWI); + } +#endif +#ifdef TWIE + else if (module == &TWIE) { + sysclk_enable_module(SYSCLK_PORT_E, SYSCLK_TWI); + } +#endif +#ifdef TWIF + else if (module == &TWIF) { + sysclk_enable_module(SYSCLK_PORT_F, SYSCLK_TWI); + } +#endif + else { + Assert(false); + } +} + +/** + * \brief Disable a peripheral's clock from its base address. + * + * Disables the clock to a peripheral, given its base address. If the peripheral + * has an associated clock on the HSB bus, this will be disabled also. + * + * \param module Pointer to the module's base address. + */ +static inline void sysclk_disable_peripheral_clock(const volatile void *module) +{ + if (module == NULL) { + Assert(false); + } +#ifdef AES + else if (module == &AES) { + sysclk_disable_module(SYSCLK_PORT_GEN, SYSCLK_AES); + } +#endif +#ifdef EBI + else if (module == &EBI) { + sysclk_disable_module(SYSCLK_PORT_GEN, SYSCLK_EBI); + } +#endif +#ifdef RTC + else if (module == &RTC) { + sysclk_disable_module(SYSCLK_PORT_GEN, SYSCLK_RTC); + } +#endif +#ifdef EVSYS + else if (module == &EVSYS) { + sysclk_disable_module(SYSCLK_PORT_GEN, SYSCLK_EVSYS); + } +#endif +#ifdef DMA + else if (module == &DMA) { + sysclk_disable_module(SYSCLK_PORT_GEN, SYSCLK_DMA); + } +#endif +#ifdef ACA + else if (module == &ACA) { + sysclk_disable_module(SYSCLK_PORT_A, SYSCLK_AC); + } +#endif +#ifdef ACB + else if (module == &ACB) { + sysclk_disable_module(SYSCLK_PORT_B, SYSCLK_AC); + } +#endif +#ifdef ADCA + else if (module == &ADCA) { + sysclk_disable_module(SYSCLK_PORT_A, SYSCLK_ADC); + } +#endif +#ifdef ADCB + else if (module == &ADCB) { + sysclk_disable_module(SYSCLK_PORT_B, SYSCLK_ADC); + } +#endif +#ifdef DACA + else if (module == &DACA) { + sysclk_disable_module(SYSCLK_PORT_A, SYSCLK_DAC); + } +#endif +// Workaround for bad XMEGA D header file +#ifndef XMEGA_D +#ifdef DACB + else if (module == &DACB) { + sysclk_disable_module(SYSCLK_PORT_B, SYSCLK_DAC); + } +#endif +#endif // Workaround end +#ifdef TCC0 + else if (module == &TCC0) { + sysclk_disable_module(SYSCLK_PORT_C, SYSCLK_TC0); + } +#endif +#ifdef TCD0 + else if (module == &TCD0) { + sysclk_disable_module(SYSCLK_PORT_D, SYSCLK_TC0); + } +#endif +#ifdef TCE0 + else if (module == &TCE0) { + sysclk_disable_module(SYSCLK_PORT_E, SYSCLK_TC0); + } +#endif +#ifdef TCF0 + else if (module == &TCF0) { + sysclk_disable_module(SYSCLK_PORT_F, SYSCLK_TC0); + } +#endif +#ifdef TCC1 + else if (module == &TCC1) { + sysclk_disable_module(SYSCLK_PORT_C, SYSCLK_TC1); + } +#endif +#ifdef TCD1 + else if (module == &TCD1) { + sysclk_disable_module(SYSCLK_PORT_D, SYSCLK_TC1); + } +#endif +#ifdef TCE1 + else if (module == &TCE1) { + sysclk_disable_module(SYSCLK_PORT_E, SYSCLK_TC1); + } +#endif +#ifdef TCF1 + else if (module == &TCF1) { + sysclk_disable_module(SYSCLK_PORT_F, SYSCLK_TC1); + } +#endif +#ifdef HIRESC + else if (module == &HIRESC) { + sysclk_disable_module(SYSCLK_PORT_C, SYSCLK_HIRES); + } +#endif +#ifdef HIRESD + else if (module == &HIRESD) { + sysclk_disable_module(SYSCLK_PORT_D, SYSCLK_HIRES); + } +#endif +#ifdef HIRESE + else if (module == &HIRESE) { + sysclk_disable_module(SYSCLK_PORT_E, SYSCLK_HIRES); + } +#endif +#ifdef HIRESF + else if (module == &HIRESF) { + sysclk_disable_module(SYSCLK_PORT_F, SYSCLK_HIRES); + } +#endif +#ifdef SPIC + else if (module == &SPIC) { + sysclk_disable_module(SYSCLK_PORT_C, SYSCLK_SPI); + } +#endif +#ifdef SPID + else if (module == &SPID) { + sysclk_disable_module(SYSCLK_PORT_D, SYSCLK_SPI); + } +#endif +#ifdef SPIE + else if (module == &SPIE) { + sysclk_disable_module(SYSCLK_PORT_E, SYSCLK_SPI); + } +#endif +#ifdef SPIF + else if (module == &SPIF) { + sysclk_disable_module(SYSCLK_PORT_F, SYSCLK_SPI); + } +#endif +#ifdef USART0C + else if (module == &USART0C) { + sysclk_disable_module(SYSCLK_PORT_C, SYSCLK_USART0); + } +#endif +#ifdef USART0D + else if (module == &USART0D) { + sysclk_disable_module(SYSCLK_PORT_D, SYSCLK_USART0); + } +#endif +#ifdef USART0E + else if (module == &USART0E) { + sysclk_disable_module(SYSCLK_PORT_E, SYSCLK_USART0); + } +#endif +#ifdef USART0F + else if (module == &USART0F) { + sysclk_disable_module(SYSCLK_PORT_F, SYSCLK_USART0); + } +#endif +#ifdef USART1C + else if (module == &USART1C) { + sysclk_disable_module(SYSCLK_PORT_C, SYSCLK_USART1); + } +#endif +#ifdef USART1D + else if (module == &USART1D) { + sysclk_disable_module(SYSCLK_PORT_D, SYSCLK_USART1); + } +#endif +#ifdef USART1E + else if (module == &USART1E) { + sysclk_disable_module(SYSCLK_PORT_E, SYSCLK_USART1); + } +#endif +#ifdef USART1F + else if (module == &USART1F) { + sysclk_disable_module(SYSCLK_PORT_F, SYSCLK_USART1); + } +#endif +#ifdef TWIC + else if (module == &TWIC) { + sysclk_disable_module(SYSCLK_PORT_C, SYSCLK_TWI); + } +#endif +#ifdef TWID + else if (module == &TWID) { + sysclk_disable_module(SYSCLK_PORT_D, SYSCLK_TWI); + } +#endif +#ifdef TWIE + else if (module == &TWIE) { + sysclk_disable_module(SYSCLK_PORT_E, SYSCLK_TWI); + } +#endif +#ifdef TWIF + else if (module == &TWIF) { + sysclk_disable_module(SYSCLK_PORT_F, SYSCLK_TWI); + } +#endif + else { + Assert(false); + } +} + +/** + * \brief Check if the synchronous clock is enabled for a module + * + * \param port ID of the port to which the module is connected (one of + * the \c SYSCLK_PORT_* definitions). + * \param id The ID (bitmask) of the peripheral module to check (one of + * the \c SYSCLK_* module definitions). + * + * \retval true If the clock for module \a id on \a port is enabled. + * \retval false If the clock for module \a id on \a port is disabled. + */ +static inline bool sysclk_module_is_enabled(enum sysclk_port_id port, + uint8_t id) +{ + uint8_t mask = *((uint8_t *)&PR.PRGEN + port); + return (mask & id) == 0; +} + +#if XMEGA_AU || XMEGA_B || XMEGA_C || defined(__DOXYGEN__) +# if defined(CONFIG_USBCLK_SOURCE) || defined(__DOXYGEN__) +# if (CONFIG_USBCLK_SOURCE == USBCLK_SRC_RCOSC) +# define USBCLK_STARTUP_TIMEOUT 1 +# elif (CONFIG_USBCLK_SOURCE == USBCLK_SRC_PLL) +# if (CONFIG_PLL0_SOURCE == PLL_SRC_XOSC) +# define USBCLK_STARTUP_TIMEOUT XOSC_STARTUP_TIMEOUT +# elif (CONFIG_PLL0_SOURCE == PLL_SRC_RC32MHZ) +# define USBCLK_STARTUP_TIMEOUT 1 +# elif (CONFIG_PLL0_SOURCE == PLL_SRC_RC2MHZ) +# define USBCLK_STARTUP_TIMEOUT 1 +# else +# error Unknow value for CONFIG_PLL0_SOURCE, see conf_clock.h. +# endif +# endif +# else /* CONFIG_USBCLK_SOURCE not defined */ +# define CONFIG_USBCLK_SOURCE USBCLK_SRC_RCOSC +# define USBCLK_STARTUP_TIMEOUT 1 +# endif /* CONFIG_USBCLK_SOURCE */ +void sysclk_enable_usb(uint8_t frequency); +void sysclk_disable_usb(void); +#endif /* XMEGA_AU || XMEGA_B || XMEGA_C */ +//@} + +//! \name System Clock Source and Prescaler configuration +//@{ + +/** + * \brief Set system clock prescaler configuration + * + * This function will change the system clock prescaler configuration to + * match the parameters. + * + * \note The parameters to this function are device-specific. + * + * \param psadiv The prescaler A setting (one of the \c SYSCLK_PSADIV_* + * definitions). This determines the clkPER4 frequency. + * \param psbcdiv The prescaler B and C settings (one of the \c SYSCLK_PSBCDIV_* + * definitions). These determine the clkPER2, clkPER and clkCPU frequencies. + */ +static inline void sysclk_set_prescalers(uint8_t psadiv, uint8_t psbcdiv) +{ + ccp_write_io((uint8_t *)&CLK.PSCTRL, psadiv | psbcdiv); +} + +/** + * \brief Change the source of the main system clock. + * + * \param src The new system clock source. Must be one of the constants + * from the System Clock Sources section. + */ +static inline void sysclk_set_source(uint8_t src) +{ + ccp_write_io((uint8_t *)&CLK.CTRL, src); +} + +/** + * \brief Lock the system clock configuration + * + * This function will lock the current system clock source and prescaler + * configuration, preventing any further changes. + */ +static inline void sysclk_lock(void) +{ + ccp_write_io((uint8_t *)&CLK.LOCK, CLK_LOCK_bm); +} + +//@} + +//! \name System Clock Initialization +//@{ + +extern void sysclk_init(void); + +//@} + +#endif /* !__ASSEMBLY__ */ + +//! @} + +#ifdef __cplusplus +} +#endif + +#endif /* XMEGA_SYSCLK_H_INCLUDED */ diff --git a/DSTAT1/src/asf/common/services/delay/delay.h b/DSTAT1/src/asf/common/services/delay/delay.h new file mode 100644 index 0000000000000000000000000000000000000000..c739053e68948419792b35e0ab8a42d5c9f12e7c --- /dev/null +++ b/DSTAT1/src/asf/common/services/delay/delay.h @@ -0,0 +1,133 @@ +/** + * \file + * + * \brief Common Delay Service + * + * Copyright (c) 2011 - 2012 Atmel Corporation. All rights reserved. + * + * \asf_license_start + * + * 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. The name of Atmel may not be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * 4. This software may only be redistributed and used in connection with an + * Atmel microcontroller product. + * + * THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE + * EXPRESSLY AND SPECIFICALLY DISCLAIMED. IN NO EVENT SHALL ATMEL 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. + * + * \asf_license_stop + * + */ +#ifndef _delay_h_ +#define _delay_h_ + +#ifdef __cplusplus +extern "C" { +#endif + + +#include + +#if defined(UC3) +# include +#elif defined(XMEGA) +# include "xmega/cycle_counter.h" +#endif + + +/** + * @defgroup group_common_services_delay Busy-Wait Delay Routines + * + * This module provides simple loop-based delay routines for those + * applications requiring a brief wait during execution. Common API + * for UC3, XMEGA, and AVR MEGA. + * + * @{ + */ + +/** + * @def F_CPU + * @brief MCU Clock Frequency (Hertz) + * + * @deprecated + * The \ref F_CPU configuration constant is used for compatibility with the + * \ref group_common_services_delay routines. The common loop-based delay + * routines are designed to use the \ref clk_group modules while anticipating + * support for legacy applications assuming a statically defined clock + * frequency. Applications using a statically configured MCU clock frequency + * can define \ref F_CPU (Hertz), in which case the common delay routines will + * use this value rather than calling sysclk_get_cpu_hz() to get the current + * MCU clock frequency. + */ +#ifndef F_CPU +# define F_CPU sysclk_get_cpu_hz() +#endif + +/** + * @def delay_init + * + * @brief Initialize the delay driver. + * @param fcpu_hz CPU frequency in Hz + * + * @deprecated + * This function is provided for compatibility with ASF applications that + * may not have been updated to configure the system clock via the common + * clock service; e.g. sysclk_init() and a configuration header file are + * used to configure clocks. + * + * The functions in this module call \ref sysclk_get_cpu_hz() function to + * obtain the system clock frequency. + */ +#define delay_init(fcpu_hz) + +/** + * @def delay_s + * @brief Delay in seconds. + * @param delay Delay in seconds + */ +#define delay_s(delay) cpu_delay_ms(1000 * delay, F_CPU) + +/** + * @def delay_ms + * @brief Delay in milliseconds. + * @param delay Delay in milliseconds + */ +#define delay_ms(delay) cpu_delay_ms(delay, F_CPU) + +/** + * @def delay_us + * @brief Delay in microseconds. + * @param delay Delay in microseconds + */ +#define delay_us(delay) cpu_delay_us(delay, F_CPU) + + +#ifdef __cplusplus +} +#endif + +/** + * @} + */ + +#endif /* _delay_h_ */ diff --git a/DSTAT1/src/asf/common/services/delay/xmega/cycle_counter.h b/DSTAT1/src/asf/common/services/delay/xmega/cycle_counter.h new file mode 100644 index 0000000000000000000000000000000000000000..5bd54382a767356055b912f5618fce5dc5e7c496 --- /dev/null +++ b/DSTAT1/src/asf/common/services/delay/xmega/cycle_counter.h @@ -0,0 +1,111 @@ +/** + * \file + * + * \brief AVR functions for busy-wait delay loops + * + * Copyright (c) 2011 - 2012 Atmel Corporation. All rights reserved. + * + * \asf_license_start + * + * 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. The name of Atmel may not be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * 4. This software may only be redistributed and used in connection with an + * Atmel microcontroller product. + * + * THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE + * EXPRESSLY AND SPECIFICALLY DISCLAIMED. IN NO EVENT SHALL ATMEL 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. + * + * \asf_license_stop + * + */ +#ifndef _cycle_counter_h_ +#define _cycle_counter_h_ + +#ifdef __cplusplus +extern "C" { +#endif + + +#include + +/** + * @name Convenience functions for busy-wait delay loops + * + * @def delay_cycles + * @brief Delay program execution for a specified number of CPU cycles. + * @param n number of CPU cycles to wait + * + * @def cpu_delay_ms + * @brief Delay program execution for a specified number of milliseconds. + * @param delay number of milliseconds to wait + * @param f_cpu CPU frequency in Hertz + * + * @def cpu_delay_us + * @brief Delay program execution for a specified number of microseconds. + * @param delay number of microseconds to wait + * @param f_cpu CPU frequency in Hertz + * + * @def cpu_ms_2_cy + * @brief Convert milli-seconds into CPU cycles. + * @param ms number of milliseconds + * @param f_cpu CPU frequency in Hertz + * @return the converted number of CPU cycles + * + * @def cpu_us_2_cy + * @brief Convert micro-seconds into CPU cycles. + * @param ms number of microseconds + * @param f_cpu CPU frequency in Hertz + * @return the converted number of CPU cycles + * + * @{ + */ +__always_optimize +static inline void __portable_avr_delay_cycles(unsigned long n) +{ + do { barrier(); } while (--n); +} + +#if !defined(__DELAY_CYCLE_INTRINSICS__) +# define delay_cycles __portable_avr_delay_cycles +# define cpu_ms_2_cy(ms, f_cpu) (((uint64_t)(ms) * (f_cpu) + 999) / 6e3) +# define cpu_us_2_cy(us, f_cpu) (((uint64_t)(us) * (f_cpu) + 999999ul) / 6e6) +#else +# if defined(__GNUC__) +# define delay_cycles __builtin_avr_delay_cycles +# elif defined(__ICCAVR__) +# define delay_cycles __delay_cycles +# endif +# define cpu_ms_2_cy(ms, f_cpu) (((uint64_t)(ms) * (f_cpu) + 999) / 1e3) +# define cpu_us_2_cy(us, f_cpu) (((uint64_t)(us) * (f_cpu) + 999999ul) / 1e6) +#endif + +#define cpu_delay_ms(delay, f_cpu) delay_cycles(cpu_ms_2_cy(delay, f_cpu)) +#define cpu_delay_us(delay, f_cpu) delay_cycles(cpu_us_2_cy(delay, f_cpu)) +//! @} + + +#ifdef __cplusplus +} +#endif + +#endif /* _cycle_counter_h_ */ diff --git a/DSTAT1/src/asf/common/services/sleepmgr/sleepmgr.h b/DSTAT1/src/asf/common/services/sleepmgr/sleepmgr.h new file mode 100644 index 0000000000000000000000000000000000000000..90143570f2cedd9ea07eec3150b110836521ab45 --- /dev/null +++ b/DSTAT1/src/asf/common/services/sleepmgr/sleepmgr.h @@ -0,0 +1,235 @@ +/** + * \file + * + * \brief Sleep manager + * + * Copyright (c) 2010 Atmel Corporation. All rights reserved. + * + * \asf_license_start + * + * 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. The name of Atmel may not be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * 4. This software may only be redistributed and used in connection with an + * Atmel microcontroller product. + * + * THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE + * EXPRESSLY AND SPECIFICALLY DISCLAIMED. IN NO EVENT SHALL ATMEL 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. + * + * \asf_license_stop + * + */ +#ifndef SLEEPMGR_H +#define SLEEPMGR_H + +#include +#include +#include + +#if defined(XMEGA) +# include "xmega/sleepmgr.h" +#elif (defined(__GNUC__) && defined(__AVR32__)) || (defined(__ICCAVR32__) || defined(__AAVR32__)) +# include "uc3/sleepmgr.h" +#else +# error Unsupported device. +#endif + +/** + * \defgroup sleepmgr_group Sleep manager + * + * The sleep manager is a service for ensuring that the device is not put to + * sleep in deeper sleep modes than the system (e.g., peripheral drivers, + * services or the application) allows at any given time. + * + * It is based on the use of lock counting for the individual sleep modes, and + * will put the device to sleep in the shallowest sleep mode that has a non-zero + * lock count. The drivers/services/application can change these counts by use + * of \ref sleepmgr_lock_mode and \ref sleepmgr_unlock_mode. + * Refer to \ref sleepmgr_mode for a list of the sleep modes available for + * locking, and the device datasheet for information on their effect. + * + * The application must supply the file \ref conf_sleepmgr.h. + * + * For the sleep manager to be enabled, the symbol \ref CONFIG_SLEEPMGR_ENABLE + * must be defined, e.g., in \ref conf_sleepmgr.h. If this symbol is not + * defined, the functions are replaced with dummy functions and no RAM is used. + * + * @{ + */ + +/** + * \def CONFIG_SLEEPMGR_ENABLE + * \brief Configuration symbol for enabling the sleep manager + * + * If this symbol is not defined, the functions of this service are replaced + * with dummy functions. This is useful for reducing code size and execution + * time if the sleep manager is not needed in the application. + * + * This symbol may be defined in \ref conf_sleepmgr.h. + */ +#if defined(__DOXYGEN__) && !defined(CONFIG_SLEEPMGR_ENABLE) +# define CONFIG_SLEEPMGR_ENABLE +#endif + +/** + * \enum sleepmgr_mode + * \brief Sleep mode locks + * + * Identifiers for the different sleep mode locks. + */ + +/** + * \brief Initialize the lock counts + * + * Sets all lock counts to 0, except the very last one, which is set to 1. This + * is done to simplify the algorithm for finding the deepest allowable sleep + * mode in \ref sleepmgr_enter_sleep. + */ +static inline void sleepmgr_init(void) +{ +#ifdef CONFIG_SLEEPMGR_ENABLE + uint8_t i; + + for (i = 0; i < SLEEPMGR_NR_OF_MODES - 1; i++) { + sleepmgr_locks[i] = 0; + } + sleepmgr_locks[SLEEPMGR_NR_OF_MODES - 1] = 1; +#endif /* CONFIG_SLEEPMGR_ENABLE */ +} + +/** + * \brief Increase lock count for a sleep mode + * + * Increases the lock count for \a mode to ensure that the sleep manager does + * not put the device to sleep in the deeper sleep modes. + * + * \param mode Sleep mode to lock. + */ +static inline void sleepmgr_lock_mode(enum sleepmgr_mode mode) +{ +#ifdef CONFIG_SLEEPMGR_ENABLE + irqflags_t flags; + + Assert(sleepmgr_locks[mode] < 0xff); + + // Enter a critical section + flags = cpu_irq_save(); + + ++sleepmgr_locks[mode]; + + // Leave the critical section + cpu_irq_restore(flags); +#endif /* CONFIG_SLEEPMGR_ENABLE */ +} + +/** + * \brief Decrease lock count for a sleep mode + * + * Decreases the lock count for \a mode. If the lock count reaches 0, the sleep + * manager can put the device to sleep in the deeper sleep modes. + * + * \param mode Sleep mode to unlock. + */ +static inline void sleepmgr_unlock_mode(enum sleepmgr_mode mode) +{ +#ifdef CONFIG_SLEEPMGR_ENABLE + irqflags_t flags; + + Assert(sleepmgr_locks[mode]); + + // Enter a critical section + flags = cpu_irq_save(); + + --sleepmgr_locks[mode]; + + // Leave the critical section + cpu_irq_restore(flags); +#endif /* CONFIG_SLEEPMGR_ENABLE */ +} + + /** + * \brief Retrieves the deepest allowable sleep mode + * + * Searches through the sleep mode lock counts, starting at the shallowest sleep + * mode, until the first non-zero lock count is found. The deepest allowable + * sleep mode is then returned. + */ +static inline enum sleepmgr_mode sleepmgr_get_sleep_mode(void) +{ + enum sleepmgr_mode sleep_mode = SLEEPMGR_ACTIVE; + +#ifdef CONFIG_SLEEPMGR_ENABLE + uint8_t *lock_ptr = sleepmgr_locks; + + // Find first non-zero lock count, starting with the shallowest modes. + while (!(*lock_ptr)) { + lock_ptr++; + sleep_mode++; + } + + // Catch the case where one too many sleepmgr_unlock_mode() call has been + // performed on the deepest sleep mode. + Assert((uintptr_t)(lock_ptr - sleepmgr_locks) < SLEEPMGR_NR_OF_MODES); + +#endif /* CONFIG_SLEEPMGR_ENABLE */ + + return sleep_mode; +} + +/** + * \fn sleepmgr_enter_sleep + * \brief Go to sleep in the deepest allowed mode + * + * Searches through the sleep mode lock counts, starting at the shallowest sleep + * mode, until the first non-zero lock count is found. The device is then put to + * sleep in the sleep mode that corresponds to the lock. + * + * \note This function enables interrupts before going to sleep, and will leave + * them enabled upon return. This also applies if sleep is skipped due to ACTIVE + * mode being locked. + */ + +static inline void sleepmgr_enter_sleep(void) +{ +#ifdef CONFIG_SLEEPMGR_ENABLE + enum sleepmgr_mode sleep_mode; + + cpu_irq_disable(); + + // Find the deepest allowable sleep mode + sleep_mode = sleepmgr_get_sleep_mode(); + // Return right away if first mode (ACTIVE) is locked. + if (sleep_mode==SLEEPMGR_ACTIVE) { + cpu_irq_enable(); + return; + } + // Enter the deepest allowable sleep mode with interrupts enabled + sleepmgr_sleep(sleep_mode); +#else + cpu_irq_enable(); +#endif /* CONFIG_SLEEPMGR_ENABLE */ +} + + +//! @} + +#endif /* SLEEPMGR_H */ diff --git a/DSTAT1/src/asf/common/services/sleepmgr/xmega/sleepmgr.c b/DSTAT1/src/asf/common/services/sleepmgr/xmega/sleepmgr.c new file mode 100644 index 0000000000000000000000000000000000000000..8e85c33762a5bc3c25fb9b83dcc96b95a050930f --- /dev/null +++ b/DSTAT1/src/asf/common/services/sleepmgr/xmega/sleepmgr.c @@ -0,0 +1,61 @@ +/** + * \file + * + * \brief Sleep manager + * + * Copyright (c) 2010 Atmel Corporation. All rights reserved. + * + * \asf_license_start + * + * 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. The name of Atmel may not be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * 4. This software may only be redistributed and used in connection with an + * Atmel microcontroller product. + * + * THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE + * EXPRESSLY AND SPECIFICALLY DISCLAIMED. IN NO EVENT SHALL ATMEL 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. + * + * \asf_license_stop + * + */ +#include +#include + +#if defined(CONFIG_SLEEPMGR_ENABLE) || defined(__DOXYGEN__) + +uint8_t sleepmgr_locks[SLEEPMGR_NR_OF_MODES]; + +# ifndef __DOXYGEN__ +PROGMEM_DECLARE(enum SLEEP_SMODE_enum, + sleepmgr_configs[SLEEPMGR_NR_OF_MODES]) = { +# else +enum SLEEP_SMODE_enum sleepmgr_configs[SLEEPMGR_NR_OF_MODES] = { +# endif + SLEEP_SMODE_IDLE_gc, + SLEEP_SMODE_ESTDBY_gc, + SLEEP_SMODE_PSAVE_gc, + SLEEP_SMODE_STDBY_gc, + SLEEP_SMODE_PDOWN_gc, +}; + +#endif /* CONFIG_SLEEPMGR_ENABLE */ diff --git a/DSTAT1/src/asf/common/services/sleepmgr/xmega/sleepmgr.h b/DSTAT1/src/asf/common/services/sleepmgr/xmega/sleepmgr.h new file mode 100644 index 0000000000000000000000000000000000000000..e94629b942070a781a3413045cbeb3a4c9b7b627 --- /dev/null +++ b/DSTAT1/src/asf/common/services/sleepmgr/xmega/sleepmgr.h @@ -0,0 +1,116 @@ +/** + * \file + * + * \brief AVR XMEGA Sleep manager implementation + * + * Copyright (c) 2010 Atmel Corporation. All rights reserved. + * + * \asf_license_start + * + * 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. The name of Atmel may not be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * 4. This software may only be redistributed and used in connection with an + * Atmel microcontroller product. + * + * THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE + * EXPRESSLY AND SPECIFICALLY DISCLAIMED. IN NO EVENT SHALL ATMEL 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. + * + * \asf_license_stop + * + */ +#ifndef XMEGA_SLEEPMGR_H +#define XMEGA_SLEEPMGR_H + +#ifdef __cplusplus +extern "C" { +#endif + +#include +#include +#include + +/** + * \weakgroup sleepmgr_group + * @{ + */ + +enum sleepmgr_mode { + //! Active mode. + SLEEPMGR_ACTIVE = 0, + //! Idle mode. + SLEEPMGR_IDLE, + //! Extended Standby mode. + SLEEPMGR_ESTDBY, + //! Power Save mode. + SLEEPMGR_PSAVE, + //! Standby mode. + SLEEPMGR_STDBY, + //! Power Down mode. + SLEEPMGR_PDOWN, + SLEEPMGR_NR_OF_MODES, +}; + +/** + * \internal + * \name Internal arrays + * @{ + */ +#if defined(CONFIG_SLEEPMGR_ENABLE) || defined(__DOXYGEN__) +//! Sleep mode lock counters +extern uint8_t sleepmgr_locks[]; +# ifndef __DOXYGEN__ +PROGMEM_DECLARE(extern enum SLEEP_SMODE_enum, sleepmgr_configs[]); +# else +/** + * \brief Look-up table with sleep mode configurations + * \note This is located in program memory (Flash) as it is constant. + */ +extern enum SLEEP_SMODE_enum sleepmgr_configs[]; +# endif /* __DOXYGEN__ */ +#endif /* CONFIG_SLEEPMGR_ENABLE */ +//! @} + +static inline void sleepmgr_sleep(const enum sleepmgr_mode sleep_mode) +{ + Assert(sleep_mode != SLEEPMGR_ACTIVE); +#ifdef CONFIG_SLEEPMGR_ENABLE + sleep_set_mode(PROGMEM_READ_BYTE(&sleepmgr_configs[sleep_mode-1])); + sleep_enable(); + + cpu_irq_enable(); + sleep_enter(); + + sleep_disable(); +#else + cpu_irq_enable(); +#endif /* CONFIG_SLEEPMGR_ENABLE */ + +} + +//! @} + +#ifdef __cplusplus +} +#endif + +#endif /* XMEGA_SLEEPMGR_H */ diff --git a/DSTAT1/src/asf/common/services/spi/spi_master.h b/DSTAT1/src/asf/common/services/spi/spi_master.h new file mode 100644 index 0000000000000000000000000000000000000000..bf089d70297dd07fe40da29d3a4ade50ced27d17 --- /dev/null +++ b/DSTAT1/src/asf/common/services/spi/spi_master.h @@ -0,0 +1,266 @@ +/** + * \file + * + * \brief SPI Master Mode management + * + * Copyright (c) 2010 Atmel Corporation. All rights reserved. + * + * \asf_license_start + * + * 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. The name of Atmel may not be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * 4. This software may only be redistributed and used in connection with an + * Atmel microcontroller product. + * + * THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE + * EXPRESSLY AND SPECIFICALLY DISCLAIMED. IN NO EVENT SHALL ATMEL 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. + * + * \asf_license_stop + * + */ +#ifndef SPI_MASTER_H_INCLUDED +#define SPI_MASTER_H_INCLUDED + +#include + +#if XMEGA +# include "xmega_spi/spi_master.h" +#elif (defined(__GNUC__) && defined(__AVR32__)) || (defined(__ICCAVR32__) || defined(__AAVR32__)) +# include "uc3_spi/spi_master.h" +#elif SAM +# include "sam_spi/spi_master.h" +#else +# error Unsupported chip type +#endif + +/** + * + * \defgroup spi_group Serial Peripheral Interface (SPI) + * + * This is the common API for SPI interface. Additional features are available + * in the documentation of the specific modules. + * + * \section spi_group_platform Platform Dependencies + * + * The SPI API is partially chip- or platform-specific. While all + * platforms provide mostly the same functionality, there are some + * variations around how different bus types and clock tree structures + * are handled. + * + * The following functions are available on all platforms, but there may + * be variations in the function signature (i.e. parameters) and + * behavior. These functions are typically called by platform-specific + * parts of drivers, and applications that aren't intended to be + * portable: + * - spi_master_init() + * - spi_master_setup_device() + * - spi_select_device() + * - spi_deselect_device() + * - spi_write_single() + * - spi_write_packet() + * - spi_read_single() + * - spi_read_packet() + * - spi_is_tx_empty() + * - spi_is_tx_ready() + * - spi_is_rx_full() + * - spi_is_rx_ready() + * - spi_enable() + * - spi_disable() + * - spi_is_enabled() + * + * \section spi_master_qucikstart_section Quick Start Guide + * See \ref spi_master_quickstart + * @{ + */ + +//! @} + +/** + * \page spi_master_quickstart Quick Start Guide for the SPI Master Driver + * + * This is the quick start guide for the \ref spi_group "SPI Driver", with + * step-by-step instructions on how to configure and use the driver for a + * specific use case. + * + * The use case contain several code fragments. The code fragments in the + * steps for setup can be copied into a custom initialization function, while + * the steps for usage can be copied into, e.g., the main application function. + * + * The steps for setting up the SPI master for XMEGA and UC3 use exactly the + * same approach, but note that there are different names on the peripherals. So + * to use this Quick Start for UC3 please make sure that all the peripheral + * names are updated according to the UC3 datasheet. + * - \subpage spi_master_xmega + * + */ +/** + * \page spi_master_xmega Basic setup for SPI master on XMEGA devices + * + * \section spi_master_xmega_basic Basic setup for XMEGA devices + * The SPI module will be set up as master: + * - SPI on PORTD + * - 1MHz SPI clock speed + * - Slave Chip Select connected on PORTD pin 1 + * - SPI mode 0 (data on rising clock edge) + * + * \section spi_master_xmega_basic_setup Setup steps + * \subsection spi_master_xmega_basic_setup_code Example code + * Add to application C-file (e.g. main.c): + * \code + * void spi_init_pins(void) + * { + * ioport_configure_port_pin(&PORTD, PIN1_bm, IOPORT_INIT_HIGH | IOPORT_DIR_OUTPUT); + * + * ioport_configure_port_pin(&PORTD, PIN4_bm, IOPORT_PULL_UP | IOPORT_DIR_INPUT); + * ioport_configure_port_pin(&PORTD, PIN5_bm, IOPORT_INIT_HIGH | IOPORT_DIR_OUTPUT); + * ioport_configure_port_pin(&PORTD, PIN6_bm, IOPORT_DIR_INPUT); + * ioport_configure_port_pin(&PORTD, PIN7_bm, IOPORT_INIT_HIGH | IOPORT_DIR_OUTPUT); + * } + * + * void spi_init_module(void) + * { + * struct spi_device spi_device_conf = { + * .id = IOPORT_CREATE_PIN(PORTD, 1) + * }; + * + * spi_master_init(&SPID); + * spi_master_setup_device(&SPID, &spi_device_conf, SPI_MODE_0, 1000000, 0); + * spi_enable(&SPID); + * } + * \endcode + * + * \subsection spi_master_xmega_basic_setup Workflow + * -# Ensure that \ref conf_spi_master.h is present for the driver. + * - \note This file is only for the driver and should not be included by the + * user. In this example the file can be left empty. + * -# Initialize the pins used by the SPI interface (this initialization is for + * the ATxmega32A4U device). + * -# Set the pin used for slave select as output high: + * \code + * ioport_configure_port_pin(&PORTD, PIN1_bm, IOPORT_INIT_HIGH | IOPORT_DIR_OUTPUT); + * \endcode + * -# Enable pull-up on own chip select (SS): + * \code + * ioport_configure_port_pin(&PORTD, PIN4_bm, IOPORT_PULL_UP | IOPORT_DIR_INPUT); + * \endcode + * \attention If this pin is pulled low the SPI module will go into slave mode. + * -# Set MOSI and SCL as output high, and set MISO as input: + * \code + * ioport_configure_port_pin(&PORTD, PIN5_bm, IOPORT_INIT_HIGH | IOPORT_DIR_OUTPUT); + * ioport_configure_port_pin(&PORTD, PIN6_bm, IOPORT_DIR_INPUT); + * ioport_configure_port_pin(&PORTD, PIN7_bm, IOPORT_INIT_HIGH | IOPORT_DIR_OUTPUT); + * \endcode + * -# Define the SPI device configuration struct to describe which pin the + * slave select (slave chip select) is connected to, in this case the slave + * select pin has been connected to PORTD pin 1 (PD1): + * - \code + * struct spi_device spi_device_conf = { + * .id = IOPORT_CREATE_PIN(PORTD, 1) + * }; + * \endcode + * -# Initialize the SPI module, in this case SPI on PORTD has been chosen: + * - \code + * spi_master_init(&SPID); + * \endcode + * -# Setup the SPI master module for a specific device: + * - \code + * spi_master_setup_device(&SPID, &spi_device_conf, SPI_MODE_0, 1000000, 0); + * \endcode + * - \note The last argument, which is zero in this case, can be ignored and is + * only included for compability purposes. + * -# Then enable the SPI: + * - \code + * spi_enable(&SPID); + * \endcode + * + * \section spi_master_xmega_basic_usage Usage steps + * \subsection spi_master_xmega_basic_usage_code Example code + * Add to, e.g., the main loop in the application C-file: + * \code + * uint8_t data_buffer[1] = {0xAA}; + * + * struct spi_device spi_device_conf = { + * .id = IOPORT_CREATE_PIN(PORTD, 1) + * }; + * + * spi_select_device(&SPID, &spi_device_conf); + * + * spi_write_packet(&SPID, data_buffer, 1); + * spi_read_packet(&SPID, data_buffer, 1); + * + * spi_deselect_device(&SPID, &spi_device_conf); + * \endcode + * + * \subsection spi_master_xmega_basic_usage_flow Workflow + * -# Create a buffer for data to be sent/received on the SPI bus, in this case + * a single byte buffer is used. The buffer can be of arbitrary size as long as + * there is space left in SRAM: + * - \code + * uint8_t data_buffer[1] = {0xAA}; + * \endcode + * -# Define the SPI device configuration struct to describe which pin the + * slave select (slave chip select) is connected to, in this case the slave + * select pin has been connected to PORTD pin 1 (PD1): + * - \code + * struct spi_device spi_device_conf = { + * .id = IOPORT_CREATE_PIN(PORTD, 1) + * }; + * \endcode + * - \note As this struct is the same for both the initializing part and the usage + * part it could be a good idea to make the struct global, and hence accessible + * for both the initializing part and usage part. Another solution could be to + * create the struct in the main function and pass the address of the struct to + * the spi_init_module() function, e.g.: + * \code + * void spi_init_module(struct spi_device *spi_device_conf) + * { + * ... + * + * spi_master_setup_device(&SPID, spi_device_conf, SPI_MODE_0, 1000000, 0); + * + * ... + * } + * \endcode + * -# Write data to the SPI slave device, in this case write one byte from the + * data_buffer: + * - \code + * spi_write_packet(&SPID, data_buffer, 1); + * \endcode + * -# Read data from the SPI slave device, in this case read one byte and put it + * into the data_buffer: + * - \code + * spi_read_packet(&SPID, data_buffer, 1); + * \endcode + * - \attention As the SPI works as a shift register so that data is shifted in at + * the same time as data is shifted out a read operation will mean that a dummy + * byte \ref CONFIG_SPI_MASTER_DUMMY is written to the SPI bus. \ref CONFIG_SPI_MASTER_DUMMY + * defaults to 0xFF, but can be changed by defining it inside the \ref conf_spi_master.h + * file. + * -# When read and write operations is done de-select the slave: + * - \code + * spi_deselect_device(&SPID, &spi_device_conf); + * \endcode + * + */ + +#endif /* SPI_MASTER_H_INCLUDED */ diff --git a/DSTAT1/src/asf/common/services/spi/xmega_spi/spi_master.c b/DSTAT1/src/asf/common/services/spi/xmega_spi/spi_master.c new file mode 100644 index 0000000000000000000000000000000000000000..a690a222662ac095a374041b6e15d7c22446781a --- /dev/null +++ b/DSTAT1/src/asf/common/services/spi/xmega_spi/spi_master.c @@ -0,0 +1,187 @@ +/***************************************************************************** + * + * \file + * + * \brief SPI software driver functions. + * + * Copyright (c) 2010 Atmel Corporation. All rights reserved. + * + * \asf_license_start + * + * 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. The name of Atmel may not be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * 4. This software may only be redistributed and used in connection with an + * Atmel microcontroller product. + * + * THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE + * EXPRESSLY AND SPECIFICALLY DISCLAIMED. IN NO EVENT SHALL ATMEL 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. + * + * \asf_license_stop + * + *****************************************************************************/ + +#include "spi_master.h" +#include "sysclk.h" + + +/*! \brief Initializes the SPI in master mode. + * + * \param spi Base address of the SPI instance. + * + */ +void spi_master_init(SPI_t *spi) +{ +#ifdef SPIA + if((uint16_t)spi == (uint16_t)&SPIA) { + sysclk_enable_module(SYSCLK_PORT_A,PR_SPI_bm); + } + +#endif +#ifdef SPIB + if((uint16_t)spi == (uint16_t)&SPIB) { + sysclk_enable_module(SYSCLK_PORT_B,PR_SPI_bm); + } +#endif +#ifdef SPIC + if((uint16_t)spi == (uint16_t)&SPIC) { + sysclk_enable_module(SYSCLK_PORT_C,PR_SPI_bm); + } +#endif +#ifdef SPID + if((uint16_t)spi == (uint16_t)&SPID) { + sysclk_enable_module(SYSCLK_PORT_D,PR_SPI_bm); + } +#endif +#ifdef SPIE + if((uint16_t)spi == (uint16_t)&SPIE) { + sysclk_enable_module(SYSCLK_PORT_E,PR_SPI_bm); + } +#endif +#ifdef SPIF + if((uint16_t)spi == (uint16_t)&SPIF) { + sysclk_enable_module(SYSCLK_PORT_F,PR_SPI_bm); + } +#endif + spi_enable_master_mode(spi); +} + +/** + * \brief Setup a SPI device. + * + * The returned device descriptor structure must be passed to the driver + * whenever that device should be used as current slave device. + * + * \param spi Base address of the SPI instance. + * \param device Pointer to SPI device struct that should be initialized. + * \param flags SPI configuration flags. Common flags for all + * implementations are the SPI modes SPI_MODE_0 ... + * SPI_MODE_3. + * \param baud_rate Baud rate for communication with slave device in Hz. + * \param sel_id Board specific seclet id + */ +void spi_master_setup_device(SPI_t *spi, struct spi_device *device, + spi_flags_t flags, uint32_t baud_rate, + board_spi_select_id_t sel_id) +{ + if(spi_xmega_set_baud_div(spi, baud_rate,sysclk_get_cpu_hz())<0) + { + //TODO Assert impossible baudrate + } + spi->CTRL|=(flags<id); +} + +/** + * \brief Deselect given device on the SPI bus + * + * Calls board chip deselect. + * + * \param spi Base address of the SPI instance. + * \param device SPI device + * + * \pre SPI device must be selected with spi_select_device() first + */ +void spi_deselect_device(SPI_t *spi, struct spi_device *device) +{ + ioport_set_pin_high(device->id); +} diff --git a/DSTAT1/src/asf/common/services/spi/xmega_spi/spi_master.h b/DSTAT1/src/asf/common/services/spi/xmega_spi/spi_master.h new file mode 100644 index 0000000000000000000000000000000000000000..a55a19e41e1d3d9379c8c44864243dbdcf3ad10a --- /dev/null +++ b/DSTAT1/src/asf/common/services/spi/xmega_spi/spi_master.h @@ -0,0 +1,257 @@ +/***************************************************************************** + * + * \file + * + * \brief SPI Master driver for AVR. + * + * This file defines a useful set of functions for the SPI interface on AVR + * devices. + * + * Copyright (c) 2009 Atmel Corporation. All rights reserved. + * + * \asf_license_start + * + * 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. The name of Atmel may not be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * 4. This software may only be redistributed and used in connection with an + * Atmel microcontroller product. + * + * THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE + * EXPRESSLY AND SPECIFICALLY DISCLAIMED. IN NO EVENT SHALL ATMEL 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. + * + * \asf_license_stop + * + ******************************************************************************/ + + +#ifndef _SPI_MASTER_H_ +#define _SPI_MASTER_H_ + +#include "compiler.h" +#include "status_codes.h" +#include "ioport.h" +#include "spi.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * \defgroup xmega_spi_master_group XMEGA SPI master service. + * + * This is the API for SPI master service on XMEGA. + * + * @{ + * + * \section xmega_spi_master_qucikstart_section Quick Start Guide + * See \ref spi_master_quickstart + */ + +/*! \name Spi Master Management Configuration + */ +//! @{ +#include "conf_spi_master.h" + +//! Default Config Spi Master Dummy Field +#ifndef CONFIG_SPI_MASTER_DUMMY +#define CONFIG_SPI_MASTER_DUMMY 0xFF +#endif +//! @} + +/** + * \brief Clock phase + */ +#define SPI_CPHA (1 << 0) + +/** + * \brief Clock polarity + */ +#define SPI_CPOL (1 << 1) + +/** + * \brief SPI mode 0 + */ +#define SPI_MODE_0 0 +/** + * \brief SPI mode 1 + */ +#define SPI_MODE_1 (SPI_CPHA) +/** + * \brief SPI mode 2 + */ +#define SPI_MODE_2 (SPI_CPOL) +/** + * \brief SPI mode 3 + */ +#define SPI_MODE_3 (SPI_CPOL | SPI_CPHA) + +typedef uint8_t spi_flags_t; +typedef uint32_t board_spi_select_id_t; + +//! \brief Polled SPI device defintion +struct spi_device { + //! Board specific select id + port_pin_t id; +}; + +/*! \brief Initializes the SPI in master mode. + * + * \param spi Base address of the SPI instance. + * + */ +extern void spi_master_init(SPI_t *spi); + +/** + * \brief Setup a SPI device. + * + * The returned device descriptor structure must be passed to the driver + * whenever that device should be used as current slave device. + * + * \param spi Base address of the SPI instance. + * \param device Pointer to SPI device struct that should be initialized. + * \param flags SPI configuration flags. Common flags for all + * implementations are the SPI modes SPI_MODE_0 ... + * SPI_MODE_3. + * \param baud_rate Baud rate for communication with slave device in Hz. + * \param sel_id Board specific seclet id + */ +extern void spi_master_setup_device(SPI_t *spi, struct spi_device *device, + spi_flags_t flags, unsigned long baud_rate, + board_spi_select_id_t sel_id); + +/*! \brief Enables the SPI. + * + * \param spi Base address of the SPI instance. + */ +extern void spi_enable(SPI_t *spi); + +/*! \brief Disables the SPI. + * + * Ensures that nothing is transferred while setting up buffers. + * + * \param spi Base address of the SPI instance. + * + * \warning This may cause data loss if used on a slave SPI. + */ +extern void spi_disable(SPI_t *spi); + + +/*! \brief Tests if the SPI is enabled. + * + * \param spi Base address of the SPI instance. + * + * \return \c 1 if the SPI is enabled, otherwise \c 0. + */ +extern bool spi_is_enabled(SPI_t *spi); + +/** + * \brief Select given device on the SPI bus + * + * Set device specific setting and calls board chip select. + * + * \param spi Base address of the SPI instance. + * \param device SPI device + * + */ +extern void spi_select_device(SPI_t *spi, struct spi_device *device); + +/** + * \brief Deselect given device on the SPI bus + * + * Calls board chip deselect. + * + * \param spi Base address of the SPI instance. + * \param device SPI device + * + * \pre SPI device must be selected with spi_select_device() first + */ +extern void spi_deselect_device(SPI_t *spi, struct spi_device *device); + +/*! \brief Write one byte to a SPI device. + * + * \param spi Base address of the SPI instance. + * \param data The data byte to be loaded + * + */ +__always_inline static inline void spi_write_single(SPI_t *spi, uint8_t data) +{ + spi_put(spi,data); +} + +/** + * \brief Send a sequence of bytes to a SPI device + * + * Received bytes on the SPI bus are discarded. + * + * \param spi Base address of the SPI instance. + * \param data data buffer to write + * \param len Length of data + * + * \pre SPI device must be selected with spi_select_device() first + */ +extern status_code_t spi_write_packet(SPI_t *spi,const uint8_t *data, size_t len); + + +/*! \brief Receive one byte from a SPI device. + * + * \param spi Base address of the SPI instance. + * \param data Pointer to the data byte where to store the received data. + * + */ +inline static void spi_read_single(SPI_t *spi, uint8_t *data) +{ + *data=spi_get(spi); +} + +/** + * \brief Receive a sequence of bytes from a SPI device + * + * All bytes sent out on SPI bus are sent as value 0. + * + * \param spi Base address of the SPI instance. + * \param data data buffer to read + * \param len Length of data + * + * \pre SPI device must be selected with spi_select_device() first + */ +extern status_code_t spi_read_packet(SPI_t *spi, uint8_t *data, size_t len); + +/*! \brief Tests if the SPI contains a received character. + * + * \param spi Base address of the SPI instance. + * + * \return \c 1 if the SPI Receive Holding Register is full, otherwise \c 0. + */ +inline static bool spi_is_rx_full(SPI_t *spi) +{ + return spi_is_tx_ok(spi); +} + +//! @} + + + +#ifdef __cplusplus +} +#endif +#endif // _SPI_MASTER_H_ diff --git a/DSTAT1/src/asf/common/services/usb/class/cdc/device/udi_cdc.c b/DSTAT1/src/asf/common/services/usb/class/cdc/device/udi_cdc.c new file mode 100644 index 0000000000000000000000000000000000000000..effbf1bb0025d381f60c4934093bf9ce85bd4fc9 --- /dev/null +++ b/DSTAT1/src/asf/common/services/usb/class/cdc/device/udi_cdc.c @@ -0,0 +1,1232 @@ +/** + * \file + * + * \brief USB Device Communication Device Class (CDC) interface. + * + * Copyright (c) 2009-2011 Atmel Corporation. All rights reserved. + * + * \asf_license_start + * + * 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. The name of Atmel may not be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * 4. This software may only be redistributed and used in connection with an + * Atmel microcontroller product. + * + * THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE + * EXPRESSLY AND SPECIFICALLY DISCLAIMED. IN NO EVENT SHALL ATMEL 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. + * + * \asf_license_stop + * + */ + +#include "conf_usb.h" +#include "usb_protocol.h" +#include "usb_protocol_cdc.h" +#include "udd.h" +#include "udc.h" +#include "udi_cdc.h" +#include + +#ifdef UDI_CDC_LOW_RATE +# define UDI_CDC_TX_BUFFERS (1*UDI_CDC_DATA_EPS_SIZE) +# define UDI_CDC_RX_BUFFERS (1*UDI_CDC_DATA_EPS_SIZE) +#else +# ifdef USB_DEVICE_HS_SUPPORT +# define UDI_CDC_TX_BUFFERS (8*UDI_CDC_DATA_EPS_SIZE) +# define UDI_CDC_RX_BUFFERS (8*UDI_CDC_DATA_EPS_SIZE) +# else +# define UDI_CDC_TX_BUFFERS (5*UDI_CDC_DATA_EPS_SIZE) +# define UDI_CDC_RX_BUFFERS (5*UDI_CDC_DATA_EPS_SIZE) +# endif +#endif + +#if UDI_CDC_PORT_NB == 1 +# define PORT 0 +#else +# define PORT port +#endif + +/** + * \addtogroup udi_cdc_group + * + * @{ + */ + +/** + * \name Interface for UDC + */ +//@{ + +bool udi_cdc_comm_enable(void); +void udi_cdc_comm_disable(void); +bool udi_cdc_comm_setup(void); +bool udi_cdc_data_enable(void); +void udi_cdc_data_disable(void); +bool udi_cdc_data_setup(void); +uint8_t udi_cdc_getsetting(void); +void udi_cdc_data_sof_notify(void); +UDC_DESC_STORAGE udi_api_t udi_api_cdc_comm = { + .enable = udi_cdc_comm_enable, + .disable = udi_cdc_comm_disable, + .setup = udi_cdc_comm_setup, + .getsetting = udi_cdc_getsetting, +}; +UDC_DESC_STORAGE udi_api_t udi_api_cdc_data = { + .enable = udi_cdc_data_enable, + .disable = udi_cdc_data_disable, + .setup = udi_cdc_data_setup, + .getsetting = udi_cdc_getsetting, + .sof_notify = udi_cdc_data_sof_notify, +}; + +#if UDI_CDC_PORT_NB > 1 +bool udi_cdc_comm_enable_2(void); +void udi_cdc_comm_disable_2(void); +bool udi_cdc_comm_setup_2(void); +bool udi_cdc_data_enable_2(void); +void udi_cdc_data_sof_notify_2(void); +UDC_DESC_STORAGE udi_api_t udi_api_cdc_comm_2 = { + .enable = udi_cdc_comm_enable_2, + .disable = udi_cdc_comm_disable_2, + .setup = udi_cdc_comm_setup_2, + .getsetting = udi_cdc_getsetting, +}; +UDC_DESC_STORAGE udi_api_t udi_api_cdc_data_2 = { + .enable = udi_cdc_data_enable_2, + .disable = udi_cdc_data_disable, + .setup = udi_cdc_data_setup, + .getsetting = udi_cdc_getsetting, + .sof_notify = udi_cdc_data_sof_notify_2, +}; +#endif + +#if UDI_CDC_PORT_NB > 2 +bool udi_cdc_comm_enable_3(void); +void udi_cdc_comm_disable_3(void); +bool udi_cdc_comm_setup_3(void); +bool udi_cdc_data_enable_3(void); +void udi_cdc_data_sof_notify_3(void); +UDC_DESC_STORAGE udi_api_t udi_api_cdc_comm_3 = { + .enable = udi_cdc_comm_enable_3, + .disable = udi_cdc_comm_disable_3, + .setup = udi_cdc_comm_setup_3, + .getsetting = udi_cdc_getsetting, +}; +UDC_DESC_STORAGE udi_api_t udi_api_cdc_data_3 = { + .enable = udi_cdc_data_enable_3, + .disable = udi_cdc_data_disable, + .setup = udi_cdc_data_setup, + .getsetting = udi_cdc_getsetting, + .sof_notify = udi_cdc_data_sof_notify_3, +}; +#endif +//@} + + +/** + * \name Internal routines + */ +//@{ + +/** + * \name Routines to control serial line + */ +//@{ + +/** + * \brief Sends line coding port 1 to application + * + * Called after SETUP request when line coding data is received. + */ +static void udi_cdc_line_coding_received(void); +#if UDI_CDC_PORT_NB > 1 +/** + * \brief Sends line coding port 2 to application + * + * Called after SETUP request when line coding data is received. + */ +static void udi_cdc_line_coding_received_2(void); +#endif +#if UDI_CDC_PORT_NB > 2 +/** + * \brief Sends line coding port 3 to application + * + * Called after SETUP request when line coding data is received. + */ +static void udi_cdc_line_coding_received_3(void); +#endif +/** + * \brief Sends line coding port to application + * + * Called after SETUP request when line coding data is received. + * + * \param port Communication port number to manage + */ +static void udi_cdc_line_coding_received_common(uint8_t port); + +/** + * \brief Records new state + * + * \param port Communication port number to manage + * \param b_set State is enabled if true, else disabled + * \param bit_mask Field to process (see CDC_SERIAL_STATE_ defines) + */ +static void udi_cdc_ctrl_state_change(uint8_t port, bool b_set, le16_t bit_mask); + +/** + * \brief Check and eventually notify the USB host of new state + * + * \param port Communication port number to manage + */ +static void udi_cdc_ctrl_state_notify(uint8_t port); + +/** + * \brief Ack sent of serial state message on port 1 + * Callback called after serial state message sent + * + * \param status UDD_EP_TRANSFER_OK, if transfer finished + * \param status UDD_EP_TRANSFER_ABORT, if transfer aborted + * \param n number of data transfered + */ +static void udi_cdc_serial_state_msg_sent(udd_ep_status_t status, iram_size_t n); +#if UDI_CDC_PORT_NB > 1 +/** + * \brief Ack sent of serial state message on port 2 + * Callback called after serial state message sent + * + * \param status UDD_EP_TRANSFER_OK, if transfer finished + * \param status UDD_EP_TRANSFER_ABORT, if transfer aborted + * \param n number of data transfered + */ +static void udi_cdc_serial_state_msg_sent_2(udd_ep_status_t status, iram_size_t n); +#endif +#if UDI_CDC_PORT_NB > 2 +/** + * \brief Ack sent of serial state message on port 3 + * Callback called after serial state message sent + * + * \param status UDD_EP_TRANSFER_OK, if transfer finished + * \param status UDD_EP_TRANSFER_ABORT, if transfer aborted + * \param n number of data transfered + */ +static void udi_cdc_serial_state_msg_sent_3(udd_ep_status_t status, iram_size_t n); +#endif +/** + * \brief Ack sent of serial state message on a port + * Callback called after serial state message sent + * + * \param port Communication port number to manage + * \param status UDD_EP_TRANSFER_OK, if transfer finished + * \param status UDD_EP_TRANSFER_ABORT, if transfer aborted + * \param n number of data transfered + */ +static void udi_cdc_serial_state_msg_sent_common(uint8_t port, udd_ep_status_t status, iram_size_t n); + +//@} + +/** + * \name Routines to process data transfer + */ +//@{ + +/** + * \brief Enable the reception of data from the USB host + * + * The value udi_cdc_rx_trans_sel indicate the RX buffer to fill. + * + * \param port Communication port number to manage + * + * \return \c 1 if function was successfully done, otherwise \c 0. + */ +static bool udi_cdc_rx_start(uint8_t port); + +/** + * \brief Update rx buffer management with a new data for port 1 + * Callback called after data reception on USB line + * + * \param status UDD_EP_TRANSFER_OK, if transfer finish + * \param status UDD_EP_TRANSFER_ABORT, if transfer aborted + * \param n number of data received + */ +static void udi_cdc_data_received(udd_ep_status_t status, iram_size_t n); +#if UDI_CDC_PORT_NB > 1 +/** + * \brief Update rx buffer management with a new data for port 2 + * Callback called after data reception on USB line + * + * \param status UDD_EP_TRANSFER_OK, if transfer finish + * \param status UDD_EP_TRANSFER_ABORT, if transfer aborted + * \param n number of data received + */ +static void udi_cdc_data_received_2(udd_ep_status_t status, iram_size_t n); +#endif +#if UDI_CDC_PORT_NB > 2 +/** + * \brief Update rx buffer management with a new data for port 3 + * Callback called after data reception on USB line + * + * \param status UDD_EP_TRANSFER_OK, if transfer finish + * \param status UDD_EP_TRANSFER_ABORT, if transfer aborted + * \param n number of data received + */ +static void udi_cdc_data_received_3(udd_ep_status_t status, iram_size_t n); +#endif + +/** + * \brief Update rx buffer management with a new data for a port + * Callback called after data reception on USB line + * + * \param port Communication port number to manage + * \param status UDD_EP_TRANSFER_OK, if transfer finish + * \param status UDD_EP_TRANSFER_ABORT, if transfer aborted + * \param n number of data received + */ +static void udi_cdc_data_received_common(uint8_t port, udd_ep_status_t status, iram_size_t n); + +/** + * \brief Ack sent of tx buffer on port 1 + * Callback called after data transfer on USB line + * + * \param status UDD_EP_TRANSFER_OK, if transfer finished + * \param status UDD_EP_TRANSFER_ABORT, if transfer aborted + * \param n number of data transfered + */ +static void udi_cdc_data_sent(udd_ep_status_t status, iram_size_t n); +#if UDI_CDC_PORT_NB > 1 +/** + * \brief Ack sent of tx buffer on port 2 + * Callback called after data transfer on USB line + * + * \param status UDD_EP_TRANSFER_OK, if transfer finished + * \param status UDD_EP_TRANSFER_ABORT, if transfer aborted + * \param n number of data transfered + */ +static void udi_cdc_data_sent_2(udd_ep_status_t status, iram_size_t n); +#endif +#if UDI_CDC_PORT_NB > 2 +/** + * \brief Ack sent of tx buffer on port 3 + * Callback called after data transfer on USB line + * + * \param status UDD_EP_TRANSFER_OK, if transfer finished + * \param status UDD_EP_TRANSFER_ABORT, if transfer aborted + * \param n number of data transfered + */ +static void udi_cdc_data_sent_3(udd_ep_status_t status, iram_size_t n); +#endif + +/** + * \brief Ack sent of tx buffer on a port + * Callback called after data transfer on USB line + * + * \param port Communication port number to manage + * \param status UDD_EP_TRANSFER_OK, if transfer finished + * \param status UDD_EP_TRANSFER_ABORT, if transfer aborted + * \param n number of data transfered + */ +static void udi_cdc_data_sent_common(uint8_t port, udd_ep_status_t status, iram_size_t n); + +/** + * \brief Send buffer on line or wait a SOF event + * + * \param port Communication port number to manage + */ +static void udi_cdc_tx_send(uint8_t port); + +#if UDI_CDC_PORT_NB == 1 +bool udi_cdc_multi_is_rx_ready(uint8_t port); +#endif + +//@} + +//@} + +/** + * \name Information about configuration of communication line + */ +//@{ +static usb_cdc_line_coding_t udi_cdc_line_coding[UDI_CDC_PORT_NB]; +static bool udi_cdc_serial_state_msg_ongoing[UDI_CDC_PORT_NB]; +static volatile le16_t udi_cdc_state[UDI_CDC_PORT_NB]; +COMPILER_WORD_ALIGNED static usb_cdc_notify_serial_state_t uid_cdc_state_msg[UDI_CDC_PORT_NB]; +static const uint8_t UDI_CDC_COMM_EPS[]={ + UDI_CDC_COMM_EP, +#if UDI_CDC_PORT_NB > 1 + UDI_CDC_COMM_EP_2, +#endif +#if UDI_CDC_PORT_NB > 2 + UDI_CDC_COMM_EP_3, +#endif +}; +static const udd_callback_trans_t udi_cdc_serial_state_msg_sents[] = { + udi_cdc_serial_state_msg_sent, +#if UDI_CDC_PORT_NB > 1 + udi_cdc_serial_state_msg_sent_2, +#endif +#if UDI_CDC_PORT_NB > 2 + udi_cdc_serial_state_msg_sent_3, +#endif +}; +typedef void (*udi_cdc_callback_setup_t) (void); +static udi_cdc_callback_setup_t udi_cdc_line_coding_receiveds[] = { + udi_cdc_line_coding_received, +#if UDI_CDC_PORT_NB > 1 + udi_cdc_line_coding_received_2, +#endif +#if UDI_CDC_PORT_NB > 2 + udi_cdc_line_coding_receivedt_3, +#endif +}; + +//! Status of CDC interface +static volatile bool udi_cdc_running[UDI_CDC_PORT_NB]; +//@} + +/** + * \name Variables to manage RX/TX transfer requests + * Two buffers for each sense are used to optimize the speed. + */ +//@{ + +//! Buffer to receive data +COMPILER_WORD_ALIGNED static uint8_t udi_cdc_rx_buf[UDI_CDC_PORT_NB][2][UDI_CDC_RX_BUFFERS]; +//! Data available in RX buffers +static uint16_t udi_cdc_rx_buf_nb[UDI_CDC_PORT_NB][2]; +//! Give the current RX buffer used (rx0 if 0, rx1 if 1) +static volatile uint8_t udi_cdc_rx_buf_sel[UDI_CDC_PORT_NB]; +//! Read position in current RX buffer +static volatile uint16_t udi_cdc_rx_pos[UDI_CDC_PORT_NB]; +//! Signal a transfer on-going +static volatile bool udi_cdc_rx_trans_ongoing[UDI_CDC_PORT_NB]; +static const uint8_t UDI_CDC_DATA_EP_OUTS[]={ + UDI_CDC_DATA_EP_OUT, +#if UDI_CDC_PORT_NB > 1 + UDI_CDC_DATA_EP_OUT_2, +#endif +#if UDI_CDC_PORT_NB > 2 + UDI_CDC_DATA_EP_OUT_3, +#endif +}; +static const udd_callback_trans_t udi_cdc_data_received_callbacks[] = { + udi_cdc_data_received, +#if UDI_CDC_PORT_NB > 1 + udi_cdc_data_received_2, +#endif +#if UDI_CDC_PORT_NB > 2 + udi_cdc_data_received_3, +#endif +}; + +//! Define a transfer halted +#define UDI_CDC_TRANS_HALTED 2 + +//! Buffer to send data +COMPILER_WORD_ALIGNED static uint8_t udi_cdc_tx_buf[UDI_CDC_PORT_NB][2][UDI_CDC_TX_BUFFERS]; +//! Data available in TX buffers +static uint16_t udi_cdc_tx_buf_nb[UDI_CDC_PORT_NB][2]; +//! Give current TX buffer used (tx0 if 0, tx1 if 1) +static volatile uint8_t udi_cdc_tx_buf_sel[UDI_CDC_PORT_NB]; +//! Value of SOF during last TX transfer +static uint16_t udi_cdc_tx_sof_num[UDI_CDC_PORT_NB]; +//! Signal a transfer on-going +static volatile bool udi_cdc_tx_trans_ongoing[UDI_CDC_PORT_NB]; +//! Signal that both buffer content data to send +static volatile bool udi_cdc_tx_both_buf_to_send[UDI_CDC_PORT_NB]; +static const uint8_t UDI_CDC_DATA_EP_INS[]={ + UDI_CDC_DATA_EP_IN, +#if UDI_CDC_PORT_NB > 1 + UDI_CDC_DATA_EP_IN_2, +#endif +#if UDI_CDC_PORT_NB > 2 + UDI_CDC_DATA_EP_IN_3, +#endif +}; +static const udd_callback_trans_t udi_cdc_data_sents[] = { + udi_cdc_data_sent, +#if UDI_CDC_PORT_NB > 1 + udi_cdc_data_sent_2, +#endif +#if UDI_CDC_PORT_NB > 2 + udi_cdc_data_sent_3, +#endif +}; + +//@} + + + +static bool udi_cdc_comm_enable_common(uint8_t port) +{ + // Initialize control signal management + udi_cdc_state[PORT] = CPU_TO_LE16(0); + + uid_cdc_state_msg[PORT].header.bmRequestType = + USB_REQ_DIR_IN | USB_REQ_TYPE_CLASS | + USB_REQ_RECIP_INTERFACE, + uid_cdc_state_msg[PORT].header.bNotification = USB_REQ_CDC_NOTIFY_SERIAL_STATE, + uid_cdc_state_msg[PORT].header.wValue = LE16(0), + uid_cdc_state_msg[PORT].header.wIndex = LE16(UDI_CDC_COMM_IFACE_NUMBER), + uid_cdc_state_msg[PORT].header.wLength = LE16(2), + uid_cdc_state_msg[PORT].value = CPU_TO_LE16(0); + + udi_cdc_line_coding[PORT].dwDTERate = CPU_TO_LE32(UDI_CDC_DEFAULT_RATE); + udi_cdc_line_coding[PORT].bCharFormat = UDI_CDC_DEFAULT_STOPBITS; + udi_cdc_line_coding[PORT].bParityType = UDI_CDC_DEFAULT_PARITY; + udi_cdc_line_coding[PORT].bDataBits = UDI_CDC_DEFAULT_DATABITS; + // Call application callback + // to initialize memories or indicate that interface is enabled +#if UDI_CDC_PORT_NB == 1 + UDI_CDC_SET_CODING_EXT((&udi_cdc_line_coding[0])); + return UDI_CDC_ENABLE_EXT(); +#else + UDI_CDC_SET_CODING_EXT(port,(&udi_cdc_line_coding[port])); + return UDI_CDC_ENABLE_EXT(port); +#endif +} + +bool udi_cdc_comm_enable(void) +{ + return udi_cdc_comm_enable_common(0); +} +#if UDI_CDC_PORT_NB > 1 +bool udi_cdc_comm_enable_2(void) +{ + return udi_cdc_comm_enable_common(1); +} +#endif +#if UDI_CDC_PORT_NB > 2 +bool udi_cdc_comm_enable_3(void) +{ + return udi_cdc_comm_enable_common(2); + +} +#endif + +static bool udi_cdc_data_enable_common(uint8_t port) +{ + // Initialize TX management + udi_cdc_tx_trans_ongoing[PORT] = false; + udi_cdc_tx_both_buf_to_send[PORT] = false; + udi_cdc_tx_buf_sel[PORT] = 0; + udi_cdc_tx_buf_nb[PORT][0] = 0; + udi_cdc_tx_buf_nb[PORT][1] = 0; + udi_cdc_tx_sof_num[PORT] = 0; + udi_cdc_tx_send(PORT); + + // Initialize RX management + udi_cdc_rx_trans_ongoing[PORT] = false; + udi_cdc_rx_buf_sel[PORT] = 0; + udi_cdc_rx_buf_nb[PORT][0] = 0; + udi_cdc_rx_pos[PORT] = 0; + udi_cdc_running[PORT] = udi_cdc_rx_start(PORT); + return udi_cdc_running[PORT]; +} + +bool udi_cdc_data_enable(void) +{ + return udi_cdc_data_enable_common(0); +} +#if UDI_CDC_PORT_NB > 1 +bool udi_cdc_data_enable_2(void) +{ + return udi_cdc_data_enable_common(1); +} +#endif +#if UDI_CDC_PORT_NB > 2 +bool udi_cdc_data_enable_3(void) +{ + return udi_cdc_data_enable_common(2); +} +#endif + + +static void udi_cdc_comm_disable_common(uint8_t port) +{ +#if UDI_CDC_PORT_NB == 1 + udi_cdc_running[0] = false; + UDI_CDC_DISABLE_EXT(); +#else + udi_cdc_running[port] = false; + UDI_CDC_DISABLE_EXT(port); +#endif +} + +void udi_cdc_comm_disable(void) +{ + udi_cdc_comm_disable_common(0); +} +#if UDI_CDC_PORT_NB > 1 +void udi_cdc_comm_disable_2(void) +{ + udi_cdc_comm_disable_common(1); +} +#endif +#if UDI_CDC_PORT_NB > 2 +void udi_cdc_comm_disable_3(void) +{ + udi_cdc_comm_disable_common(2); +} +#endif + +void udi_cdc_data_disable(void) +{ +} + + + +static bool udi_cdc_comm_setup_common(uint8_t port) +{ + if (Udd_setup_is_in()) { + // GET Interface Requests + if (Udd_setup_type() == USB_REQ_TYPE_CLASS) { + // Requests Class Interface Get + switch (udd_g_ctrlreq.req.bRequest) { + case USB_REQ_CDC_GET_LINE_CODING: + // Get configuration of CDC line + if (sizeof(usb_cdc_line_coding_t) != + udd_g_ctrlreq.req.wLength) + return false; // Error for USB host + udd_g_ctrlreq.payload = + (uint8_t *) & + udi_cdc_line_coding[PORT]; + udd_g_ctrlreq.payload_size = + sizeof(udi_cdc_line_coding); + return true; + } + } + } + if (Udd_setup_is_out()) { + // SET Interface Requests + if (Udd_setup_type() == USB_REQ_TYPE_CLASS) { + // Requests Class Interface Set + switch (udd_g_ctrlreq.req.bRequest) { + case USB_REQ_CDC_SET_LINE_CODING: + // Change configuration of CDC line + if (sizeof(usb_cdc_line_coding_t) != + udd_g_ctrlreq.req.wLength) + return false; // Error for USB host + udd_g_ctrlreq.callback = + udi_cdc_line_coding_receiveds[PORT]; + udd_g_ctrlreq.payload = + (uint8_t *) & + udi_cdc_line_coding[PORT]; + udd_g_ctrlreq.payload_size = + sizeof(udi_cdc_line_coding); + return true; + case USB_REQ_CDC_SET_CONTROL_LINE_STATE: + // According cdc spec 1.1 chapter 6.2.14 +#if UDI_CDC_PORT_NB == 1 + UDI_CDC_SET_DTR_EXT((0 != + (udd_g_ctrlreq.req.wValue + & CDC_CTRL_SIGNAL_DTE_PRESENT))); + UDI_CDC_SET_RTS_EXT((0 != + (udd_g_ctrlreq.req.wValue + & CDC_CTRL_SIGNAL_ACTIVATE_CARRIER))); +#else + UDI_CDC_SET_DTR_EXT(PORT, (0 != + (udd_g_ctrlreq.req.wValue + & CDC_CTRL_SIGNAL_DTE_PRESENT))); + UDI_CDC_SET_RTS_EXT(PORT, (0 != + (udd_g_ctrlreq.req.wValue + & CDC_CTRL_SIGNAL_ACTIVATE_CARRIER))); +#endif + return true; + } + } + } + return false; // request Not supported +} + +bool udi_cdc_comm_setup(void) +{ + return udi_cdc_comm_setup_common(0); +} +#if UDI_CDC_PORT_NB > 1 +bool udi_cdc_comm_setup_2(void) +{ + return udi_cdc_comm_setup_common(1); +} +#endif +#if UDI_CDC_PORT_NB > 2 +bool udi_cdc_comm_setup_3(void) +{ + return udi_cdc_comm_setup_common(2); +} +#endif + +bool udi_cdc_data_setup(void) +{ + return false; // request Not supported +} + +uint8_t udi_cdc_getsetting(void) +{ + return 0; // CDC don't have multiple alternate setting +} + +void udi_cdc_data_sof_notify(void) +{ + udi_cdc_tx_send(0); +} +#if UDI_CDC_PORT_NB > 1 +void udi_cdc_data_sof_notify_2(void) +{ + udi_cdc_tx_send(1); +} +#endif +#if UDI_CDC_PORT_NB > 2 +void udi_cdc_data_sof_notify_3(void) +{ + udi_cdc_tx_send(2); +} +#endif + +//------------------------------------------------- +//------- Internal routines to control serial line + + +static void udi_cdc_line_coding_received(void) +{ + udi_cdc_line_coding_received_common(0); +} +#if UDI_CDC_PORT_NB > 1 +static void udi_cdc_line_coding_received_2(void) +{ + udi_cdc_line_coding_received_common(1); +} +#endif +#if UDI_CDC_PORT_NB > 2 +static void udi_cdc_line_coding_received_3(void) +{ + udi_cdc_line_coding_received_common(2); +} +#endif +static void udi_cdc_line_coding_received_common(uint8_t port) +{ + // Send line coding to component associated to CDC +#if UDI_CDC_PORT_NB == 1 + UDI_CDC_SET_CODING_EXT((&udi_cdc_line_coding[0])); +#else + UDI_CDC_SET_CODING_EXT(port, (&udi_cdc_line_coding[port])); +#endif +} + + +static void udi_cdc_ctrl_state_change(uint8_t port, bool b_set, le16_t bit_mask) +{ + irqflags_t flags; + + // Update state + flags = cpu_irq_save(); // Protect udi_cdc_state + if (b_set) { + udi_cdc_state[PORT] |= bit_mask; + } else { + udi_cdc_state[PORT] &= ~bit_mask; + } + cpu_irq_restore(flags); + + // Send it if possible and state changed + udi_cdc_ctrl_state_notify(PORT); +} + + +static void udi_cdc_ctrl_state_notify(uint8_t port) +{ + // Send it if possible and state changed + if ((!udi_cdc_serial_state_msg_ongoing[PORT]) + && (udi_cdc_state[PORT] != uid_cdc_state_msg[PORT].value)) { + // Fill notification message + uid_cdc_state_msg[PORT].value = udi_cdc_state[PORT]; + // Send notification message + udi_cdc_serial_state_msg_ongoing[PORT] = + udd_ep_run(UDI_CDC_COMM_EPS[PORT] , + false, + (uint8_t *) & uid_cdc_state_msg[PORT], + sizeof(uid_cdc_state_msg), + udi_cdc_serial_state_msg_sents[PORT]); + } +} + + +static void udi_cdc_serial_state_msg_sent(udd_ep_status_t status, iram_size_t n) +{ + udi_cdc_serial_state_msg_sent_common(0, status, n); +} +#if UDI_CDC_PORT_NB > 1 +static void udi_cdc_serial_state_msg_sent_2(udd_ep_status_t status, iram_size_t n) +{ + udi_cdc_serial_state_msg_sent_common(1, status, n); +} +#endif +#if UDI_CDC_PORT_NB > 2 +static void udi_cdc_serial_state_msg_sent_3(udd_ep_status_t status, iram_size_t n) +{ + udi_cdc_serial_state_msg_sent_common(2, status, n); +} +#endif + +static void udi_cdc_serial_state_msg_sent_common(uint8_t port, udd_ep_status_t status, iram_size_t n) +{ + udi_cdc_serial_state_msg_ongoing[PORT] = false; + + // For the irregular signals like break, the incoming ring signal, + // or the overrun error state, this will reset their values to zero + // and again will not send another notification until their state changes. + udi_cdc_state[PORT] &= ~(CDC_SERIAL_STATE_BREAK | + CDC_SERIAL_STATE_RING | + CDC_SERIAL_STATE_FRAMING | + CDC_SERIAL_STATE_PARITY | CDC_SERIAL_STATE_OVERRUN); + uid_cdc_state_msg[PORT].value &= ~(CDC_SERIAL_STATE_BREAK | + CDC_SERIAL_STATE_RING | + CDC_SERIAL_STATE_FRAMING | + CDC_SERIAL_STATE_PARITY | CDC_SERIAL_STATE_OVERRUN); + // Send it if possible and state changed + udi_cdc_ctrl_state_notify(PORT); +} + + +//------------------------------------------------- +//------- Internal routines to process data transfer + + +static bool udi_cdc_rx_start(uint8_t port) +{ + irqflags_t flags; + uint8_t buf_sel_trans; + + flags = cpu_irq_save(); + buf_sel_trans = udi_cdc_rx_buf_sel[PORT]; + if (udi_cdc_rx_trans_ongoing[PORT] || + (udi_cdc_rx_pos[PORT] < udi_cdc_rx_buf_nb[PORT][buf_sel_trans])) { + // Transfer already on-going or current buffer no empty + cpu_irq_restore(flags); + return false; + } + + // Change current buffer + udi_cdc_rx_pos[PORT] = 0; + udi_cdc_rx_buf_sel[PORT] = (buf_sel_trans==0)?1:0; + + // Start transfer on RX + udi_cdc_rx_trans_ongoing[PORT] = true; + cpu_irq_restore(flags); + + if (udi_cdc_multi_is_rx_ready(PORT)) { +#if UDI_CDC_PORT_NB == 1 + UDI_CDC_RX_NOTIFY(); +#else + UDI_CDC_RX_NOTIFY(port); +#endif + } + + return udd_ep_run( UDI_CDC_DATA_EP_OUTS[PORT], + true, + udi_cdc_rx_buf[PORT][buf_sel_trans], + UDI_CDC_RX_BUFFERS, + udi_cdc_data_received_callbacks[PORT]); +} + + +static void udi_cdc_data_received(udd_ep_status_t status, iram_size_t n) +{ + udi_cdc_data_received_common(0, status, n); +} +#if UDI_CDC_PORT_NB > 1 +static void udi_cdc_data_received_2(udd_ep_status_t status, iram_size_t n) +{ + udi_cdc_data_received_common(1, status, n); +} +#endif +#if UDI_CDC_PORT_NB > 2 +static void udi_cdc_data_received_3(udd_ep_status_t status, iram_size_t n) +{ + udi_cdc_data_received_common(2, status, n); +} +#endif + +static void udi_cdc_data_received_common(uint8_t port, udd_ep_status_t status, iram_size_t n) +{ + uint8_t buf_sel_trans; + + if (UDD_EP_TRANSFER_OK != status) { + // Abort reception + return; + } + buf_sel_trans = (udi_cdc_rx_buf_sel[PORT]==0)?1:0; + if (!n) { + udd_ep_run( UDI_CDC_DATA_EP_OUTS[PORT], + true, + udi_cdc_rx_buf[PORT][buf_sel_trans], + UDI_CDC_RX_BUFFERS, + udi_cdc_data_received_callbacks[PORT]); + return; + } + udi_cdc_rx_buf_nb[PORT][buf_sel_trans] = n; + udi_cdc_rx_trans_ongoing[PORT] = false; + udi_cdc_rx_start(PORT); +} + + +static void udi_cdc_data_sent(udd_ep_status_t status, iram_size_t n) +{ + udi_cdc_data_sent_common(0, status, n); +} +#if UDI_CDC_PORT_NB > 1 +static void udi_cdc_data_sent_2(udd_ep_status_t status, iram_size_t n) +{ + udi_cdc_data_sent_common(1, status, n); +} +#endif +#if UDI_CDC_PORT_NB > 2 +static void udi_cdc_data_sent_3(udd_ep_status_t status, iram_size_t n) +{ + udi_cdc_data_sent_common(2, status, n); +} +#endif + +static void udi_cdc_data_sent_common(uint8_t port, udd_ep_status_t status, iram_size_t n) +{ + if (UDD_EP_TRANSFER_OK != status) { + // Abort transfer + return; + } + udi_cdc_tx_buf_nb[PORT][(udi_cdc_tx_buf_sel[PORT]==0)?1:0] = 0; + udi_cdc_tx_both_buf_to_send[PORT] = false; + udi_cdc_tx_trans_ongoing[PORT] = false; + udi_cdc_tx_send(PORT); +} + + +static void udi_cdc_tx_send(uint8_t port) +{ + irqflags_t flags; + uint8_t buf_sel_trans; + bool b_short_packet; + + if (udi_cdc_tx_trans_ongoing[PORT]) { + return; // Already on going or wait next SOF to send next data + } + if (udd_is_high_speed()) { + if (udi_cdc_tx_sof_num[PORT] == udd_get_micro_frame_number()) { + return; // Wait next SOF to send next data + } + }else{ + if (udi_cdc_tx_sof_num[PORT] == udd_get_frame_number()) { + return; // Wait next SOF to send next data + } + } + + flags = cpu_irq_save(); // to protect udi_cdc_tx_buf_sel + buf_sel_trans = udi_cdc_tx_buf_sel[PORT]; + if (!udi_cdc_tx_both_buf_to_send[PORT]) { + // Send current Buffer + // and switch the current buffer + udi_cdc_tx_buf_sel[PORT] = (buf_sel_trans==0)?1:0; + }else{ + // Send the other Buffer + // and no switch the current buffer + buf_sel_trans = (buf_sel_trans==0)?1:0; + } + udi_cdc_tx_trans_ongoing[PORT] = true; + cpu_irq_restore(flags); + + b_short_packet = (udi_cdc_tx_buf_nb[PORT][buf_sel_trans] != UDI_CDC_TX_BUFFERS); + if (b_short_packet) { + if (udd_is_high_speed()) { + udi_cdc_tx_sof_num[PORT] = udd_get_micro_frame_number(); + }else{ + udi_cdc_tx_sof_num[PORT] = udd_get_frame_number(); + } + }else{ + udi_cdc_tx_sof_num[PORT] = 0; // Force next transfer without wait SOF + } + + // Send the buffer with enable of short packet + udd_ep_run( UDI_CDC_DATA_EP_INS[PORT], + b_short_packet, + udi_cdc_tx_buf[PORT][buf_sel_trans], + udi_cdc_tx_buf_nb[PORT][buf_sel_trans], + udi_cdc_data_sents[PORT]); +} + + +//--------------------------------------------- +//------- Application interface + + +//------- Application interface + +void udi_cdc_ctrl_signal_dcd(bool b_set) +{ + udi_cdc_ctrl_state_change(0, b_set, CDC_SERIAL_STATE_DCD); +} + +void udi_cdc_ctrl_signal_dsr(bool b_set) +{ + udi_cdc_ctrl_state_change(0, b_set, CDC_SERIAL_STATE_DSR); +} + +void udi_cdc_signal_framing_error(void) +{ + udi_cdc_ctrl_state_change(0, true, CDC_SERIAL_STATE_FRAMING); +} + +void udi_cdc_signal_parity_error(void) +{ + udi_cdc_ctrl_state_change(0, true, CDC_SERIAL_STATE_PARITY); +} + +void udi_cdc_signal_overrun(void) +{ + udi_cdc_ctrl_state_change(0, true, CDC_SERIAL_STATE_OVERRUN); +} + +#if UDI_CDC_PORT_NB > 1 +void udi_cdc_multi_ctrl_signal_dcd(uint8_t port, bool b_set) +{ + udi_cdc_ctrl_state_change(port, b_set, CDC_SERIAL_STATE_DCD); +} + +void udi_cdc_multi_ctrl_signal_dsr(uint8_t port, bool b_set) +{ + udi_cdc_ctrl_state_change(port, b_set, CDC_SERIAL_STATE_DSR); +} + +void udi_cdc_multi_signal_framing_error(uint8_t port) +{ + udi_cdc_ctrl_state_change(port, true, CDC_SERIAL_STATE_FRAMING); +} + +void udi_cdc_multi_signal_parity_error(uint8_t port) +{ + udi_cdc_ctrl_state_change(port, true, CDC_SERIAL_STATE_PARITY); +} + +void udi_cdc_multi_signal_overrun(uint8_t port) +{ + udi_cdc_ctrl_state_change(port, true, CDC_SERIAL_STATE_OVERRUN); +} +#endif + +bool udi_cdc_multi_is_rx_ready(uint8_t port) +{ + uint16_t pos = udi_cdc_rx_pos[PORT]; + return (pos < udi_cdc_rx_buf_nb[PORT][udi_cdc_rx_buf_sel[PORT]]); +} + +bool udi_cdc_is_rx_ready(void) +{ + return udi_cdc_multi_is_rx_ready(0); +} + +int udi_cdc_multi_getc(uint8_t port) +{ + int rx_data = 0; + bool b_databit_9; + uint16_t pos; + uint8_t buf_sel; + + b_databit_9 = (9 == udi_cdc_line_coding[PORT].bDataBits); + +udi_cdc_getc_process_one_byte: + // Check avaliable data + pos = udi_cdc_rx_pos[PORT]; + buf_sel = udi_cdc_rx_buf_sel[PORT]; + while (pos >= udi_cdc_rx_buf_nb[PORT][buf_sel]) { + if (!udi_cdc_running[PORT]) { + return 0; + } + goto udi_cdc_getc_process_one_byte; + } + + // Read data + rx_data |= udi_cdc_rx_buf[PORT][buf_sel][pos]; + udi_cdc_rx_pos[PORT] = pos+1; + + udi_cdc_rx_start(PORT); + + if (b_databit_9) { + // Receive MSB + b_databit_9 = false; + rx_data = rx_data << 8; + goto udi_cdc_getc_process_one_byte; + } + return rx_data; +} + +int udi_cdc_getc(void) +{ + return udi_cdc_multi_getc(0); +} + +iram_size_t udi_cdc_multi_read_buf(uint8_t port, int* buf, iram_size_t size) +{ + uint8_t *ptr_buf = (uint8_t *)buf; + iram_size_t copy_nb; + uint16_t pos; + uint8_t buf_sel; + +udi_cdc_read_buf_loop_wait: + // Check avaliable data + pos = udi_cdc_rx_pos[PORT]; + buf_sel = udi_cdc_rx_buf_sel[PORT]; + while (pos >= udi_cdc_rx_buf_nb[PORT][buf_sel]) { + if (!udi_cdc_running[PORT]) { + return size; + } + goto udi_cdc_read_buf_loop_wait; + } + + // Read data + copy_nb = udi_cdc_rx_buf_nb[PORT][buf_sel] - pos; + if (copy_nb>size) { + copy_nb = size; + } + memcpy(ptr_buf, &udi_cdc_rx_buf[PORT][buf_sel][pos], copy_nb); + udi_cdc_rx_pos[PORT] += copy_nb; + ptr_buf += copy_nb; + size -= copy_nb; + udi_cdc_rx_start(PORT); + + if (size) { + goto udi_cdc_read_buf_loop_wait; + } + return 0; +} + +iram_size_t udi_cdc_read_buf(int* buf, iram_size_t size) +{ + return udi_cdc_multi_read_buf(0, buf, size); +} + +bool udi_cdc_multi_is_tx_ready(uint8_t port) +{ + irqflags_t flags; + if (udi_cdc_tx_buf_nb[PORT][udi_cdc_tx_buf_sel[PORT]]!=UDI_CDC_TX_BUFFERS) { + return true; + } + if (!udi_cdc_tx_both_buf_to_send[PORT]) { + flags = cpu_irq_save(); // to protect udi_cdc_tx_buf_sel + if (!udi_cdc_tx_trans_ongoing[PORT]) { + // No transfer on-going + // then use the other buffer to store data + udi_cdc_tx_both_buf_to_send[PORT] = true; + udi_cdc_tx_buf_sel[PORT] = (udi_cdc_tx_buf_sel[PORT]==0)?1:0; + } + cpu_irq_restore(flags); + } + return (udi_cdc_tx_buf_nb[PORT][udi_cdc_tx_buf_sel[PORT]]!=UDI_CDC_TX_BUFFERS); +} + +bool udi_cdc_is_tx_ready(void) +{ + return udi_cdc_multi_is_tx_ready(0); +} + +int udi_cdc_multi_putc(uint8_t port, int value) +{ + irqflags_t flags; + bool b_databit_9; + uint8_t buf_sel; + + b_databit_9 = (9 == udi_cdc_line_coding[PORT].bDataBits); + +udi_cdc_putc_process_one_byte: + // Check avaliable space + if (!udi_cdc_multi_is_tx_ready(PORT)) { + if (!udi_cdc_running[PORT]) { + return false; + } + goto udi_cdc_putc_process_one_byte; + } + + // Write value + flags = cpu_irq_save(); + buf_sel = udi_cdc_tx_buf_sel[PORT]; + udi_cdc_tx_buf[PORT][buf_sel][udi_cdc_tx_buf_nb[PORT][buf_sel]++] = value; + cpu_irq_restore(flags); + + if (b_databit_9) { + // Send MSB + b_databit_9 = false; + value = value >> 8; + goto udi_cdc_putc_process_one_byte; + } + return true; +} + +int udi_cdc_putc(int value) +{ + return udi_cdc_multi_putc(0, value); +} + +iram_size_t udi_cdc_multi_write_buf(uint8_t port, const int* buf, iram_size_t size) +{ + irqflags_t flags; + uint8_t buf_sel; + uint16_t buf_nb; + iram_size_t copy_nb; + uint8_t *ptr_buf = (uint8_t *)buf; + + if (9 == udi_cdc_line_coding[PORT].bDataBits) { + size *=2; + } + +udi_cdc_write_buf_loop_wait: + // Check avaliable space + if (!udi_cdc_multi_is_tx_ready(PORT)) { + if (!udi_cdc_running[PORT]) { + return size; + } + goto udi_cdc_write_buf_loop_wait; + } + + // Write values + flags = cpu_irq_save(); + buf_sel = udi_cdc_tx_buf_sel[PORT]; + buf_nb = udi_cdc_tx_buf_nb[PORT][buf_sel]; + copy_nb = UDI_CDC_TX_BUFFERS - buf_nb; + if (copy_nb>size) { + copy_nb = size; + } + memcpy(&udi_cdc_tx_buf[PORT][buf_sel][buf_nb], ptr_buf, copy_nb); + udi_cdc_tx_buf_nb[PORT][buf_sel] = buf_nb + copy_nb; + cpu_irq_restore(flags); + + // Update buffer pointer + ptr_buf = ptr_buf + copy_nb; + size -= copy_nb; + + if (size) { + goto udi_cdc_write_buf_loop_wait; + } + + return 0; +} + +iram_size_t udi_cdc_write_buf(const int* buf, iram_size_t size) +{ + return udi_cdc_multi_write_buf(0, buf, size); +} + +//@} diff --git a/DSTAT1/src/asf/common/services/usb/class/cdc/device/udi_cdc.h b/DSTAT1/src/asf/common/services/usb/class/cdc/device/udi_cdc.h new file mode 100644 index 0000000000000000000000000000000000000000..099f185a500dc000b7a4b89c8fc9862ad989365e --- /dev/null +++ b/DSTAT1/src/asf/common/services/usb/class/cdc/device/udi_cdc.h @@ -0,0 +1,507 @@ +/** + * \file + * + * \brief USB Device Communication Device Class (CDC) interface definitions. + * + * Copyright (c) 2009-2011 Atmel Corporation. All rights reserved. + * + * \asf_license_start + * + * 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. The name of Atmel may not be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * 4. This software may only be redistributed and used in connection with an + * Atmel microcontroller product. + * + * THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE + * EXPRESSLY AND SPECIFICALLY DISCLAIMED. IN NO EVENT SHALL ATMEL 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. + * + * \asf_license_stop + * + */ + +#ifndef _UDI_CDC_H_ +#define _UDI_CDC_H_ + +#include "conf_usb.h" +#include "usb_protocol.h" +#include "usb_protocol_cdc.h" +#include "udd.h" +#include "udc_desc.h" +#include "udi.h" + +// Check the number of port +#ifndef UDI_CDC_PORT_NB +# define UDI_CDC_PORT_NB 1 +#endif +#if UDI_CDC_PORT_NB > 3 +# error UDI_CDC_PORT_NB must be inferior or equal to 3 +#endif + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * \ingroup udi_group + * \defgroup udi_cdc_group UDI for Communication Device Class + * + * @{ + */ + +/** + * \name Interface Descriptor + * + * The following structures provide the interface descriptor. + * It must be implemented in USB configuration descriptor. + */ +//@{ + + +/** + * \brief Communication Class interface descriptor + * + * Interface descriptor with associated functional and endpoint + * descriptors for the CDC Communication Class interface. + */ +typedef struct { + //! Standard interface descriptor + usb_iface_desc_t iface; + //! CDC Header functional descriptor + usb_cdc_hdr_desc_t header; + //! CDC Abstract Control Model functional descriptor + usb_cdc_acm_desc_t acm; + //! CDC Union functional descriptor + usb_cdc_union_desc_t union_desc; + //! CDC Call Management functional descriptor + usb_cdc_call_mgmt_desc_t call_mgmt; + //! Notification endpoint descriptor + usb_ep_desc_t ep_notify; +} udi_cdc_comm_desc_t; + + +/** + * \brief Data Class interface descriptor + * + * Interface descriptor with associated endpoint descriptors for the + * CDC Data Class interface. + */ +typedef struct { + //! Standard interface descriptor + usb_iface_desc_t iface; + //! Data IN/OUT endpoint descriptors + usb_ep_desc_t ep_in; + usb_ep_desc_t ep_out; +} udi_cdc_data_desc_t; + + +//! CDC communication enpoints size for all speeds +#define UDI_CDC_COMM_EP_SIZE 64 +//! CDC data enpoints size for all speeds (no need to use 512B for HS) +#define UDI_CDC_DATA_EPS_SIZE 64 + +/** + * \name Content of interface descriptors for single or first com port + */ +//@{ +//! By default no string associated to these interfaces +#ifndef UDI_CDC_IAD_STRING_ID +#define UDI_CDC_IAD_STRING_ID 0 +#endif +#ifndef UDI_CDC_COMM_STRING_ID +#define UDI_CDC_COMM_STRING_ID 0 +#endif +#ifndef UDI_CDC_DATA_STRING_ID +#define UDI_CDC_DATA_STRING_ID 0 +#endif +# define UDI_CDC_IAD_DESC {\ + UDI_CDC_IAD_DESC_COMMON \ + .bFirstInterface = UDI_CDC_COMM_IFACE_NUMBER, \ + .iFunction = UDI_CDC_IAD_STRING_ID,\ + } +# define UDI_CDC_COMM_DESC {\ + UDI_CDC_COMM_DESC_COMMON \ + .ep_notify.bEndpointAddress = UDI_CDC_COMM_EP,\ + .iface.bInterfaceNumber = UDI_CDC_COMM_IFACE_NUMBER,\ + .call_mgmt.bDataInterface = UDI_CDC_DATA_IFACE_NUMBER,\ + .union_desc.bMasterInterface = UDI_CDC_COMM_IFACE_NUMBER,\ + .union_desc.bSlaveInterface0 = UDI_CDC_DATA_IFACE_NUMBER,\ + .iface.iInterface = UDI_CDC_COMM_STRING_ID,\ + } +# define UDI_CDC_DATA_DESC {\ + UDI_CDC_DATA_DESC_COMMON \ + .ep_in.bEndpointAddress = UDI_CDC_DATA_EP_IN,\ + .ep_out.bEndpointAddress = UDI_CDC_DATA_EP_OUT,\ + .iface.bInterfaceNumber = UDI_CDC_DATA_IFACE_NUMBER,\ + .iface.iInterface = UDI_CDC_DATA_STRING_ID,\ + } +//@} + +/** + * \name Content of interface descriptors for second com port + */ +//@{ +//! By default no string associated to these interfaces +#ifndef UDI_CDC_IAD_STRING_ID_2 +#define UDI_CDC_IAD_STRING_ID_2 0 +#endif +#ifndef UDI_CDC_COMM_STRING_ID_2 +#define UDI_CDC_COMM_STRING_ID_2 0 +#endif +#ifndef UDI_CDC_DATA_STRING_ID_2 +#define UDI_CDC_DATA_STRING_ID_2 0 +#endif +# define UDI_CDC_IAD_DESC_2 {\ + UDI_CDC_IAD_DESC_COMMON \ + .bFirstInterface = UDI_CDC_COMM_IFACE_NUMBER_2, \ + .iFunction = UDI_CDC_IAD_STRING_ID_2,\ + } +# define UDI_CDC_COMM_DESC_2 {\ + UDI_CDC_COMM_DESC_COMMON \ + .ep_notify.bEndpointAddress = UDI_CDC_COMM_EP_2,\ + .iface.bInterfaceNumber = UDI_CDC_COMM_IFACE_NUMBER_2,\ + .call_mgmt.bDataInterface = UDI_CDC_DATA_IFACE_NUMBER_2,\ + .union_desc.bMasterInterface = UDI_CDC_COMM_IFACE_NUMBER_2,\ + .union_desc.bSlaveInterface0 = UDI_CDC_DATA_IFACE_NUMBER_2,\ + .iface.iInterface = UDI_CDC_COMM_STRING_ID_2,\ + } +# define UDI_CDC_DATA_DESC_2 {\ + UDI_CDC_DATA_DESC_COMMON \ + .ep_in.bEndpointAddress = UDI_CDC_DATA_EP_IN_2,\ + .ep_out.bEndpointAddress = UDI_CDC_DATA_EP_OUT_2,\ + .iface.bInterfaceNumber = UDI_CDC_DATA_IFACE_NUMBER_2,\ + .iface.iInterface = UDI_CDC_DATA_STRING_ID_2,\ + } +//@} + +/** + * \name Content of interface descriptors for third com port + */ +//@{ +//! By default no string associated to these interfaces +#ifndef UDI_CDC_IAD_STRING_ID_3 +#define UDI_CDC_IAD_STRING_ID_3 0 +#endif +#ifndef UDI_CDC_COMM_STRING_ID_3 +#define UDI_CDC_COMM_STRING_ID_3 0 +#endif +#ifndef UDI_CDC_DATA_STRING_ID_3 +#define UDI_CDC_DATA_STRING_ID_3 0 +#endif +# define UDI_CDC_IAD_DESC_3 {\ + UDI_CDC_IAD_DESC_COMMON \ + .bFirstInterface = UDI_CDC_COMM_IFACE_NUMBER_3, \ + .iFunction = UDI_CDC_IAD_STRING_ID_3,\ + } +# define UDI_CDC_COMM_DESC_3 {\ + UDI_CDC_COMM_DESC_COMMON \ + .ep_notify.bEndpointAddress = UDI_CDC_COMM_EP_3,\ + .iface.bInterfaceNumber = UDI_CDC_COMM_IFACE_NUMBER_3,\ + .call_mgmt.bDataInterface = UDI_CDC_DATA_IFACE_NUMBER_3,\ + .union_desc.bMasterInterface = UDI_CDC_COMM_IFACE_NUMBER_3,\ + .union_desc.bSlaveInterface0 = UDI_CDC_DATA_IFACE_NUMBER_3,\ + .iface.iInterface = UDI_CDC_COMM_STRING_ID_3,\ + } +# define UDI_CDC_DATA_DESC_3 {\ + UDI_CDC_DATA_DESC_COMMON \ + .ep_in.bEndpointAddress = UDI_CDC_DATA_EP_IN_3,\ + .ep_out.bEndpointAddress = UDI_CDC_DATA_EP_OUT_3,\ + .iface.bInterfaceNumber = UDI_CDC_DATA_IFACE_NUMBER_3,\ + .iface.iInterface = UDI_CDC_DATA_STRING_ID_3,\ + } +//@} + + +//! Content of CDC IAD interface descriptor for all speeds +#define UDI_CDC_IAD_DESC_COMMON \ + .bLength = sizeof(usb_iad_desc_t),\ + .bDescriptorType = USB_DT_IAD,\ + .bInterfaceCount = 2,\ + .bFunctionClass = CDC_CLASS_COMM,\ + .bFunctionSubClass = CDC_SUBCLASS_ACM,\ + .bFunctionProtocol = CDC_PROTOCOL_V25TER, + +//! Content of CDC COMM interface descriptor for all speeds +#define UDI_CDC_COMM_DESC_COMMON \ + .iface.bLength = sizeof(usb_iface_desc_t),\ + .iface.bDescriptorType = USB_DT_INTERFACE,\ + .iface.bAlternateSetting = 0,\ + .iface.bNumEndpoints = 1,\ + .iface.bInterfaceClass = CDC_CLASS_COMM,\ + .iface.bInterfaceSubClass = CDC_SUBCLASS_ACM,\ + .iface.bInterfaceProtocol = CDC_PROTOCOL_V25TER,\ + .header.bFunctionLength = sizeof(usb_cdc_hdr_desc_t),\ + .header.bDescriptorType = CDC_CS_INTERFACE,\ + .header.bDescriptorSubtype = CDC_SCS_HEADER,\ + .header.bcdCDC = LE16(0x0110),\ + .call_mgmt.bFunctionLength = sizeof(usb_cdc_call_mgmt_desc_t),\ + .call_mgmt.bDescriptorType = CDC_CS_INTERFACE,\ + .call_mgmt.bDescriptorSubtype = CDC_SCS_CALL_MGMT,\ + .call_mgmt.bmCapabilities = \ + CDC_CALL_MGMT_SUPPORTED | CDC_CALL_MGMT_OVER_DCI,\ + .acm.bFunctionLength = sizeof(usb_cdc_acm_desc_t),\ + .acm.bDescriptorType = CDC_CS_INTERFACE,\ + .acm.bDescriptorSubtype = CDC_SCS_ACM,\ + .acm.bmCapabilities = CDC_ACM_SUPPORT_LINE_REQUESTS,\ + .union_desc.bFunctionLength = sizeof(usb_cdc_union_desc_t),\ + .union_desc.bDescriptorType = CDC_CS_INTERFACE,\ + .union_desc.bDescriptorSubtype= CDC_SCS_UNION,\ + .ep_notify.bLength = sizeof(usb_ep_desc_t),\ + .ep_notify.bDescriptorType = USB_DT_ENDPOINT,\ + .ep_notify.bmAttributes = USB_EP_TYPE_INTERRUPT,\ + .ep_notify.wMaxPacketSize = LE16(UDI_CDC_COMM_EP_SIZE),\ + .ep_notify.bInterval = 0xFF, + +//! Content of CDC DATA interface descriptor for all speeds +#define UDI_CDC_DATA_DESC_COMMON \ + .iface.bLength = sizeof(usb_iface_desc_t),\ + .iface.bDescriptorType = USB_DT_INTERFACE,\ + .iface.bAlternateSetting = 0,\ + .iface.bNumEndpoints = 2,\ + .iface.bInterfaceClass = CDC_CLASS_DATA,\ + .iface.bInterfaceSubClass = 0,\ + .iface.bInterfaceProtocol = 0,\ + .ep_in.bLength = sizeof(usb_ep_desc_t),\ + .ep_in.bDescriptorType = USB_DT_ENDPOINT,\ + .ep_in.wMaxPacketSize = LE16(UDI_CDC_DATA_EPS_SIZE),\ + .ep_in.bmAttributes = USB_EP_TYPE_BULK,\ + .ep_in.bInterval = 0,\ + .ep_out.bLength = sizeof(usb_ep_desc_t),\ + .ep_out.bDescriptorType = USB_DT_ENDPOINT,\ + .ep_out.wMaxPacketSize = LE16(UDI_CDC_DATA_EPS_SIZE),\ + .ep_out.bmAttributes = USB_EP_TYPE_BULK,\ + .ep_out.bInterval = 0, +//@} + + +//! Global struture which contains standard UDI API for UDC +extern UDC_DESC_STORAGE udi_api_t udi_api_cdc_comm; +extern UDC_DESC_STORAGE udi_api_t udi_api_cdc_data; +extern UDC_DESC_STORAGE udi_api_t udi_api_cdc_comm_2; +extern UDC_DESC_STORAGE udi_api_t udi_api_cdc_data_2; +extern UDC_DESC_STORAGE udi_api_t udi_api_cdc_comm_3; +extern UDC_DESC_STORAGE udi_api_t udi_api_cdc_data_3; + +/** + * \name Interface for application + * + * These routines are used by memory to transfer its data + * to/from USB CDC endpoint. + */ +//@{ + +/** + * \brief Notify a state change of DCD signal + * + * \param b_set DCD is enabled if true, else disabled + */ +void udi_cdc_ctrl_signal_dcd(bool b_set); + +/** + * \brief Notify a state change of DSR signal + * + * \param b_set DSR is enabled if true, else disabled + */ +void udi_cdc_ctrl_signal_dsr(bool b_set); + +/** + * \brief Notify a framing error + */ +void udi_cdc_signal_framing_error(void); + +/** + * \brief Notify a parity error + */ +void udi_cdc_signal_parity_error(void); + +/** + * \brief Notify a overrun + */ +void udi_cdc_signal_overrun(void); + +/** + * \brief This function checks if a character has been received on the CDC line + * + * \return \c 1 if a byte is ready to be read. + */ +bool udi_cdc_is_rx_ready(void); + +/** + * \brief Waits and gets a value on CDC line + * + * \return value read on CDC line + */ +int udi_cdc_getc(void); + +/** + * \brief Reads a RAM buffer on CDC line + * + * \param buf Values readed + * \param size Number of value readed + * + * \return the number of data remaining + */ +iram_size_t udi_cdc_read_buf(int* buf, iram_size_t size); + +/** + * \brief This function checks if a new character sent is possible + * The type int is used to support scanf redirection from compiler LIB. + * + * \return \c 1 if a new chracter can be sent + */ +bool udi_cdc_is_tx_ready(void); + +/** + * \brief Puts a byte on CDC line + * The type int is used to support printf redirection from compiler LIB. + * + * \param value Value to put + * + * \return \c 1 if function was successfully done, otherwise \c 0. + */ +int udi_cdc_putc(int value); + +/** + * \brief Writes a RAM buffer on CDC line + * + * \param buf Values to write + * \param size Number of value to write + * + * \return the number of data remaining + */ +iram_size_t udi_cdc_write_buf(const int* buf, iram_size_t size); +//@} + + +/** + * \name Interface for application for all ports + * + * These routines are used by memory to transfer its data + * to/from USB CDC endpoint. + */ +//@{ + +/** + * \brief Notify a state change of DCD signal + * + * \param port Communication port number to manage + * \param b_set DCD is enabled if true, else disabled + */ +void udi_cdc_multi_ctrl_signal_dcd(uint8_t port, bool b_set); + +/** + * \brief Notify a state change of DSR signal + * + * \param port Communication port number to manage + * \param b_set DSR is enabled if true, else disabled + */ +void udi_cdc_multi_ctrl_signal_dsr(uint8_t port, bool b_set); + +/** + * \brief Notify a framing error + * + * \param port Communication port number to manage + */ +void udi_cdc_multi_signal_framing_error(uint8_t port); + +/** + * \brief Notify a parity error + * + * \param port Communication port number to manage + */ +void udi_cdc_multi_signal_parity_error(uint8_t port); + +/** + * \brief Notify a overrun + * + * \param port Communication port number to manage + */ +void udi_cdc_multi_signal_overrun(uint8_t port); + +/** + * \brief This function checks if a character has been received on the CDC line + * + * \param port Communication port number to manage + * + * \return \c 1 if a byte is ready to be read. + */ +bool udi_cdc_multi_is_rx_ready(uint8_t port); + +/** + * \brief Waits and gets a value on CDC line + * + * \param port Communication port number to manage + * + * \return value read on CDC line + */ +int udi_cdc_multi_getc(uint8_t port); + +/** + * \brief Reads a RAM buffer on CDC line + * + * \param port Communication port number to manage + * \param buf Values readed + * \param size Number of value readed + * + * \return the number of data remaining + */ +iram_size_t udi_cdc_multi_read_buf(uint8_t port, int* buf, iram_size_t size); + +/** + * \brief This function checks if a new character sent is possible + * The type int is used to support scanf redirection from compiler LIB. + * + * \param port Communication port number to manage + * + * \return \c 1 if a new chracter can be sent + */ +bool udi_cdc_multi_is_tx_ready(uint8_t port); + +/** + * \brief Puts a byte on CDC line + * The type int is used to support printf redirection from compiler LIB. + * + * \param port Communication port number to manage + * \param value Value to put + * + * \return \c 1 if function was successfully done, otherwise \c 0. + */ +int udi_cdc_multi_putc(uint8_t port, int value); + +/** + * \brief Writes a RAM buffer on CDC line + * + * \param port Communication port number to manage + * \param buf Values to write + * \param size Number of value to write + * + * \return the number of data remaining + */ +iram_size_t udi_cdc_multi_write_buf(uint8_t port, const int* buf, iram_size_t size); +//@} + +//@} + +#ifdef __cplusplus +} +#endif +#endif // _UDI_CDC_H_ diff --git a/DSTAT1/src/asf/common/services/usb/class/cdc/device/udi_cdc_conf.h b/DSTAT1/src/asf/common/services/usb/class/cdc/device/udi_cdc_conf.h new file mode 100644 index 0000000000000000000000000000000000000000..f65af6893477dcfa62dffd7f363e28df91543c3f --- /dev/null +++ b/DSTAT1/src/asf/common/services/usb/class/cdc/device/udi_cdc_conf.h @@ -0,0 +1,137 @@ +/** + * \file + * + * \brief Default CDC configuration for a USB Device with a single interface + * + * Copyright (c) 2009-2011 Atmel Corporation. All rights reserved. + * + * \asf_license_start + * + * 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. The name of Atmel may not be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * 4. This software may only be redistributed and used in connection with an + * Atmel microcontroller product. + * + * THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE + * EXPRESSLY AND SPECIFICALLY DISCLAIMED. IN NO EVENT SHALL ATMEL 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. + * + * \asf_license_stop + * + */ + +#ifndef _UDI_CDC_CONF_H_ +#define _UDI_CDC_CONF_H_ + +#include "usb_protocol_cdc.h" +#include "conf_usb.h" + +// Check the number of port +#ifndef UDI_CDC_PORT_NB +# define UDI_CDC_PORT_NB 1 +#endif +#if UDI_CDC_PORT_NB > 3 +# error UDI_CDC_PORT_NB must be inferior or equal at 3 +#endif + + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * \ingroup udi_cdc_group + * \defgroup udi_cdc_group_conf Default CDC configuration for a USB Device + * with a single interface CDC + * + * @{ + */ + +//! Control endpoint size (Endpoint 0) +#define USB_DEVICE_EP_CTRL_SIZE 64 + +#if XMEGA +/** + * \name Endpoint configuration on XMEGA + * The XMEGA supports a IN and OUT endpoint with the same number endpoint. + */ +//@{ +//! Endpoints' numbers used by single or first CDC port +#define UDI_CDC_DATA_EP_IN (1 | USB_EP_DIR_IN) // TX +#define UDI_CDC_DATA_EP_OUT (2 | USB_EP_DIR_OUT) // RX +#define UDI_CDC_COMM_EP (2 | USB_EP_DIR_IN) // Notify endpoint +//! Endpoints' numbers used by second CDC port (Optional) +#define UDI_CDC_DATA_EP_IN_2 (3 | USB_EP_DIR_IN) // TX +#define UDI_CDC_DATA_EP_OUT_2 (4 | USB_EP_DIR_OUT) // RX +#define UDI_CDC_COMM_EP_2 (4 | USB_EP_DIR_IN) // Notify endpoint +//! Endpoints' numbers used by third CDC port (Optional) +#define UDI_CDC_DATA_EP_IN_3 (5 | USB_EP_DIR_IN) // TX +#define UDI_CDC_DATA_EP_OUT_3 (6 | USB_EP_DIR_OUT) // RX +#define UDI_CDC_COMM_EP_3 (6 | USB_EP_DIR_IN) // Notify endpoint +//@} + +#else + +/** + * \name Default endpoint configuration + */ +//@{ +//! Endpoints' numbers used by single or first CDC port +#define UDI_CDC_DATA_EP_IN (1 | USB_EP_DIR_IN) // TX +#define UDI_CDC_DATA_EP_OUT (2 | USB_EP_DIR_OUT) // RX +#define UDI_CDC_COMM_EP (3 | USB_EP_DIR_IN) // Notify endpoint +//! Endpoints' numbers used by second CDC port (Optional) +#define UDI_CDC_DATA_EP_IN_2 (4 | USB_EP_DIR_IN) // TX +#define UDI_CDC_DATA_EP_OUT_2 (5 | USB_EP_DIR_OUT) // RX +#define UDI_CDC_COMM_EP_2 (6 | USB_EP_DIR_IN) // Notify endpoint +//! Endpoints' numbers used by third CDC port (Optional) +#define UDI_CDC_DATA_EP_IN_3 (7 | USB_EP_DIR_IN) // TX +#define UDI_CDC_DATA_EP_OUT_3 (8 | USB_EP_DIR_OUT) // RX +#define UDI_CDC_COMM_EP_3 (9 | USB_EP_DIR_IN) // Notify endpoint +//@} + +#endif + +//! Interface numbers used by single or first CDC port +#define UDI_CDC_COMM_IFACE_NUMBER 0 +#define UDI_CDC_DATA_IFACE_NUMBER 1 +//! Interface numbers used by second CDC port (Optional) +#define UDI_CDC_COMM_IFACE_NUMBER_2 2 +#define UDI_CDC_DATA_IFACE_NUMBER_2 3 +//! Interface numbers used by third CDC port (Optional) +#define UDI_CDC_COMM_IFACE_NUMBER_3 4 +#define UDI_CDC_DATA_IFACE_NUMBER_3 5 + +/** + * \name UDD Configuration + */ +//@{ +//! 3 endpoints used by single CDC interface +#define USB_DEVICE_MAX_EP (3*UDI_CDC_PORT_NB) +//@} + +//@} + +#ifdef __cplusplus +} +#endif +#endif // _UDI_CDC_CONF_H_ diff --git a/DSTAT1/src/asf/common/services/usb/class/cdc/device/udi_cdc_desc.c b/DSTAT1/src/asf/common/services/usb/class/cdc/device/udi_cdc_desc.c new file mode 100644 index 0000000000000000000000000000000000000000..40dc678c57a5f5358c6111bab1afcc2f8a583e43 --- /dev/null +++ b/DSTAT1/src/asf/common/services/usb/class/cdc/device/udi_cdc_desc.c @@ -0,0 +1,212 @@ +/** + * \file + * + * \brief Default descriptors for a USB Device with a single interface CDC + * + * Copyright (c) 2009-2011 Atmel Corporation. All rights reserved. + * + * \asf_license_start + * + * 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. The name of Atmel may not be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * 4. This software may only be redistributed and used in connection with an + * Atmel microcontroller product. + * + * THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE + * EXPRESSLY AND SPECIFICALLY DISCLAIMED. IN NO EVENT SHALL ATMEL 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. + * + * \asf_license_stop + * + */ + +#include "conf_usb.h" +#include "udd.h" +#include "udc_desc.h" +#include "udi_cdc.h" + + +/** + * \ingroup udi_cdc_group + * \defgroup udi_cdc_group_desc Default descriptors for a USB Device + * with a single interface CDC + * + * @{ + */ + +//! Two interfaces for a CDC device +#if UDI_CDC_PORT_NB == 1 +# define USB_DEVICE_NB_INTERFACE 2 +#elif UDI_CDC_PORT_NB == 2 +# define USB_DEVICE_NB_INTERFACE 4 +#elif UDI_CDC_PORT_NB == 3 +# define USB_DEVICE_NB_INTERFACE 6 +#endif + +/**INDENT-OFF**/ + +//! USB Device Descriptor +COMPILER_WORD_ALIGNED +UDC_DESC_STORAGE usb_dev_desc_t udc_device_desc = { + .bLength = sizeof(usb_dev_desc_t), + .bDescriptorType = USB_DT_DEVICE, + .bcdUSB = LE16(USB_V2_0), +#if UDI_CDC_PORT_NB > 1 + .bDeviceClass = 0, +#else + .bDeviceClass = CDC_CLASS_DEVICE, +#endif + .bDeviceSubClass = 0, + .bDeviceProtocol = 0, + .bMaxPacketSize0 = USB_DEVICE_EP_CTRL_SIZE, + .idVendor = LE16(USB_DEVICE_VENDOR_ID), + .idProduct = LE16(USB_DEVICE_PRODUCT_ID), + .bcdDevice = LE16((USB_DEVICE_MAJOR_VERSION << 8) + | USB_DEVICE_MINOR_VERSION), +#ifdef USB_DEVICE_MANUFACTURE_NAME + .iManufacturer = 1, +#else + .iManufacturer = 0, // No manufacture string +#endif +#ifdef USB_DEVICE_PRODUCT_NAME + .iProduct = 2, +#else + .iProduct = 0, // No product string +#endif +#ifdef USB_DEVICE_SERIAL_NAME + .iSerialNumber = 3, +#else + .iSerialNumber = 0, // No serial string +#endif + .bNumConfigurations = 1 +}; + + +#ifdef USB_DEVICE_HS_SUPPORT +//! USB Device Qualifier Descriptor for HS +COMPILER_WORD_ALIGNED +UDC_DESC_STORAGE usb_dev_qual_desc_t udc_device_qual = { + .bLength = sizeof(usb_dev_qual_desc_t), + .bDescriptorType = USB_DT_DEVICE_QUALIFIER, + .bcdUSB = LE16(USB_V2_0), +#if UDI_CDC_PORT_NB > 1 + .bDeviceClass = 0, +#else + .bDeviceClass = CDC_CLASS_DEVICE, +#endif + .bDeviceSubClass = 0, + .bDeviceProtocol = 0, + .bMaxPacketSize0 = USB_DEVICE_EP_CTRL_SIZE, + .bNumConfigurations = 1 +}; +#endif + +//! Structure for USB Device Configuration Descriptor +COMPILER_PACK_SET(1); +typedef struct { + usb_conf_desc_t conf; +#if UDI_CDC_PORT_NB == 1 + udi_cdc_comm_desc_t udi_cdc_comm; + udi_cdc_data_desc_t udi_cdc_data; +#endif +#if UDI_CDC_PORT_NB > 1 + usb_iad_desc_t udi_cdc_iad; + udi_cdc_comm_desc_t udi_cdc_comm; + udi_cdc_data_desc_t udi_cdc_data; + usb_iad_desc_t udi_cdc_iad_2; + udi_cdc_comm_desc_t udi_cdc_comm_2; + udi_cdc_data_desc_t udi_cdc_data_2; +#endif +#if UDI_CDC_PORT_NB > 2 + usb_iad_desc_t udi_cdc_iad_3; + udi_cdc_comm_desc_t udi_cdc_comm_3; + udi_cdc_data_desc_t udi_cdc_data_3; +#endif +} udc_desc_t; +COMPILER_PACK_RESET(); + +//! USB Device Configuration Descriptor filled for full and high speed +COMPILER_WORD_ALIGNED +UDC_DESC_STORAGE udc_desc_t udc_desc = { + .conf.bLength = sizeof(usb_conf_desc_t), + .conf.bDescriptorType = USB_DT_CONFIGURATION, + .conf.wTotalLength = LE16(sizeof(udc_desc_t)), + .conf.bNumInterfaces = USB_DEVICE_NB_INTERFACE, + .conf.bConfigurationValue = 1, + .conf.iConfiguration = 0, + .conf.bmAttributes = USB_CONFIG_ATTR_MUST_SET | USB_DEVICE_ATTR, + .conf.bMaxPower = USB_CONFIG_MAX_POWER(USB_DEVICE_POWER), + .udi_cdc_comm = UDI_CDC_COMM_DESC, + .udi_cdc_data = UDI_CDC_DATA_DESC, +#if UDI_CDC_PORT_NB > 1 + .udi_cdc_iad = UDI_CDC_IAD_DESC, + .udi_cdc_iad_2 = UDI_CDC_IAD_DESC_2, + .udi_cdc_comm_2 = UDI_CDC_COMM_DESC_2, + .udi_cdc_data_2 = UDI_CDC_DATA_DESC_2, +#endif +#if UDI_CDC_PORT_NB > 2 + .udi_cdc_iad_3 = UDI_CDC_IAD_DESC_3, + .udi_cdc_comm_3 = UDI_CDC_COMM_DESC_3, + .udi_cdc_data_3 = UDI_CDC_DATA_DESC_3, +#endif +}; + + +/** + * \name UDC structures which content all USB Device definitions + */ +//@{ + +//! Associate an UDI for each USB interface +UDC_DESC_STORAGE udi_api_t *udi_apis[USB_DEVICE_NB_INTERFACE] = { + &udi_api_cdc_comm, + &udi_api_cdc_data, +#if UDI_CDC_PORT_NB > 1 + &udi_api_cdc_comm_2, + &udi_api_cdc_data_2, +#endif +#if UDI_CDC_PORT_NB > 2 + &udi_api_cdc_comm_3, + &udi_api_cdc_data_3, +#endif +}; + +//! Add UDI with USB Descriptors FS & HS +UDC_DESC_STORAGE udc_config_speed_t udc_config_fshs[1] = { { + .desc = (usb_conf_desc_t UDC_DESC_STORAGE*)&udc_desc, + .udi_apis = udi_apis, +}}; + +//! Add all information about USB Device in global structure for UDC +UDC_DESC_STORAGE udc_config_t udc_config = { + .confdev_lsfs = &udc_device_desc, + .conf_lsfs = udc_config_fshs, +#ifdef USB_DEVICE_HS_SUPPORT + .confdev_hs = &udc_device_desc, + .qualifier = &udc_device_qual, + .conf_hs = udc_config_fshs, +#endif +}; + +//@} +/**INDENT-ON**/ +//@} diff --git a/DSTAT1/src/asf/common/services/usb/class/cdc/usb_protocol_cdc.h b/DSTAT1/src/asf/common/services/usb/class/cdc/usb_protocol_cdc.h new file mode 100644 index 0000000000000000000000000000000000000000..7f1dc84a2b0d21ae0f9a7dddc3ae7ebd1f137b6c --- /dev/null +++ b/DSTAT1/src/asf/common/services/usb/class/cdc/usb_protocol_cdc.h @@ -0,0 +1,313 @@ +/** + * \file + * + * \brief USB Communication Device Class (CDC) protocol definitions + * + * Copyright (c) 2009 Atmel Corporation. All rights reserved. + * + * \asf_license_start + * + * 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. The name of Atmel may not be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * 4. This software may only be redistributed and used in connection with an + * Atmel microcontroller product. + * + * THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE + * EXPRESSLY AND SPECIFICALLY DISCLAIMED. IN NO EVENT SHALL ATMEL 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. + * + * \asf_license_stop + * + */ +#ifndef _USB_PROTOCOL_CDC_H_ +#define _USB_PROTOCOL_CDC_H_ + +#include "compiler.h" + +/** + * \ingroup usb_protocol_group + * \defgroup cdc_protocol_group Communication Device Class Definitions + * @{ + */ + +/** + * \name Possible values of class + */ +//@{ +#define CDC_CLASS_DEVICE 0x02 //!< USB Communication Device Class +#define CDC_CLASS_COMM 0x02 //!< CDC Communication Class Interface +#define CDC_CLASS_DATA 0x0A //!< CDC Data Class Interface +//@} + +//! \name USB CDC Subclass IDs +//@{ +#define CDC_SUBCLASS_DLCM 0x01 //!< Direct Line Control Model +#define CDC_SUBCLASS_ACM 0x02 //!< Abstract Control Model +#define CDC_SUBCLASS_TCM 0x03 //!< Telephone Control Model +#define CDC_SUBCLASS_MCCM 0x04 //!< Multi-Channel Control Model +#define CDC_SUBCLASS_CCM 0x05 //!< CAPI Control Model +#define CDC_SUBCLASS_ETH 0x06 //!< Ethernet Networking Control Model +#define CDC_SUBCLASS_ATM 0x07 //!< ATM Networking Control Model +//@} + +//! \name USB CDC Communication Interface Protocol IDs +//@{ +#define CDC_PROTOCOL_V25TER 0x01 //!< Common AT commands +//@} + +//! \name USB CDC Data Interface Protocol IDs +//@{ +#define CDC_PROTOCOL_I430 0x30 //!< ISDN BRI +#define CDC_PROTOCOL_HDLC 0x31 //!< HDLC +#define CDC_PROTOCOL_TRANS 0x32 //!< Transparent +#define CDC_PROTOCOL_Q921M 0x50 //!< Q.921 management protocol +#define CDC_PROTOCOL_Q921 0x51 //!< Q.931 [sic] Data link protocol +#define CDC_PROTOCOL_Q921TM 0x52 //!< Q.921 TEI-multiplexor +#define CDC_PROTOCOL_V42BIS 0x90 //!< Data compression procedures +#define CDC_PROTOCOL_Q931 0x91 //!< Euro-ISDN protocol control +#define CDC_PROTOCOL_V120 0x92 //!< V.24 rate adaption to ISDN +#define CDC_PROTOCOL_CAPI20 0x93 //!< CAPI Commands +#define CDC_PROTOCOL_HOST 0xFD //!< Host based driver +/** + * \brief Describes the Protocol Unit Functional Descriptors [sic] + * on Communication Class Interface + */ +#define CDC_PROTOCOL_PUFD 0xFE +//@} + +//! \name USB CDC Functional Descriptor Types +//@{ +#define CDC_CS_INTERFACE 0x24 //!< Interface Functional Descriptor +#define CDC_CS_ENDPOINT 0x25 //!< Endpoint Functional Descriptor +//@} + +//! \name USB CDC Functional Descriptor Subtypes +//@{ +#define CDC_SCS_HEADER 0x00 //!< Header Functional Descriptor +#define CDC_SCS_CALL_MGMT 0x01 //!< Call Management +#define CDC_SCS_ACM 0x02 //!< Abstract Control Management +#define CDC_SCS_UNION 0x06 //!< Union Functional Descriptor +//@} + +//! \name USB CDC Request IDs +//@{ +#define USB_REQ_CDC_SEND_ENCAPSULATED_COMMAND 0x00 +#define USB_REQ_CDC_GET_ENCAPSULATED_RESPONSE 0x01 +#define USB_REQ_CDC_SET_COMM_FEATURE 0x02 +#define USB_REQ_CDC_GET_COMM_FEATURE 0x03 +#define USB_REQ_CDC_CLEAR_COMM_FEATURE 0x04 +#define USB_REQ_CDC_SET_AUX_LINE_STATE 0x10 +#define USB_REQ_CDC_SET_HOOK_STATE 0x11 +#define USB_REQ_CDC_PULSE_SETUP 0x12 +#define USB_REQ_CDC_SEND_PULSE 0x13 +#define USB_REQ_CDC_SET_PULSE_TIME 0x14 +#define USB_REQ_CDC_RING_AUX_JACK 0x15 +#define USB_REQ_CDC_SET_LINE_CODING 0x20 +#define USB_REQ_CDC_GET_LINE_CODING 0x21 +#define USB_REQ_CDC_SET_CONTROL_LINE_STATE 0x22 +#define USB_REQ_CDC_SEND_BREAK 0x23 +#define USB_REQ_CDC_SET_RINGER_PARMS 0x30 +#define USB_REQ_CDC_GET_RINGER_PARMS 0x31 +#define USB_REQ_CDC_SET_OPERATION_PARMS 0x32 +#define USB_REQ_CDC_GET_OPERATION_PARMS 0x33 +#define USB_REQ_CDC_SET_LINE_PARMS 0x34 +#define USB_REQ_CDC_GET_LINE_PARMS 0x35 +#define USB_REQ_CDC_DIAL_DIGITS 0x36 +#define USB_REQ_CDC_SET_UNIT_PARAMETER 0x37 +#define USB_REQ_CDC_GET_UNIT_PARAMETER 0x38 +#define USB_REQ_CDC_CLEAR_UNIT_PARAMETER 0x39 +#define USB_REQ_CDC_GET_PROFILE 0x3A +#define USB_REQ_CDC_SET_ETHERNET_MULTICAST_FILTERS 0x40 +#define USB_REQ_CDC_SET_ETHERNET_POWER_MANAGEMENT_PATTERNFILTER 0x41 +#define USB_REQ_CDC_GET_ETHERNET_POWER_MANAGEMENT_PATTERNFILTER 0x42 +#define USB_REQ_CDC_SET_ETHERNET_PACKET_FILTER 0x43 +#define USB_REQ_CDC_GET_ETHERNET_STATISTIC 0x44 +#define USB_REQ_CDC_SET_ATM_DATA_FORMAT 0x50 +#define USB_REQ_CDC_GET_ATM_DEVICE_STATISTICS 0x51 +#define USB_REQ_CDC_SET_ATM_DEFAULT_VC 0x52 +#define USB_REQ_CDC_GET_ATM_VC_STATISTICS 0x53 +// Added bNotification codes according cdc spec 1.1 chapter 6.3 +#define USB_REQ_CDC_NOTIFY_RING_DETECT 0x09 +#define USB_REQ_CDC_NOTIFY_SERIAL_STATE 0x20 +#define USB_REQ_CDC_NOTIFY_CALL_STATE_CHANGE 0x28 +#define USB_REQ_CDC_NOTIFY_LINE_STATE_CHANGE 0x29 +//@} + +/* + * Need to pack structures tightly, or the compiler might insert padding + * and violate the spec-mandated layout. + */ +COMPILER_PACK_SET(1); + +//! \name USB CDC Descriptors +//@{ + + +//! CDC Header Functional Descriptor +typedef struct { + uint8_t bFunctionLength; + uint8_t bDescriptorType; + uint8_t bDescriptorSubtype; + le16_t bcdCDC; +} usb_cdc_hdr_desc_t; + +//! CDC Call Management Functional Descriptor +typedef struct { + uint8_t bFunctionLength; + uint8_t bDescriptorType; + uint8_t bDescriptorSubtype; + uint8_t bmCapabilities; + uint8_t bDataInterface; +} usb_cdc_call_mgmt_desc_t; + +//! CDC ACM Functional Descriptor +typedef struct { + uint8_t bFunctionLength; + uint8_t bDescriptorType; + uint8_t bDescriptorSubtype; + uint8_t bmCapabilities; +} usb_cdc_acm_desc_t; + +//! CDC Union Functional Descriptor +typedef struct { + uint8_t bFunctionLength; + uint8_t bDescriptorType; + uint8_t bDescriptorSubtype; + uint8_t bMasterInterface; + uint8_t bSlaveInterface0; +} usb_cdc_union_desc_t; + + +//! \name USB CDC Call Management Capabilities +//@{ +//! Device handles call management itself +#define CDC_CALL_MGMT_SUPPORTED (1 << 0) +//! Device can send/receive call management info over a Data Class interface +#define CDC_CALL_MGMT_OVER_DCI (1 << 1) +//@} + +//! \name USB CDC ACM Capabilities +//@{ +//! Device supports the request combination of +//! Set_Comm_Feature, Clear_Comm_Feature, and Get_Comm_Feature. +#define CDC_ACM_SUPPORT_FEATURE_REQUESTS (1 << 0) +//! Device supports the request combination of +//! Set_Line_Coding, Set_Control_Line_State, Get_Line_Coding, +//! and the notification Serial_State. +#define CDC_ACM_SUPPORT_LINE_REQUESTS (1 << 1) +//! Device supports the request Send_Break +#define CDC_ACM_SUPPORT_SENDBREAK_REQUESTS (1 << 2) +//! Device supports the notification Network_Connection. +#define CDC_ACM_SUPPORT_NOTIFY_REQUESTS (1 << 3) +//@} +//@} + +//! \name USB CDC line control +//@{ + +//! \name USB CDC line coding +//@{ +//! Line Coding structure +typedef struct { + le32_t dwDTERate; + uint8_t bCharFormat; + uint8_t bParityType; + uint8_t bDataBits; +} usb_cdc_line_coding_t; +//! Possible values of bCharFormat +enum cdc_char_format { + CDC_STOP_BITS_1 = 0, //!< 1 stop bit + CDC_STOP_BITS_1_5 = 1, //!< 1.5 stop bits + CDC_STOP_BITS_2 = 2, //!< 2 stop bits +}; +//! Possible values of bParityType +enum cdc_parity { + CDC_PAR_NONE = 0, //!< No parity + CDC_PAR_ODD = 1, //!< Odd parity + CDC_PAR_EVEN = 2, //!< Even parity + CDC_PAR_MARK = 3, //!< Parity forced to 0 (space) + CDC_PAR_SPACE = 4, //!< Parity forced to 1 (mark) +}; +//@} + +//! \name USB CDC control signals +//! spec 1.1 chapter 6.2.14 +//@{ + +//! Control signal structure +typedef struct { + uint16_t value; +} usb_cdc_control_signal_t; + +//! \name Possible values in usb_cdc_control_signal_t +//@{ +//! Carrier control for half duplex modems. +//! This signal corresponds to V.24 signal 105 and RS-232 signal RTS. +//! The device ignores the value of this bit +//! when operating in full duplex mode. +#define CDC_CTRL_SIGNAL_ACTIVATE_CARRIER (1 << 1) +//! Indicates to DCE if DTE is present or not. +//! This signal corresponds to V.24 signal 108/2 and RS-232 signal DTR. +#define CDC_CTRL_SIGNAL_DTE_PRESENT (1 << 0) +//@} +//@} + + +//! \name USB CDC notification message +//@{ + +typedef struct { + uint8_t bmRequestType; + uint8_t bNotification; + le16_t wValue; + le16_t wIndex; + le16_t wLength; +} usb_cdc_notify_msg_t; + +//! \name USB CDC serial state +//@{* + +//! Hardware handshake support (cdc spec 1.1 chapter 6.3.5) +typedef struct { + usb_cdc_notify_msg_t header; + le16_t value; +} usb_cdc_notify_serial_state_t; + +//! \name Possible values in usb_cdc_notify_serial_state_t +//@{ +#define CDC_SERIAL_STATE_DCD CPU_TO_LE16((1<<0)) +#define CDC_SERIAL_STATE_DSR CPU_TO_LE16((1<<1)) +#define CDC_SERIAL_STATE_BREAK CPU_TO_LE16((1<<2)) +#define CDC_SERIAL_STATE_RING CPU_TO_LE16((1<<3)) +#define CDC_SERIAL_STATE_FRAMING CPU_TO_LE16((1<<4)) +#define CDC_SERIAL_STATE_PARITY CPU_TO_LE16((1<<5)) +#define CDC_SERIAL_STATE_OVERRUN CPU_TO_LE16((1<<6)) +//@} +//! @} + +//! @} + +COMPILER_PACK_RESET(); + +//! @} + +#endif // _USB_PROTOCOL_CDC_H_ diff --git a/DSTAT1/src/asf/common/services/usb/udc/udc.c b/DSTAT1/src/asf/common/services/usb/udc/udc.c new file mode 100644 index 0000000000000000000000000000000000000000..6daea9cfdb31c194a82110ea37802bedd5ba8327 --- /dev/null +++ b/DSTAT1/src/asf/common/services/usb/udc/udc.c @@ -0,0 +1,1084 @@ +/** + * \file + * + * \brief USB Device Controller (UDC) + * + * Copyright (c) 2009 - 2011 Atmel Corporation. All rights reserved. + * + * \asf_license_start + * + * 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. The name of Atmel may not be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * 4. This software may only be redistributed and used in connection with an + * Atmel microcontroller product. + * + * THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE + * EXPRESSLY AND SPECIFICALLY DISCLAIMED. IN NO EVENT SHALL ATMEL 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. + * + * \asf_license_stop + * + */ + +#include "conf_usb.h" +#include "usb_protocol.h" +#include "udd.h" +#include "udc_desc.h" +#include "udi.h" +#include "udc.h" + +/** + * \addtogroup udc_group + * @{ + */ + +//! \name Internal variables to manage the USB device +//! @{ + +//! Device status state (see enum usb_device_status in usb_protocol.h) +static le16_t udc_device_status; + +//! Device Configuration number selected by the USB host +static uint8_t udc_num_configuration = 0; + +//! Pointer on the selected speed device configuration +static udc_config_speed_t UDC_DESC_STORAGE *udc_ptr_conf; + +//! Pointer on interface descriptor used by SETUP request. +static usb_iface_desc_t UDC_DESC_STORAGE *udc_ptr_iface; + +//! @} + + +//! \name Internal structure to store the USB device main strings +//! @{ + +/** + * \brief Language ID of USB device (US ID by default) + */ +COMPILER_WORD_ALIGNED +static UDC_DESC_STORAGE usb_str_lgid_desc_t udc_string_desc_languageid = { + .desc.bLength = sizeof(usb_str_lgid_desc_t), + .desc.bDescriptorType = USB_DT_STRING, + .string = {LE16(USB_LANGID_EN_US)} +}; + +/** + * \brief USB device manufacture name storage + * String is allocated only if USB_DEVICE_MANUFACTURE_NAME is declared + * by usb application configuration + */ +#ifdef USB_DEVICE_MANUFACTURE_NAME +static uint8_t udc_string_manufacturer_name[] = USB_DEVICE_MANUFACTURE_NAME; +# define USB_DEVICE_MANUFACTURE_NAME_SIZE \ + (sizeof(udc_string_manufacturer_name)-1) +#else +# define USB_DEVICE_MANUFACTURE_NAME_SIZE 0 +#endif + +/** + * \brief USB device product name storage + * String is allocated only if USB_DEVICE_PRODUCT_NAME is declared + * by usb application configuration + */ +#ifdef USB_DEVICE_PRODUCT_NAME +static uint8_t udc_string_product_name[] = USB_DEVICE_PRODUCT_NAME; +# define USB_DEVICE_PRODUCT_NAME_SIZE (sizeof(udc_string_product_name)-1) +#else +# define USB_DEVICE_PRODUCT_NAME_SIZE 0 +#endif + +/** + * \brief Get USB device serial number + * + * Use the define USB_DEVICE_SERIAL_NAME to set static serial number. + * + * For dynamic serial number set the define USB_DEVICE_GET_SERIAL_NAME_POINTER + * to a suitable pointer. This will also require the serial number length + * define USB_DEVICE_GET_SERIAL_NAME_LENGTH. + */ +#if defined USB_DEVICE_GET_SERIAL_NAME_POINTER + static const uint8_t *udc_get_string_serial_name(void) + { + return (const uint8_t *)USB_DEVICE_GET_SERIAL_NAME_POINTER; + } +# define USB_DEVICE_SERIAL_NAME_SIZE \ + USB_DEVICE_GET_SERIAL_NAME_LENGTH +#elif defined USB_DEVICE_SERIAL_NAME + static const uint8_t *udc_get_string_serial_name(void) + { + return (const uint8_t *)USB_DEVICE_SERIAL_NAME; + } +# define USB_DEVICE_SERIAL_NAME_SIZE \ + (sizeof(USB_DEVICE_SERIAL_NAME)-1) +#else +# define USB_DEVICE_SERIAL_NAME_SIZE 0 +#endif + +/** + * \brief USB device string descriptor + * Structure used to transfer ASCII strings to USB String descriptor structure. + */ +struct udc_string_desc_t { + usb_str_desc_t header; + le16_t string[Max(Max(USB_DEVICE_MANUFACTURE_NAME_SIZE, \ + USB_DEVICE_PRODUCT_NAME_SIZE), USB_DEVICE_SERIAL_NAME_SIZE)]; +}; +COMPILER_WORD_ALIGNED +static UDC_DESC_STORAGE struct udc_string_desc_t udc_string_desc = { + .header.bDescriptorType = USB_DT_STRING +}; +//! @} + +usb_iface_desc_t UDC_DESC_STORAGE *udc_get_interface_desc(void) +{ + return udc_ptr_iface; +} + +/** + * \brief Returns a value to check the end of USB Configuration descriptor + * + * \return address after the last byte of USB Configuration descriptor + */ +static usb_conf_desc_t UDC_DESC_STORAGE *udc_get_eof_conf(void) +{ + return (UDC_DESC_STORAGE usb_conf_desc_t *) ((uint8_t *) + udc_ptr_conf->desc + + le16_to_cpu(udc_ptr_conf->desc->wTotalLength)); +} + +#if (0!=USB_DEVICE_MAX_EP) +/** + * \brief Search specific descriptor in global interface descriptor + * + * \param desc Address of interface descriptor + * or previous specific descriptor found + * \param desc_id Descriptor ID to search + * + * \return address of specific descriptor found + * \return NULL if it is the end of global interface descriptor + */ +static usb_conf_desc_t UDC_DESC_STORAGE *udc_next_desc_in_iface(usb_conf_desc_t + UDC_DESC_STORAGE * desc, uint8_t desc_id) +{ + usb_conf_desc_t UDC_DESC_STORAGE *ptr_eof_desc; + + ptr_eof_desc = udc_get_eof_conf(); + // Go to next descriptor + desc = (UDC_DESC_STORAGE usb_conf_desc_t *) ((uint8_t *) desc + + desc->bLength); + // Check the end of configuration descriptor + while (ptr_eof_desc > desc) { + // If new interface descriptor is found, + // then it is the end of the current global interface descriptor + if (USB_DT_INTERFACE == desc->bDescriptorType) { + break; // End of global interface descriptor + } + if (desc_id == desc->bDescriptorType) { + return desc; // Specific descriptor found + } + // Go to next descriptor + desc = (UDC_DESC_STORAGE usb_conf_desc_t *) ((uint8_t *) desc + + desc->bLength); + } + return NULL; // No specific descriptor found +} +#endif + +/** + * \brief Search an interface descriptor + * This routine updates the internal pointer udc_ptr_iface. + * + * \param iface_num Interface number to find in Configuration Descriptor + * \param setting_num Setting number of interface to find + * + * \return 1 if found or 0 if not found + */ +static bool udc_update_iface_desc(uint8_t iface_num, uint8_t setting_num) +{ + usb_conf_desc_t UDC_DESC_STORAGE *ptr_end_desc; + + if (0 == udc_num_configuration) { + return false; + } + + if (iface_num >= udc_ptr_conf->desc->bNumInterfaces) { + return false; + } + + // Start at the beginning of configuration descriptor + udc_ptr_iface = (UDC_DESC_STORAGE usb_iface_desc_t *) + udc_ptr_conf->desc; + + // Check the end of configuration descriptor + ptr_end_desc = udc_get_eof_conf(); + while (ptr_end_desc > + (UDC_DESC_STORAGE usb_conf_desc_t *) udc_ptr_iface) { + if (USB_DT_INTERFACE == udc_ptr_iface->bDescriptorType) { + // A interface descriptor is found + // Check interface and alternate setting number + if ((iface_num == udc_ptr_iface->bInterfaceNumber) && + (setting_num == + udc_ptr_iface->bAlternateSetting)) { + return true; // Interface found + } + } + // Go to next descriptor + udc_ptr_iface = (UDC_DESC_STORAGE usb_iface_desc_t *) ( + (uint8_t *) udc_ptr_iface + + udc_ptr_iface->bLength); + } + return false; // Interface not found +} + +/** + * \brief Disables an usb device interface (UDI) + * This routine call the UDI corresponding to interface number + * + * \param iface_num Interface number to disable + * + * \return 1 if it is done or 0 if interface is not found + */ +static bool udc_iface_disable(uint8_t iface_num) +{ + udi_api_t UDC_DESC_STORAGE *udi_api; + + // Select first alternate setting of the interface + // to update udc_ptr_iface before call iface->getsetting() + if (!udc_update_iface_desc(iface_num, 0)) { + return false; + } + + // Select the interface with the current alternate setting + udi_api = udc_ptr_conf->udi_apis[iface_num]; + +#if (0!=USB_DEVICE_MAX_EP) + if (!udc_update_iface_desc(iface_num, udi_api->getsetting())) { + return false; + } + + // Start at the beginning of interface descriptor + { + usb_ep_desc_t UDC_DESC_STORAGE *ep_desc; + ep_desc = (UDC_DESC_STORAGE usb_ep_desc_t *) udc_ptr_iface; + while (1) { + // Search Endpoint descriptor included in global interface descriptor + ep_desc = (UDC_DESC_STORAGE usb_ep_desc_t *) + udc_next_desc_in_iface((UDC_DESC_STORAGE + usb_conf_desc_t *) + ep_desc, USB_DT_ENDPOINT); + if (NULL == ep_desc) { + break; + } + // Free the endpoint used by the interface + udd_ep_free(ep_desc->bEndpointAddress); + } + } +#endif + + // Disable interface + udi_api->disable(); + return true; +} + +/** + * \brief Enables an usb device interface (UDI) + * This routine calls the UDI corresponding + * to the interface and setting number. + * + * \param iface_num Interface number to enable + * \param setting_num Setting number to enable + * + * \return 1 if it is done or 0 if interface is not found + */ +static bool udc_iface_enable(uint8_t iface_num, uint8_t setting_num) +{ + // Select the interface descriptor + if (!udc_update_iface_desc(iface_num, setting_num)) { + return false; + } + +#if (0!=USB_DEVICE_MAX_EP) + usb_ep_desc_t UDC_DESC_STORAGE *ep_desc; + + // Start at the beginning of the global interface descriptor + ep_desc = (UDC_DESC_STORAGE usb_ep_desc_t *) udc_ptr_iface; + while (1) { + // Search Endpoint descriptor included in the global interface descriptor + ep_desc = (UDC_DESC_STORAGE usb_ep_desc_t *) + udc_next_desc_in_iface((UDC_DESC_STORAGE + usb_conf_desc_t *) ep_desc, + USB_DT_ENDPOINT); + if (NULL == ep_desc) + break; + // Alloc the endpoint used by the interface + if (!udd_ep_alloc(ep_desc->bEndpointAddress, + ep_desc->bmAttributes, + le16_to_cpu + (ep_desc->wMaxPacketSize))) { + return false; + } + } +#endif + // Enable the interface + return udc_ptr_conf->udi_apis[iface_num]->enable(); +} + +/*! \brief Start the USB Device stack + */ +void udc_start(void) +{ + udd_enable(); +} + +/*! \brief Stop the USB Device stack + */ +void udc_stop(void) +{ + udd_disable(); +} + +/** + * \brief Reset the current configuration of the USB device, + * This routines can be called by UDD when a RESET on the USB line occurs. + */ +void udc_reset(void) +{ + uint8_t iface_num; + + if (udc_num_configuration) { + for (iface_num = 0; + iface_num < udc_ptr_conf->desc->bNumInterfaces; + iface_num++) { + udc_iface_disable(iface_num); + } + } + udc_num_configuration = 0; +#if (USB_CONFIG_ATTR_REMOTE_WAKEUP \ + == (USB_DEVICE_ATTR & USB_CONFIG_ATTR_REMOTE_WAKEUP)) + if (CPU_TO_LE16(USB_DEV_STATUS_REMOTEWAKEUP) & udc_device_status) { + // Remote wakeup is enabled then disable it + UDC_REMOTEWAKEUP_DISABLE(); + } +#endif + udc_device_status = +#if (USB_DEVICE_ATTR & USB_CONFIG_ATTR_SELF_POWERED) + CPU_TO_LE16(USB_DEV_STATUS_SELF_POWERED); +#else + CPU_TO_LE16(USB_DEV_STATUS_BUS_POWERED); +#endif +} + +void udc_sof_notify(void) +{ + uint8_t iface_num; + + if (udc_num_configuration) { + for (iface_num = 0; + iface_num < udc_ptr_conf->desc->bNumInterfaces; + iface_num++) { + if (udc_ptr_conf->udi_apis[iface_num]->sof_notify != NULL) { + udc_ptr_conf->udi_apis[iface_num]->sof_notify(); + } + } + } +} + +/** + * \brief Standard device request to get device status + * + * \return true if success + */ +static bool udc_req_std_dev_get_status(void) +{ + if (udd_g_ctrlreq.req.wLength != sizeof(udc_device_status)) { + return false; + } + + udd_set_setup_payload( (uint8_t *) & udc_device_status, + sizeof(udc_device_status)); + return true; +} + +#if (0!=USB_DEVICE_MAX_EP) +/** + * \brief Standard endpoint request to get endpoint status + * + * \return true if success + */ +static bool udc_req_std_ep_get_status(void) +{ + static le16_t udc_ep_status; + + if (udd_g_ctrlreq.req.wLength != sizeof(udc_ep_status)) { + return false; + } + + udc_ep_status = udd_ep_is_halted(udd_g_ctrlreq.req. + wIndex & 0xFF) ? CPU_TO_LE16(USB_EP_STATUS_HALTED) : 0; + + udd_set_setup_payload( (uint8_t *) & udc_ep_status, + sizeof(udc_ep_status)); + return true; +} +#endif + +/** + * \brief Standard device request to change device status + * + * \return true if success + */ +static bool udc_req_std_dev_clear_feature(void) +{ + if (udd_g_ctrlreq.req.wLength) { + return false; + } + + if (udd_g_ctrlreq.req.wValue == USB_DEV_FEATURE_REMOTE_WAKEUP) { + udc_device_status &= CPU_TO_LE16(~USB_DEV_STATUS_REMOTEWAKEUP); +#if (USB_CONFIG_ATTR_REMOTE_WAKEUP \ + == (USB_DEVICE_ATTR & USB_CONFIG_ATTR_REMOTE_WAKEUP)) + UDC_REMOTEWAKEUP_DISABLE(); +#endif + return true; + } + return false; +} + +#if (0!=USB_DEVICE_MAX_EP) +/** + * \brief Standard endpoint request to clear endpoint feature + * + * \return true if success + */ +static bool udc_req_std_ep_clear_feature(void) +{ + if (udd_g_ctrlreq.req.wLength) { + return false; + } + + if (udd_g_ctrlreq.req.wValue == USB_EP_FEATURE_HALT) { + return udd_ep_clear_halt(udd_g_ctrlreq.req.wIndex & 0xFF); + } + return false; +} +#endif + +/** + * \brief Standard device request to set a feature + * + * \return true if success + */ +static bool udc_req_std_dev_set_feature(void) +{ + if (udd_g_ctrlreq.req.wLength) { + return false; + } + + switch (udd_g_ctrlreq.req.wValue) { + + case USB_DEV_FEATURE_REMOTE_WAKEUP: +#if (USB_CONFIG_ATTR_REMOTE_WAKEUP \ + == (USB_DEVICE_ATTR & USB_CONFIG_ATTR_REMOTE_WAKEUP)) + udc_device_status |= CPU_TO_LE16(USB_DEV_STATUS_REMOTEWAKEUP); + UDC_REMOTEWAKEUP_ENABLE(); + return true; +#else + return false; +#endif + +#ifdef USB_DEVICE_HS_SUPPORT + case USB_DEV_FEATURE_TEST_MODE: + if (!udd_is_high_speed()) { + break; + } + if (udd_g_ctrlreq.req.wIndex & 0xff) { + break; + } + // Unconfigure the device, terminating all ongoing requests + udc_reset(); + switch ((udd_g_ctrlreq.req.wIndex >> 8) & 0xFF) { + case USB_DEV_TEST_MODE_J: + udd_g_ctrlreq.callback = udd_test_mode_j; + return true; + + case USB_DEV_TEST_MODE_K: + udd_g_ctrlreq.callback = udd_test_mode_k; + return true; + + case USB_DEV_TEST_MODE_SE0_NAK: + udd_g_ctrlreq.callback = udd_test_mode_se0_nak; + return true; + + case USB_DEV_TEST_MODE_PACKET: + udd_g_ctrlreq.callback = udd_test_mode_packet; + return true; + + case USB_DEV_TEST_MODE_FORCE_ENABLE: // Only for downstream facing hub ports + default: + break; + } + break; +#endif + default: + break; + } + return false; +} + +/** + * \brief Standard endpoint request to halt an endpoint + * + * \return true if success + */ +#if (0!=USB_DEVICE_MAX_EP) +static bool udc_req_std_epset_feature(void) +{ + if (udd_g_ctrlreq.req.wLength) { + return false; + } + if (udd_g_ctrlreq.req.wValue == USB_EP_FEATURE_HALT) { + return udd_ep_set_halt(udd_g_ctrlreq.req.wIndex & 0xFF); + } + return false; +} +#endif + +/** + * \brief Change the address of device + * Callback called at the end of request set address + */ +static void udc_valid_address(void) +{ + udd_set_address(udd_g_ctrlreq.req.wValue & 0x7F); +} + +/** + * \brief Standard device request to set device address + * + * \return true if success + */ +static bool udc_req_std_dev_set_address(void) +{ + if (udd_g_ctrlreq.req.wLength) { + return false; + } + + // The address must be changed at the end of setup request after the handshake + // then we use a callback to change address + udd_g_ctrlreq.callback = udc_valid_address; + return true; +} + +/** + * \brief Standard device request to get device string descriptor + * + * \return true if success + */ +static bool udc_req_std_dev_get_str_desc(void) +{ + uint8_t i; + const uint8_t *str; + uint8_t str_length = 0; + + // Link payload pointer to the string corresponding at request + switch (udd_g_ctrlreq.req.wValue & 0xff) { + case 0: + udd_set_setup_payload((uint8_t *) &udc_string_desc_languageid, + sizeof(udc_string_desc_languageid)); + break; + +#ifdef USB_DEVICE_MANUFACTURE_NAME + case 1: + str_length = USB_DEVICE_MANUFACTURE_NAME_SIZE; + str = udc_string_manufacturer_name; + break; +#endif +#ifdef USB_DEVICE_PRODUCT_NAME + case 2: + str_length = USB_DEVICE_PRODUCT_NAME_SIZE; + str = udc_string_product_name; + break; +#endif +#if defined USB_DEVICE_SERIAL_NAME || defined USB_DEVICE_GET_SERIAL_NAME_POINTER + case 3: + str_length = USB_DEVICE_SERIAL_NAME_SIZE; + str = udc_get_string_serial_name(); + break; +#endif + default: +#ifdef UDC_GET_EXTRA_STRING + if (UDC_GET_EXTRA_STRING()) { + break; + } +#endif + return false; + } + + if (str_length) { + for(i = 0; i < str_length; i++) { + udc_string_desc.string[i] = cpu_to_le16((le16_t)str[i]); + } + + udc_string_desc.header.bLength = 2 + (str_length) * 2; + udd_set_setup_payload( + (uint8_t *) &udc_string_desc, + udc_string_desc.header.bLength); + } + + return true; +} + +/** + * \brief Standard device request to get descriptors about USB device + * + * \return true if success + */ +static bool udc_req_std_dev_get_descriptor(void) +{ + uint8_t conf_num; + + conf_num = udd_g_ctrlreq.req.wValue & 0xff; + + // Check descriptor ID + switch ((uint8_t) (udd_g_ctrlreq.req.wValue >> 8)) { + case USB_DT_DEVICE: + // Device descriptor requested +#ifdef USB_DEVICE_HS_SUPPORT + if (!udd_is_high_speed()) { + udd_set_setup_payload( + (uint8_t *) udc_config.confdev_hs, + udc_config.confdev_hs->bLength); + } else +#endif + { + udd_set_setup_payload( + (uint8_t *) udc_config.confdev_lsfs, + udc_config.confdev_lsfs->bLength); + } + break; + + case USB_DT_CONFIGURATION: + // Configuration descriptor requested +#ifdef USB_DEVICE_HS_SUPPORT + if (udd_is_high_speed()) { + // HS descriptor + if (conf_num >= udc_config.confdev_hs-> + bNumConfigurations) { + return false; + } + udd_set_setup_payload( + (uint8_t *)udc_config.conf_hs[conf_num].desc, + le16_to_cpu(udc_config.conf_hs[conf_num].desc->wTotalLength)); + } else +#endif + { + // FS descriptor + if (conf_num >= udc_config.confdev_lsfs-> + bNumConfigurations) { + return false; + } + udd_set_setup_payload( + (uint8_t *)udc_config.conf_lsfs[conf_num].desc, + le16_to_cpu(udc_config.conf_lsfs[conf_num].desc->wTotalLength)); + } + ((usb_conf_desc_t *) udd_g_ctrlreq.payload)->bDescriptorType = + USB_DT_CONFIGURATION; + break; + +#ifdef USB_DEVICE_HS_SUPPORT + case USB_DT_DEVICE_QUALIFIER: + // Device qualifier descriptor requested + udd_set_setup_payload( (uint8_t *) udc_config.qualifier, + udc_config.qualifier->bLength); + break; + + case USB_DT_OTHER_SPEED_CONFIGURATION: + // Other configuration descriptor requested + if (!udd_is_high_speed()) { + // HS descriptor + if (conf_num >= udc_config.confdev_hs-> + bNumConfigurations) { + return false; + } + udd_set_setup_payload( + (uint8_t *)udc_config.conf_hs[conf_num].desc, + le16_to_cpu(udc_config.conf_hs[conf_num].desc->wTotalLength)); + } else { + // FS descriptor + if (conf_num >= udc_config.confdev_lsfs-> + bNumConfigurations) { + return false; + } + udd_set_setup_payload( + (uint8_t *)udc_config.conf_lsfs[conf_num].desc, + le16_to_cpu(udc_config.conf_lsfs[conf_num].desc->wTotalLength)); + } + ((usb_conf_desc_t *) udd_g_ctrlreq.payload)->bDescriptorType = + USB_DT_OTHER_SPEED_CONFIGURATION; + break; +#endif + + case USB_DT_STRING: + // String descriptor requested + if (!udc_req_std_dev_get_str_desc()) { + return false; + } + break; + + default: + // Unknown descriptor requested + return false; + } + // if the descriptor is larger than length requested, then reduce it + if (udd_g_ctrlreq.req.wLength < udd_g_ctrlreq.payload_size) { + udd_g_ctrlreq.payload_size = udd_g_ctrlreq.req.wLength; + } + return true; +} + +/** + * \brief Standard device request to get configuration number + * + * \return true if success + */ +static bool udc_req_std_dev_get_configuration(void) +{ + if (udd_g_ctrlreq.req.wLength != 1) { + return false; + } + + udd_set_setup_payload(&udc_num_configuration,1); + return true; +} + +/** + * \brief Standard device request to enable a configuration + * + * \return true if success + */ +static bool udc_req_std_dev_set_configuration(void) +{ + uint8_t iface_num; + + // Check request length + if (udd_g_ctrlreq.req.wLength) { + return false; + } + // Authorize configuration only if the address is valid + if (!udd_getaddress()) { + return false; + } + // Check the configuration number requested +#ifdef USB_DEVICE_HS_SUPPORT + if (udd_is_high_speed()) { + // HS descriptor + if ((udd_g_ctrlreq.req.wValue & 0xFF) > + udc_config.confdev_hs->bNumConfigurations) { + return false; + } + } else +#endif + { + // FS descriptor + if ((udd_g_ctrlreq.req.wValue & 0xFF) > + udc_config.confdev_lsfs->bNumConfigurations) { + return false; + } + } + + // Reset current configuration + udc_reset(); + + // Enable new configuration + udc_num_configuration = udd_g_ctrlreq.req.wValue & 0xFF; + if (udc_num_configuration == 0) { + return true; // Default empty configuration requested + } + // Update pointer of the configuration descriptor +#ifdef USB_DEVICE_HS_SUPPORT + if (udd_is_high_speed()) { + // HS descriptor + udc_ptr_conf = &udc_config.conf_hs[udc_num_configuration - 1]; + } else +#endif + { + // FS descriptor + udc_ptr_conf = &udc_config.conf_lsfs[udc_num_configuration - 1]; + } + // Enable all interfaces of the selected configuration + for (iface_num = 0; iface_num < udc_ptr_conf->desc->bNumInterfaces; + iface_num++) { + if (!udc_iface_enable(iface_num, 0)) { + return false; + } + } + return true; +} + +/** + * \brief Standard interface request + * to get the alternate setting number of an interface + * + * \return true if success + */ +static bool udc_req_std_iface_get_setting(void) +{ + static uint8_t udc_iface_setting; + uint8_t iface_num; + udi_api_t UDC_DESC_STORAGE *udi_api; + + if (udd_g_ctrlreq.req.wLength != 1) { + return false; // Error in request + } + if (!udc_num_configuration) { + return false; // The device is not is configured state yet + } + + // Check the interface number included in the request + iface_num = udd_g_ctrlreq.req.wIndex & 0xFF; + if (iface_num >= udc_ptr_conf->desc->bNumInterfaces) { + return false; + } + + // Select first alternate setting of the interface to update udc_ptr_iface + // before call iface->getsetting() + if (!udc_update_iface_desc(iface_num, 0)) { + return false; + } + // Get alternate setting from UDI + udi_api = udc_ptr_conf->udi_apis[iface_num]; + udc_iface_setting = udi_api->getsetting(); + + // Link value to payload pointer of request + udd_set_setup_payload(&udc_iface_setting,1); + return true; +} + +/** + * \brief Standard interface request + * to set an alternate setting of an interface + * + * \return true if success + */ +static bool udc_req_std_iface_set_setting(void) +{ + uint8_t iface_num, setting_num; + + if (udd_g_ctrlreq.req.wLength) { + return false; // Error in request + } + if (!udc_num_configuration) { + return false; // The device is not is configured state yet + } + + iface_num = udd_g_ctrlreq.req.wIndex & 0xFF; + setting_num = udd_g_ctrlreq.req.wValue & 0xFF; + + // Disable current setting + if (!udc_iface_disable(iface_num)) { + return false; + } + + // Enable new setting + return udc_iface_enable(iface_num, setting_num); +} + +/** + * \brief Main routine to manage the standard USB SETUP request + * + * \return true if the request is supported + */ +static bool udc_reqstd(void) +{ + if (Udd_setup_is_in()) { + // GET Standard Requests + if (udd_g_ctrlreq.req.wLength == 0) { + return false; // Error for USB host + } + + if (USB_REQ_RECIP_DEVICE == Udd_setup_recipient()) { + // Standard Get Device request + switch (udd_g_ctrlreq.req.bRequest) { + case USB_REQ_GET_STATUS: + return udc_req_std_dev_get_status(); + case USB_REQ_GET_DESCRIPTOR: + return udc_req_std_dev_get_descriptor(); + case USB_REQ_GET_CONFIGURATION: + return udc_req_std_dev_get_configuration(); + default: + break; + } + } + + if (USB_REQ_RECIP_INTERFACE == Udd_setup_recipient()) { + // Standard Get Interface request + switch (udd_g_ctrlreq.req.bRequest) { + case USB_REQ_GET_INTERFACE: + return udc_req_std_iface_get_setting(); + default: + break; + } + } +#if (0!=USB_DEVICE_MAX_EP) + if (USB_REQ_RECIP_ENDPOINT == Udd_setup_recipient()) { + // Standard Get Endpoint request + switch (udd_g_ctrlreq.req.bRequest) { + case USB_REQ_GET_STATUS: + return udc_req_std_ep_get_status(); + default: + break; + } + } +#endif + } else { + // SET Standard Requests + if (USB_REQ_RECIP_DEVICE == Udd_setup_recipient()) { + // Standard Set Device request + switch (udd_g_ctrlreq.req.bRequest) { + case USB_REQ_SET_ADDRESS: + return udc_req_std_dev_set_address(); + case USB_REQ_CLEAR_FEATURE: + return udc_req_std_dev_clear_feature(); + case USB_REQ_SET_FEATURE: + return udc_req_std_dev_set_feature(); + case USB_REQ_SET_CONFIGURATION: + return udc_req_std_dev_set_configuration(); + case USB_REQ_SET_DESCRIPTOR: + /* Not supported (defined as optional by the USB 2.0 spec) */ + break; + default: + break; + } + } + + if (USB_REQ_RECIP_INTERFACE == Udd_setup_recipient()) { + // Standard Set Interface request + switch (udd_g_ctrlreq.req.bRequest) { + case USB_REQ_SET_INTERFACE: + return udc_req_std_iface_set_setting(); + default: + break; + } + } +#if (0!=USB_DEVICE_MAX_EP) + if (USB_REQ_RECIP_ENDPOINT == Udd_setup_recipient()) { + // Standard Set Endpoint request + switch (udd_g_ctrlreq.req.bRequest) { + case USB_REQ_CLEAR_FEATURE: + return udc_req_std_ep_clear_feature(); + case USB_REQ_SET_FEATURE: + return udc_req_std_epset_feature(); + default: + break; + } + } +#endif + } + return false; +} + +/** + * \brief Send the SETUP interface request to UDI + * + * \return true if the request is supported + */ +static bool udc_req_iface(void) +{ + uint8_t iface_num; + udi_api_t UDC_DESC_STORAGE *udi_api; + + if (0 == udc_num_configuration) { + return false; // The device is not is configured state yet + } + // Check interface number + iface_num = udd_g_ctrlreq.req.wIndex & 0xFF; + if (iface_num >= udc_ptr_conf->desc->bNumInterfaces) { + return false; + } + + //* To update udc_ptr_iface with the selected interface in request + // Select first alternate setting of interface to update udc_ptr_iface + // before calling udi_api->getsetting() + if (!udc_update_iface_desc(iface_num, 0)) { + return false; + } + // Select the interface with the current alternate setting + udi_api = udc_ptr_conf->udi_apis[iface_num]; + if (!udc_update_iface_desc(iface_num, udi_api->getsetting())) { + return false; + } + + // Send the SETUP request to the UDI corresponding to the interface number + return udi_api->setup(); +} + +/** + * \brief Main routine to manage the USB SETUP request. + * + * This function parses a USB SETUP request and submits an appropriate + * response back to the host or, in the case of SETUP OUT requests + * with data, sets up a buffer for receiving the data payload. + * + * The main standard requests defined by the USB 2.0 standard are handled + * internally. The interface requests are sent to UDI, and the specific request + * sent to a specific application callback. + * + * \return true if the request is supported, else the request is stalled by UDD + */ +bool udc_process_setup(void) +{ + // By default no data (receive/send) and no callbacks registered + udd_g_ctrlreq.payload_size = 0; + udd_g_ctrlreq.callback = NULL; + udd_g_ctrlreq.over_under_run = NULL; + + if (Udd_setup_is_in()) { + if (udd_g_ctrlreq.req.wLength == 0) { + return false; // Error from USB host + } + } + + // If standard request then try to decode it in UDC + if (Udd_setup_type() == USB_REQ_TYPE_STANDARD) { + if (udc_reqstd()) { + return true; + } + } + + // If interface request then try to decode it in UDI + if (Udd_setup_recipient() == USB_REQ_RECIP_INTERFACE) { + if (udc_req_iface()) { + return true; + } + } + + // Here SETUP request unknown by UDC and UDIs +#ifdef USB_DEVICE_SPECIFIC_REQUEST + // Try to decode it in specific callback + return USB_DEVICE_SPECIFIC_REQUEST(); // Ex: Vendor request,... +#else + return false; +#endif +} + +//! @} diff --git a/DSTAT1/src/asf/common/services/usb/udc/udc.h b/DSTAT1/src/asf/common/services/usb/udc/udc.h new file mode 100644 index 0000000000000000000000000000000000000000..488d1d2b5c026ede0e5373ea58e7557273ab73a4 --- /dev/null +++ b/DSTAT1/src/asf/common/services/usb/udc/udc.h @@ -0,0 +1,242 @@ +/** + * \file + * + * \brief Interface of the USB Device Controller (UDC) + * + * Copyright (c) 2009 - 2012 Atmel Corporation. All rights reserved. + * + * \asf_license_start + * + * 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. The name of Atmel may not be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * 4. This software may only be redistributed and used in connection with an + * Atmel microcontroller product. + * + * THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE + * EXPRESSLY AND SPECIFICALLY DISCLAIMED. IN NO EVENT SHALL ATMEL 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. + * + * \asf_license_stop + * + */ + +#ifndef _UDC_H_ +#define _UDC_H_ + +#include "conf_usb.h" +#include "usb_protocol.h" +#include "udc_desc.h" +#include "udd.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * \ingroup usb_device_group + * \defgroup udc_group USB Device Controller (UDC) + * + * The UDC provides a high-level abstraction of the usb device. + * You can use these functions to control the main device state + * (start/attach/wakeup). + * + * \section USB_DEVICE_CONF USB Device Custom configuration + * The following USB Device configuration must be included in the conf_usb.h + * file of the application. + * + * USB_DEVICE_VENDOR_ID (Word)
+ * Vendor ID provided by USB org (ATMEL 0x03EB). + * + * USB_DEVICE_PRODUCT_ID (Word)
+ * Product ID (Referenced in usb_atmel.h). + * + * USB_DEVICE_MAJOR_VERSION (Byte)
+ * Major version of the device + * + * USB_DEVICE_MINOR_VERSION (Byte)
+ * Minor version of the device + * + * USB_DEVICE_MANUFACTURE_NAME (string)
+ * ASCII name for the manufacture + * + * USB_DEVICE_PRODUCT_NAME (string)
+ * ASCII name for the product + * + * USB_DEVICE_SERIAL_NAME (string)
+ * ASCII name to enable and set a serial number + * + * USB_DEVICE_POWER (Numeric)
+ * (unit mA) Maximum device power + * + * USB_DEVICE_ATTR (Byte)
+ * USB attributes available: + * - USB_CONFIG_ATTR_SELF_POWERED + * - USB_CONFIG_ATTR_REMOTE_WAKEUP + * Note: if remote wake enabled then defines remotewakeup callbacks, + * see Table 5-2. External API from UDC - Callback + * + * USB_DEVICE_LOW_SPEED (Only defined)
+ * Force the USB Device to run in low speed + * + * USB_DEVICE_HS_SUPPORT (Only defined)
+ * Authorize the USB Device to run in high speed + * + * USB_DEVICE_MAX_EP (Byte)
+ * Define the maximum endpoint number used by the USB Device.
+ * This one is already defined in UDI default configuration. + * Ex: + * - When endpoint control 0x00, endpoint 0x01 and + * endpoint 0x82 is used then USB_DEVICE_MAX_EP=2 + * - When only endpoint control 0x00 is used then USB_DEVICE_MAX_EP=0 + * - When endpoint 0x01 and endpoint 0x81 is used then USB_DEVICE_MAX_EP=1
+ * (configuration not possible on USBB interface) + * @{ + */ + +/** + * \brief Authorizes the VBUS event + * + * \return true, if the VBUS monitoring is possible. + * + * \section udc_vbus_monitoring VBus monitoring used cases + * + * The VBus monitoring is used only for USB SELF Power application. + * + * - No custom implementation \n + * // Authorize VBUS monitoring \n + * if (!udc_include_vbus_monitoring()) { \n + * // VBUS monitoring is not available on this product \n + * // thereby VBUS has to be considered as present \n + * // Attach USB Device \n + * udc_attach(); \n + * } \n + * + * - Add custom VBUS monitoring \n + * // Authorize VBUS monitoring \n + * if (!udc_include_vbus_monitoring()) { \n + * // Implement custom VBUS monitoring via GPIO or other \n + * } \n + * Event_VBUS_present() // VBUS interrupt or GPIO interrupt or other \n + * { \n + * // Attach USB Device \n + * udc_attach(); \n + * } \n + * + * - Case of battery charging \n + * Event VBUS present() // VBUS interrupt or GPIO interrupt or .. \n + * { \n + * // Authorize battery charging, but wait key press to start USB. \n + * } \n + * Event Key press() \n + * { \n + * // Stop batteries charging \n + * // Start USB \n + * udc_attach(); \n + * } \n + */ +static inline bool udc_include_vbus_monitoring(void) +{ + return udd_include_vbus_monitoring(); +} + +/*! \brief Start the USB Device stack + */ +void udc_start(void); + +/*! \brief Stop the USB Device stack + */ +void udc_stop(void); + +/** + * \brief Attach device to the bus when possible + * + * \warning If a VBus control is included in driver, + * then it will attach device when an acceptable Vbus + * level from the host is detected. + */ +static inline void udc_attach(void) +{ + udd_attach(); +} + + +/** + * \brief Detaches the device from the bus + * + * The driver must remove pull-up on USB line D- or D+. + */ +static inline void udc_detach(void) +{ + udd_detach(); +} + + +/*! \brief The USB driver sends a resume signal called \e "Upstream Resume" + */ +static inline void udc_wakeup(void) +{ + udd_send_wake_up(); +} + + +/** + * \brief Returns a pointer on the current interface descriptor + * + * \return pointer on the current interface descriptor. + */ +usb_iface_desc_t UDC_DESC_STORAGE *udc_get_interface_desc(void); + +//@} + +/** + * \ingroup usb_group + * \defgroup usb_device_group USB Stack Devices + * + * This module includes USB Stack Device implementation. + * The stack is divided in three parts: + * - USB Device Controller (UDC) provides USB chapter 9 compliance + * - USB Device Interface (UDI) provides USB Class compliance + * - USB Device Driver (UDD) provides USB Driver for each AVR product + + * Many USB Device applications can be implemented on Atmel MCU. + * Atmel provides many application notes for different applications: + * - AVR4900, provides general information about Device Stack + * - AVR4901, explains how to create a new class + * - AVR4902, explains how to create a composite device + * - AVR49xx, all device classes provided in ASF have an application note + * + * A basic USB knowledge is required to understand the USB Device + * Class application notes (HID,MS,CDC,PHDC,...). + * Then, to create an USB device with + * only one class provided by ASF, refer directly to the application note + * corresponding to this USB class. The USB Device application note for + * New Class and Composite is dedicated to advanced USB users. + * + * @{ + */ + +//! @} + +#ifdef __cplusplus +} +#endif +#endif // _UDC_H_ diff --git a/DSTAT1/src/asf/common/services/usb/udc/udc_desc.h b/DSTAT1/src/asf/common/services/usb/udc/udc_desc.h new file mode 100644 index 0000000000000000000000000000000000000000..506401b2162fe0d6e6fff51ed104409ed4c06fb8 --- /dev/null +++ b/DSTAT1/src/asf/common/services/usb/udc/udc_desc.h @@ -0,0 +1,129 @@ +/** + * \file + * + * \brief Common API for USB Device Interface + * + * Copyright (c) 2009 Atmel Corporation. All rights reserved. + * + * \asf_license_start + * + * 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. The name of Atmel may not be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * 4. This software may only be redistributed and used in connection with an + * Atmel microcontroller product. + * + * THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE + * EXPRESSLY AND SPECIFICALLY DISCLAIMED. IN NO EVENT SHALL ATMEL 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. + * + * \asf_license_stop + * + */ + +#ifndef _UDC_DESC_H_ +#define _UDC_DESC_H_ + +#include "conf_usb.h" +#include "usb_protocol.h" +#include "udi.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * \ingroup udc_group + * \defgroup udc_desc_group USB Device Descriptor + * + * @{ + */ + +/** + * \brief Defines the memory's location of USB descriptors + * + * By default the Descriptor is stored in RAM + * (UDC_DESC_STORAGE is defined empty). + * + * If you have need to free RAM space, + * it is possible to put descriptor in flash in following case: + * - USB driver authorize flash transfer (USBB on UC3 and USB on Mega) + * - USB Device is not high speed (UDC no need to change USB descriptors) + * + * For UC3 application used "const". + * + * For Mega application used "code". + */ +#define UDC_DESC_STORAGE + // Descriptor storage in internal RAM +#if (defined UDC_DATA_USE_HRAM_SUPPORT) +# if defined(__GNUC__) +# define UDC_DATA(x) COMPILER_WORD_ALIGNED __attribute__((__section__(".data_hram0"))) +# define UDC_BSS(x) COMPILER_ALIGNED(x) __attribute__((__section__(".bss_hram0"))) +# elif defined(__ICCAVR32__) +# define UDC_DATA(x) COMPILER_ALIGNED(x) __data32 +# define UDC_BSS(x) COMPILER_ALIGNED(x) __data32 +# endif +#else +# define UDC_DATA(x) COMPILER_ALIGNED(x) +# define UDC_BSS(x) COMPILER_ALIGNED(x) +#endif + + + +/** + * \brief Configuration descriptor and UDI link for one USB speed + */ +typedef struct { + //! USB configuration descriptor + usb_conf_desc_t UDC_DESC_STORAGE *desc; + //! Array of UDI API pointer + udi_api_t UDC_DESC_STORAGE *UDC_DESC_STORAGE * udi_apis; +} udc_config_speed_t; + + +/** + * \brief All information about the USB Device + */ +typedef struct { + //! USB device descriptor for low or full speed + usb_dev_desc_t UDC_DESC_STORAGE *confdev_lsfs; + //! USB configuration descriptor and UDI API pointers for low or full speed + udc_config_speed_t UDC_DESC_STORAGE *conf_lsfs; +#ifdef USB_DEVICE_HS_SUPPORT + //! USB device descriptor for high speed + usb_dev_desc_t UDC_DESC_STORAGE *confdev_hs; + //! USB device qualifier, only use in high speed mode + usb_dev_qual_desc_t UDC_DESC_STORAGE *qualifier; + //! USB configuration descriptor and UDI API pointers for high speed + udc_config_speed_t UDC_DESC_STORAGE *conf_hs; +#endif +} udc_config_t; + +//! Global variables of USB Device Descriptor and UDI links +extern UDC_DESC_STORAGE udc_config_t udc_config; + +//@} + +#ifdef __cplusplus +} +#endif +#endif // _UDC_DESC_H_ diff --git a/DSTAT1/src/asf/common/services/usb/udc/udd.h b/DSTAT1/src/asf/common/services/usb/udc/udd.h new file mode 100644 index 0000000000000000000000000000000000000000..53d791af656afb27a1d1d48049f64e5f2a898726 --- /dev/null +++ b/DSTAT1/src/asf/common/services/usb/udc/udd.h @@ -0,0 +1,390 @@ +/** + * \file + * + * \brief Common API for USB Device Drivers (UDD) + * + * Copyright (c) 2009 - 2012 Atmel Corporation. All rights reserved. + * + * \asf_license_start + * + * 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. The name of Atmel may not be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * 4. This software may only be redistributed and used in connection with an + * Atmel microcontroller product. + * + * THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE + * EXPRESSLY AND SPECIFICALLY DISCLAIMED. IN NO EVENT SHALL ATMEL 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. + * + * \asf_license_stop + * + */ + +#ifndef _UDD_H_ +#define _UDD_H_ + +#include "usb_protocol.h" +#include "udc_desc.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * \ingroup usb_device_group + * \defgroup udd_group USB Device Driver (UDD) + * + * The UDD driver provides a low-level abstraction of the device + * controller hardware. Most events coming from the hardware such as + * interrupts, which may cause the UDD to call into the UDC and UDI. + * + * @{ + */ + +//! \brief Endpoint identifier +typedef uint8_t udd_ep_id_t; + +//! \brief Endpoint transfer status +//! Returned in parameters of callback register via udd_ep_run routine. +typedef enum { + UDD_EP_TRANSFER_OK = 0, + UDD_EP_TRANSFER_ABORT = 1, +} udd_ep_status_t; + +/** + * \brief Global variable to give and record information of the setup request management + * + * This global variable allows to decode and response a setup request. + * It can be updated by udc_process_setup() from UDC or *setup() from UDIs. + */ +typedef struct { + //! Data received in USB SETUP packet + //! Note: The swap of "req.wValues" from uin16_t to le16_t is done by UDD. + usb_setup_req_t req; + + //! Point to buffer to send or fill with data following SETUP packet + uint8_t *payload; + + //! Size of buffer to send or fill, and content the number of byte transfered + uint16_t payload_size; + + //! Callback called after reception of ZLP from setup request + void (*callback) (void); + + //! Callback called when the buffer given (.payload) is full or empty. + //! This one return false to abort data transfer, or true with a new buffer in .payload. + bool(*over_under_run) (void); +} udd_ctrl_request_t; +extern udd_ctrl_request_t udd_g_ctrlreq; + +//! Return true if the setup request \a udd_g_ctrlreq indicates IN data transfer +#define Udd_setup_is_in() \ + (USB_REQ_DIR_IN == (udd_g_ctrlreq.req.bmRequestType & USB_REQ_DIR_MASK)) + +//! Return true if the setup request \a udd_g_ctrlreq indicates OUT data transfer +#define Udd_setup_is_out() \ + (USB_REQ_DIR_OUT == (udd_g_ctrlreq.req.bmRequestType & USB_REQ_DIR_MASK)) + +//! Return the type of the SETUP request \a udd_g_ctrlreq. \see usb_reqtype. +#define Udd_setup_type() \ + (udd_g_ctrlreq.req.bmRequestType & USB_REQ_TYPE_MASK) + +//! Return the recipient of the SETUP request \a udd_g_ctrlreq. \see usb_recipient +#define Udd_setup_recipient() \ + (udd_g_ctrlreq.req.bmRequestType & USB_REQ_RECIP_MASK) + +/** + * \brief End of halt callback function type. + * Registered by routine udd_ep_wait_stall_clear() + * Callback called when endpoint stall is cleared. + */ +typedef void (*udd_callback_halt_cleared_t) (void); + +/** + * \brief End of transfer callback function type. + * Registered by routine udd_ep_run() + * Callback called by USB interrupt after data transfer or abort (reset,...). + * + * \param status UDD_EP_TRANSFER_OK, if transfer is complete + * \param status UDD_EP_TRANSFER_ABORT, if transfer is aborted + * \param n number of data transfered + */ +typedef void (*udd_callback_trans_t) (udd_ep_status_t status, + iram_size_t nb_transfered); + +/** + * \brief Authorizes the VBUS event + * + * \return true, if the VBUS monitoring is possible. + */ +bool udd_include_vbus_monitoring(void); + +/** + * \brief Enables the USB Device mode + */ +void udd_enable(void); + +/** + * \brief Disables the USB Device mode + */ +void udd_disable(void); + +/** + * \brief Attach device to the bus when possible + * + * \warning If a VBus control is included in driver, + * then it will attach device when an acceptable Vbus + * level from the host is detected. + */ +void udd_attach(void); + +/** + * \brief Detaches the device from the bus + * + * The driver must remove pull-up on USB line D- or D+. + */ +void udd_detach(void); + +/** + * \brief Test whether the USB Device Controller is running at high + * speed or not. + * + * \return \c true if the Device is running at high speed mode, otherwise \c false. + */ +bool udd_is_high_speed(void); + +/** + * \brief Changes the USB address of device + * + * \param address New USB address + */ +void udd_set_address(uint8_t address); + +/** + * \brief Returns the USB address of device + * + * \return USB address + */ +uint8_t udd_getaddress(void); + +/** + * \brief Returns the current start of frame number + * + * \return current start of frame number. + */ +uint16_t udd_get_frame_number(void); + +/** + * \brief Returns the current micro start of frame number + * + * \return current micro start of frame number required in high speed mode. + */ +uint16_t udd_get_micro_frame_number(void); + +/*! \brief The USB driver sends a resume signal called Upstream Resume + */ +void udd_send_wake_up(void); + +/** + * \brief Load setup payload + * + * \param payload Pointer on payload + * \param payload_size Size of payload + */ +void udd_set_setup_payload( uint8_t *payload, uint16_t payload_size ); + + +/** + * \name Endpoint Management + * + * The following functions allow drivers to create and remove + * endpoints, as well as set, clear and query their "halted" and + * "wedged" states. + */ +//@{ + +#if (USB_DEVICE_MAX_EP != 0) + +/** + * \brief Configures and enables an endpoint + * + * \param ep Endpoint number including direction (USB_EP_DIR_IN/USB_EP_DIR_OUT). + * \param bmAttributes Attributes of endpoint declared in the descriptor. + * \param MaxEndpointSize Endpoint maximum size + * + * \return \c 1 if the endpoint is enabled, otherwise \c 0. + */ +bool udd_ep_alloc(udd_ep_id_t ep, uint8_t bmAttributes, + uint16_t MaxEndpointSize); + +/** + * \brief Disables an endpoint + * + * \param ep Endpoint number including direction (USB_EP_DIR_IN/USB_EP_DIR_OUT). + */ +void udd_ep_free(udd_ep_id_t ep); + +/** + * \brief Check if the endpoint \a ep is halted. + * + * \param ep The ID of the endpoint to check. + * + * \return \c 1 if \a ep is halted, otherwise \c 0. + */ +bool udd_ep_is_halted(udd_ep_id_t ep); + +/** + * \brief Set the halted state of the endpoint \a ep + * + * After calling this function, any transaction on \a ep will result + * in a STALL handshake being sent. Any pending transactions will be + * performed first, however. + * + * \param ep The ID of the endpoint to be halted + * + * \return \c 1 if \a ep is halted, otherwise \c 0. + */ +bool udd_ep_set_halt(udd_ep_id_t ep); + +/** + * \brief Clear the halted state of the endpoint \a ep + * + * After calling this function, any transaction on \a ep will + * be handled normally, i.e. a STALL handshake will not be sent, and + * the data toggle sequence will start at DATA0. + * + * \param ep The ID of the endpoint to be un-halted + * + * \return \c 1 if function was successfully done, otherwise \c 0. + */ +bool udd_ep_clear_halt(udd_ep_id_t ep); + +/** + * \brief Registers a callback to call when endpoint halt is cleared + * + * \param ep The ID of the endpoint to use + * \param callback NULL or function to call when endpoint halt is cleared + * + * \warning if the endpoint is not halted then the \a callback is called immediately. + * + * \return \c 1 if the register is accepted, otherwise \c 0. + */ +bool udd_ep_wait_stall_clear(udd_ep_id_t ep, + udd_callback_halt_cleared_t callback); + +/** + * \brief Allows to receive or send data on an endpoint + * + * The driver uses a specific DMA USB to transfer data + * from internal RAM to endpoint, if this one is available. + * When the transfer is finished or aborted (stall, reset, ...), the \a callback is called. + * The \a callback returns the transfer status and eventually the number of byte transfered. + * Note: The control endpoint is not authorized. + * + * \param ep The ID of the endpoint to use + * \param b_shortpacket Enabled automatic short packet + * \param buf Buffer on Internal RAM to send or fill. + * It must be align, then use COMPILER_WORD_ALIGNED. + * \param buf_size Buffer size to send or fill + * \param callback NULL or function to call at the end of transfer + * + * \warning About \a b_shortpacket, for IN endpoint it means that a short packet + * (or a Zero Length Packet) will be sent to the USB line to properly close the usb + * transfer at the end of the data transfer. + * For Bulk and Interrupt OUT endpoint, it will automatically stop the transfer + * at the end of the data transfer (received short packet). + * + * \return \c 1 if function was successfully done, otherwise \c 0. + */ +bool udd_ep_run(udd_ep_id_t ep, bool b_shortpacket, + uint8_t * buf, iram_size_t buf_size, + udd_callback_trans_t callback); +/** + * \brief Aborts transfer on going on endpoint + * + * If a transfer is on going, then it is stopped and + * the callback registered is called to signal the end of transfer. + * Note: The control endpoint is not authorized. + * + * \param ep Endpoint to abort + */ +void udd_ep_abort(udd_ep_id_t ep); + +#endif + +//@} + + +/** + * \name High speed test mode management + * + * The following functions allow the device to jump to a specific test mode required in high speed mode. + */ +//@{ +void udd_test_mode_j(void); +void udd_test_mode_k(void); +void udd_test_mode_se0_nak(void); +void udd_test_mode_packet(void); +//@} + + +/** + * \name UDC callbacks to provide for UDD + * + * The following callbacks are used by UDD. + */ +//@{ + +/** + * \brief Decodes and manages a setup request + * + * The driver call it when a SETUP packet is received. + * The \c udd_g_ctrlreq contains the data of SETUP packet. + * If this callback accepts the setup request then it must + * return \c 1 and eventually update \c udd_g_ctrlreq to send or receive data. + * + * \return \c 1 if the request is accepted, otherwise \c 0. + */ +extern bool udc_process_setup(void); + +/** + * \brief Reset the UDC + * + * The UDC must reset all configuration. + */ +extern void udc_reset(void); + +/** + * \brief To signal that a SOF is occured + * + * The UDC must send the signal to all UDIs enabled + */ +extern void udc_sof_notify(void); + +//@} + +//@} + +#ifdef __cplusplus +} +#endif +#endif // _UDD_H_ diff --git a/DSTAT1/src/asf/common/services/usb/udc/udi.h b/DSTAT1/src/asf/common/services/usb/udc/udi.h new file mode 100644 index 0000000000000000000000000000000000000000..81f387016d3a4bd7717310594d3dd17e10b3d76c --- /dev/null +++ b/DSTAT1/src/asf/common/services/usb/udc/udi.h @@ -0,0 +1,128 @@ +/** + * \file + * + * \brief Common API for USB Device Interface + * + * Copyright (c) 2009 - 2012 Atmel Corporation. All rights reserved. + * + * \asf_license_start + * + * 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. The name of Atmel may not be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * 4. This software may only be redistributed and used in connection with an + * Atmel microcontroller product. + * + * THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE + * EXPRESSLY AND SPECIFICALLY DISCLAIMED. IN NO EVENT SHALL ATMEL 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. + * + * \asf_license_stop + * + */ + +#ifndef _UDI_H_ +#define _UDI_H_ + +#include "conf_usb.h" +#include "usb_protocol.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * \ingroup usb_device_group + * \defgroup udi_group USB Device Interface (UDI) + * The UDI provides a common API for all classes, + * and this is used by UDC for the main control of USB Device interface. + * @{ + */ + +/** + * \brief UDI API. + * + * The callbacks within this structure are called only by + * USB Device Controller (UDC) + * + * The udc_get_interface_desc() can be use by UDI to know the interface descriptor + * selected by UDC. + */ +typedef struct { + /** + * \brief Enable the interface. + * + * This function is called when the host selects a configuration + * to which this interface belongs through a Set Configuration + * request, and when the host selects an alternate setting of + * this interface through a Set Interface request. + * + * \return \c 1 if function was successfully done, otherwise \c 0. + */ + bool(*enable) (void); + + /** + * \brief Disable the interface. + * + * This function is called when this interface is currently + * active, and + * - the host selects any configuration through a Set + * Configuration request, or + * - the host issues a USB reset, or + * - the device is detached from the host (i.e. Vbus is no + * longer present) + */ + void (*disable) (void); + + /** + * \brief Handle a control request directed at an interface. + * + * This function is called when this interface is currently + * active and the host sends a SETUP request + * with this interface as the recipient. + * + * Use udd_g_ctrlreq to decode and response to SETUP request. + * + * \return \c 1 if this interface supports the SETUP request, otherwise \c 0. + */ + bool(*setup) (void); + + /** + * \brief Returns the current setting of the selected interface. + * + * This function is called when UDC when know alternate setting of selected interface. + * + * \return alternate setting of selected interface + */ + uint8_t(*getsetting) (void); + + /** + * \brief To signal that a SOF is occured + */ + void(*sof_notify) (void); +} udi_api_t; + +//@} + +#ifdef __cplusplus +} +#endif +#endif // _UDI_H_ diff --git a/DSTAT1/src/asf/common/services/usb/usb_atmel.h b/DSTAT1/src/asf/common/services/usb/usb_atmel.h new file mode 100644 index 0000000000000000000000000000000000000000..e9db074ccebc4586adf39d507563730062b5942a --- /dev/null +++ b/DSTAT1/src/asf/common/services/usb/usb_atmel.h @@ -0,0 +1,180 @@ +/** + * \file + * + * \brief All USB VIDs and PIDs from Atmel USB applications + * + * Copyright (c) 2009-2011 Atmel Corporation. All rights reserved. + * + * \asf_license_start + * + * 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. The name of Atmel may not be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * 4. This software may only be redistributed and used in connection with an + * Atmel microcontroller product. + * + * THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE + * EXPRESSLY AND SPECIFICALLY DISCLAIMED. IN NO EVENT SHALL ATMEL 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. + * + * \asf_license_stop + * + */ + +#ifndef _USB_ATMEL_H_ +#define _USB_ATMEL_H_ + +/** + * \defgroup usb_group USB Stack + * + * This stack includes the USB Device Stack, USB Host Stack and common + * definitions. + * @{ + */ + +//! @} + +/** + * \ingroup usb_group + * \defgroup usb_atmel_ids_group Atmel USB Identifiers + * + * This module defines Atmel PID and VIDs constants. + * + * @{ + */ + +//! \name Vendor Identifier assigned by USB org to ATMEL +#define USB_VID_ATMEL 0x03EB + + +//! \name Product Identifier assigned by ATMEL to AVR applications +//! @{ + +//! \name The range from 2000h to 20FFh is reserved to the old PID for C51, MEGA, and others. +//! @{ +#define USB_PID_ATMEL_MEGA_HIDGENERIC 0x2013 +#define USB_PID_ATMEL_MEGA_HIDKEYBOARD 0x2017 +#define USB_PID_ATMEL_MEGA_CDC 0x2018 +#define USB_PID_ATMEL_MEGA_AUDIO_IN 0x2019 +#define USB_PID_ATMEL_MEGA_MS 0x201A +#define USB_PID_ATMEL_MEGA_AUDIO_IN_OUT 0x201B +#define USB_PID_ATMEL_MEGA_HIDMOUSE 0x201C +#define USB_PID_ATMEL_MEGA_HIDMOUSE_CERTIF_U4 0x201D +#define USB_PID_ATMEL_MEGA_CDC_MULTI 0x201E +#define USB_PID_ATMEL_MEGA_MS_HIDMS_HID_USBKEY 0x2022 +#define USB_PID_ATMEL_MEGA_MS_HIDMS_HID_STK525 0x2023 +#define USB_PID_ATMEL_MEGA_MS_2 0x2029 +#define USB_PID_ATMEL_MEGA_MS_HIDMS 0x202A +#define USB_PID_ATMEL_MEGA_MS_3 0x2032 +#define USB_PID_ATMEL_MEGA_LIBUSB 0x2050 +//! @} + +//! \name The range 2100h to 21FFh is reserved to PIDs for AVR Tools. +//! @{ +#define USB_PID_ATMEL_XPLAINED 0x2122 +//! @} + +//! \name The range 2300h to 23FFh is reserved to PIDs for demo from ASF1.7=> +//! @{ +#define USB_PID_ATMEL_UC3_ENUM 0x2300 +#define USB_PID_ATMEL_UC3_MS 0x2301 +#define USB_PID_ATMEL_UC3_MS_SDRAM_LOADER 0x2302 +#define USB_PID_ATMEL_UC3_EVK1100_CTRLPANEL 0x2303 +#define USB_PID_ATMEL_UC3_HID 0x2304 +#define USB_PID_ATMEL_UC3_EVK1101_CTRLPANEL_HID 0x2305 +#define USB_PID_ATMEL_UC3_EVK1101_CTRLPANEL_HID_MS 0x2306 +#define USB_PID_ATMEL_UC3_CDC 0x2307 +#define USB_PID_ATMEL_UC3_AUDIO_MICRO 0x2308 +#define USB_PID_ATMEL_UC3_CDC_DEBUG 0x2310 // Virtual Com (debug interface) on EVK11xx +#define USB_PID_ATMEL_UC3_AUDIO_SPEAKER_MICRO 0x2311 +#define USB_PID_ATMEL_UC3_CDC_MSC 0x2312 +//! @} + +//! \name The range 2400h to 24FFh is reserved to PIDs for ASF applications +//! @{ +#define USB_PID_ATMEL_AVR_HIDMOUSE 0x2400 +#define USB_PID_ATMEL_AVR_HIDKEYBOARD 0x2401 +#define USB_PID_ATMEL_AVR_HIDGENERIC 0x2402 +#define USB_PID_ATMEL_AVR_MSC 0x2403 +#define USB_PID_ATMEL_AVR_CDC 0x2404 +#define USB_PID_ATMEL_AVR_PHDC 0x2405 +#define USB_PID_ATMEL_AVR_MSC_HIDMOUSE 0x2420 +#define USB_PID_ATMEL_AVR_MSC_HIDS_CDC 0x2421 +#define USB_PID_ATMEL_AVR_MSC_HIDKEYBOARD 0x2422 +#define USB_PID_ATMEL_ASF_VENDOR_CLASS 0x2423 +#define USB_PID_ATMEL_AVR_MSC_CDC 0x2424 +#define USB_PID_ATMEL_AVR_TWO_CDC 0x2425 +#define USB_PID_ATMEL_AVR_XPLAIN_BC_POWERONLY 0x2430 +#define USB_PID_ATMEL_AVR_XPLAIN_BC_TERMINAL 0x2431 +#define USB_PID_ATMEL_AVR_XPLAIN_BC_TOUCH 0x2432 +#define USB_PID_ATMEL_AVR_AUDIO_SPEAKER 0x2433 +#define USB_PID_ATMEL_AVR_XMEGA_B1_XPLAINED 0x2434 +//! @} + +//! \name The range 2F00h to 2FFFh is reserved to official PIDs for AVR bootloaders +//! Note, !!!! don't use this range for demos or examples !!!! +//! @{ +#define USB_PID_ATMEL_DFU_ATXMEGA16C4 0x2FD8 +#define USB_PID_ATMEL_DFU_ATXMEGA32C4 0x2FD9 +#define USB_PID_ATMEL_DFU_ATXMEGA256C3 0x2FDA +#define USB_PID_ATMEL_DFU_ATXMEGA384C3 0x2FDB +#define USB_PID_ATMEL_DFU_ATUCL3_L4 0x2FDC +#define USB_PID_ATMEL_DFU_ATXMEGA64A4U 0x2FDD +#define USB_PID_ATMEL_DFU_ATXMEGA128A4U 0x2FDE + +#define USB_PID_ATMEL_DFU_ATXMEGA64B3 0x2FDF +#define USB_PID_ATMEL_DFU_ATXMEGA128B3 0x2FE0 +#define USB_PID_ATMEL_DFU_ATXMEGA64B1 0x2FE1 +#define USB_PID_ATMEL_DFU_ATXMEGA256A3BU 0x2FE2 +#define USB_PID_ATMEL_DFU_ATXMEGA16A4U 0x2FE3 +#define USB_PID_ATMEL_DFU_ATXMEGA32A4U 0x2FE4 +#define USB_PID_ATMEL_DFU_ATXMEGA64A3U 0x2FE5 +#define USB_PID_ATMEL_DFU_ATXMEGA128A3U 0x2FE6 +#define USB_PID_ATMEL_DFU_ATXMEGA192A3U 0x2FE7 +#define USB_PID_ATMEL_DFU_ATXMEGA64A1U 0x2FE8 +#define USB_PID_ATMEL_DFU_ATUC3D 0x2FE9 +#define USB_PID_ATMEL_DFU_ATXMEGA128B1 0x2FEA +#define USB_PID_ATMEL_DFU_AT32UC3C 0x2FEB +#define USB_PID_ATMEL_DFU_ATXMEGA256A3U 0x2FEC +#define USB_PID_ATMEL_DFU_ATXMEGA128A1U 0x2FED +#define USB_PID_ATMEL_DFU_ATMEGA8U2 0x2FEE +#define USB_PID_ATMEL_DFU_ATMEGA16U2 0x2FEF +#define USB_PID_ATMEL_DFU_ATMEGA32U2 0x2FF0 +#define USB_PID_ATMEL_DFU_AT32UC3A3 0x2FF1 +#define USB_PID_ATMEL_DFU_ATMEGA32U6 0x2FF2 +#define USB_PID_ATMEL_DFU_ATMEGA16U4 0x2FF3 +#define USB_PID_ATMEL_DFU_ATMEGA32U4 0x2FF4 +#define USB_PID_ATMEL_DFU_AT32AP7200 0x2FF5 +#define USB_PID_ATMEL_DFU_AT32UC3B 0x2FF6 +#define USB_PID_ATMEL_DFU_AT90USB82 0x2FF7 +#define USB_PID_ATMEL_DFU_AT32UC3A 0x2FF8 +#define USB_PID_ATMEL_DFU_AT90USB64 0x2FF9 +#define USB_PID_ATMEL_DFU_AT90USB162 0x2FFA +#define USB_PID_ATMEL_DFU_AT90USB128 0x2FFB +// 2FFCh to 2FFFh used by C51 family products +//! @} + +//! @} + +//! @} + + +#endif // _USB_ATMEL_H_ diff --git a/DSTAT1/src/asf/common/services/usb/usb_protocol.h b/DSTAT1/src/asf/common/services/usb/usb_protocol.h new file mode 100644 index 0000000000000000000000000000000000000000..61140dbaadb9c4be361e9ab51186dab2840d87c0 --- /dev/null +++ b/DSTAT1/src/asf/common/services/usb/usb_protocol.h @@ -0,0 +1,408 @@ +/** + * \file + * + * \brief USB protocol definitions. + * + * This file contains the USB definitions and data structures provided by the + * USB 2.0 specification. + * + * Copyright (c) 2009 Atmel Corporation. All rights reserved. + * + * \asf_license_start + * + * 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. The name of Atmel may not be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * 4. This software may only be redistributed and used in connection with an + * Atmel microcontroller product. + * + * THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE + * EXPRESSLY AND SPECIFICALLY DISCLAIMED. IN NO EVENT SHALL ATMEL 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. + * + * \asf_license_stop + * + */ + +#ifndef _USB_PROTOCOL_H_ +#define _USB_PROTOCOL_H_ + +#include "usb_atmel.h" + +/** + * \ingroup usb_group + * \defgroup usb_protocol_group USB Protocol Definitions + * + * This module defines constants and data structures provided by the USB + * 2.0 specification. + * + * @{ + */ + +//! Value for field bcdUSB +#define USB_V2_0 0x0200 //!< USB Specification version 2.00 + +/*! \name Generic definitions (Class, subclass and protocol) + */ +//! @{ +#define NO_CLASS 0x00 +#define CLASS_VENDOR_SPECIFIC 0xFF +#define NO_SUBCLASS 0x00 +#define NO_PROTOCOL 0x00 +//! @} + +//! \name IAD (Interface Association Descriptor) constants +//! @{ +#define CLASS_IAD 0xEF +#define SUB_CLASS_IAD 0x02 +#define PROTOCOL_IAD 0x01 +//! @} + +/** + * \brief USB request data transfer direction (bmRequestType) + */ +#define USB_REQ_DIR_OUT (0<<7) //!< Host to device +#define USB_REQ_DIR_IN (1<<7) //!< Device to host +#define USB_REQ_DIR_MASK (1<<7) //!< Mask + +/** + * \brief USB request types (bmRequestType) + */ +#define USB_REQ_TYPE_STANDARD (0<<5) //!< Standard request +#define USB_REQ_TYPE_CLASS (1<<5) //!< Class-specific request +#define USB_REQ_TYPE_VENDOR (2<<5) //!< Vendor-specific request +#define USB_REQ_TYPE_MASK (3<<5) //!< Mask + +/** + * \brief USB recipient codes (bmRequestType) + */ +#define USB_REQ_RECIP_DEVICE (0<<0) //!< Recipient device +#define USB_REQ_RECIP_INTERFACE (1<<0) //!< Recipient interface +#define USB_REQ_RECIP_ENDPOINT (2<<0) //!< Recipient endpoint +#define USB_REQ_RECIP_OTHER (3<<0) //!< Recipient other +#define USB_REQ_RECIP_MASK (0x1F) //!< Mask + +/** + * \brief Standard USB requests (bRequest) + */ +enum usb_reqid { + USB_REQ_GET_STATUS = 0, + USB_REQ_CLEAR_FEATURE = 1, + USB_REQ_SET_FEATURE = 3, + USB_REQ_SET_ADDRESS = 5, + USB_REQ_GET_DESCRIPTOR = 6, + USB_REQ_SET_DESCRIPTOR = 7, + USB_REQ_GET_CONFIGURATION = 8, + USB_REQ_SET_CONFIGURATION = 9, + USB_REQ_GET_INTERFACE = 10, + USB_REQ_SET_INTERFACE = 11, + USB_REQ_SYNCH_FRAME = 12, +}; + +/** + * \brief Standard USB device status flags + * + */ +enum usb_device_status { + USB_DEV_STATUS_BUS_POWERED = 0, + USB_DEV_STATUS_SELF_POWERED = 1, + USB_DEV_STATUS_REMOTEWAKEUP = 2 +}; + +/** + * \brief Standard USB Interface status flags + * + */ +enum usb_interface_status { + USB_IFACE_STATUS_RESERVED = 0 +}; + +/** + * \brief Standard USB endpoint status flags + * + */ +enum usb_endpoint_status { + USB_EP_STATUS_HALTED = 1, +}; + +/** + * \brief Standard USB device feature flags + * + * \note valid for SetFeature request. + */ +enum usb_device_feature { + USB_DEV_FEATURE_REMOTE_WAKEUP = 1, //!< Remote wakeup enabled + USB_DEV_FEATURE_TEST_MODE = 2, //!< USB test mode + USB_DEV_FEATURE_OTG_B_HNP_ENABLE = 3, + USB_DEV_FEATURE_OTG_A_HNP_SUPPORT = 4, + USB_DEV_FEATURE_OTG_A_ALT_HNP_SUPPORT = 5 +}; + +/** + * \brief Test Mode possible on HS USB device + * + * \note valid for USB_DEV_FEATURE_TEST_MODE request. + */ +enum usb_device_hs_test_mode { + USB_DEV_TEST_MODE_J = 1, + USB_DEV_TEST_MODE_K = 2, + USB_DEV_TEST_MODE_SE0_NAK = 3, + USB_DEV_TEST_MODE_PACKET = 4, + USB_DEV_TEST_MODE_FORCE_ENABLE = 5, +}; + +/** + * \brief Standard USB endpoint feature/status flags + */ +enum usb_endpoint_feature { + USB_EP_FEATURE_HALT = 0, +}; + +/** + * \brief Standard USB Test Mode Selectors + */ +enum usb_test_mode_selector { + USB_TEST_J = 0x01, + USB_TEST_K = 0x02, + USB_TEST_SE0_NAK = 0x03, + USB_TEST_PACKET = 0x04, + USB_TEST_FORCE_ENABLE = 0x05, +}; + +/** + * \brief Standard USB descriptor types + */ +enum usb_descriptor_type { + USB_DT_DEVICE = 1, + USB_DT_CONFIGURATION = 2, + USB_DT_STRING = 3, + USB_DT_INTERFACE = 4, + USB_DT_ENDPOINT = 5, + USB_DT_DEVICE_QUALIFIER = 6, + USB_DT_OTHER_SPEED_CONFIGURATION = 7, + USB_DT_INTERFACE_POWER = 8, + USB_DT_OTG = 9, + USB_DT_IAD = 0x0B, +}; + +/** + * \brief Standard USB endpoint transfer types + */ +enum usb_ep_type { + USB_EP_TYPE_CONTROL = 0x00, + USB_EP_TYPE_ISOCHRONOUS = 0x01, + USB_EP_TYPE_BULK = 0x02, + USB_EP_TYPE_INTERRUPT = 0x03, + USB_EP_TYPE_MASK = 0x03, +}; + +/** + * \brief Standard USB language IDs for string descriptors + */ +enum usb_langid { + USB_LANGID_EN_US = 0x0409, //!< English (United States) +}; + +/** + * \brief Mask selecting the index part of an endpoint address + */ +#define USB_EP_ADDR_MASK 0x0f + +//! \brief USB address identifier +typedef uint8_t usb_add_t; + +/** + * \brief Endpoint transfer direction is IN + */ +#define USB_EP_DIR_IN 0x80 + +/** + * \brief Endpoint transfer direction is OUT + */ +#define USB_EP_DIR_OUT 0x00 + +//! \brief Endpoint identifier +typedef uint8_t usb_ep_t; + +/** + * \brief Maximum length in bytes of a USB descriptor + * + * The maximum length of a USB descriptor is limited by the 8-bit + * bLength field. + */ +#define USB_MAX_DESC_LEN 255 + +/* + * 2-byte alignment requested for all USB structures. + */ +COMPILER_PACK_SET(1); + +/** + * \brief A USB Device SETUP request + * + * The data payload of SETUP packets always follows this structure. + */ +typedef struct { + uint8_t bmRequestType; + uint8_t bRequest; + le16_t wValue; + le16_t wIndex; + le16_t wLength; +} usb_setup_req_t; + +/** + * \brief Standard USB device descriptor stucture + */ +typedef struct { + uint8_t bLength; + uint8_t bDescriptorType; + le16_t bcdUSB; + uint8_t bDeviceClass; + uint8_t bDeviceSubClass; + uint8_t bDeviceProtocol; + uint8_t bMaxPacketSize0; + le16_t idVendor; + le16_t idProduct; + le16_t bcdDevice; + uint8_t iManufacturer; + uint8_t iProduct; + uint8_t iSerialNumber; + uint8_t bNumConfigurations; +} usb_dev_desc_t; + +/** + * \brief Standard USB device qualifier descriptor structure + * + * This descriptor contains information about the device when running at + * the "other" speed (i.e. if the device is currently operating at high + * speed, this descriptor can be used to determine what would change if + * the device was operating at full speed.) + */ +typedef struct { + uint8_t bLength; + uint8_t bDescriptorType; + le16_t bcdUSB; + uint8_t bDeviceClass; + uint8_t bDeviceSubClass; + uint8_t bDeviceProtocol; + uint8_t bMaxPacketSize0; + uint8_t bNumConfigurations; + uint8_t bReserved; +} usb_dev_qual_desc_t; + + +/** + * \brief Standard USB Interface Association Descriptor structure + */ +typedef struct { + uint8_t bLength; //!< size of this descriptor in bytes + uint8_t bDescriptorType; //!< INTERFACE descriptor type + uint8_t bFirstInterface; //!< Number of interface + uint8_t bInterfaceCount; //!< value to select alternate setting + uint8_t bFunctionClass; //!< Class code assigned by the USB + uint8_t bFunctionSubClass;//!< Sub-class code assigned by the USB + uint8_t bFunctionProtocol;//!< Protocol code assigned by the USB + uint8_t iFunction; //!< Index of string descriptor +} usb_association_desc_t; + + +/** + * \brief Standard USB configuration descriptor structure + */ +typedef struct { + uint8_t bLength; + uint8_t bDescriptorType; + le16_t wTotalLength; + uint8_t bNumInterfaces; + uint8_t bConfigurationValue; + uint8_t iConfiguration; + uint8_t bmAttributes; + uint8_t bMaxPower; +} usb_conf_desc_t; + + +#define USB_CONFIG_ATTR_MUST_SET (1 << 7) //!< Must always be set +#define USB_CONFIG_ATTR_BUS_POWERED (0 << 6) //!< Bus-powered +#define USB_CONFIG_ATTR_SELF_POWERED (1 << 6) //!< Self-powered +#define USB_CONFIG_ATTR_REMOTE_WAKEUP (1 << 5) //!< remote wakeup supported + +#define USB_CONFIG_MAX_POWER(ma) (((ma) + 1) / 2) //!< Max power in mA + +/** + * \brief Standard USB association descriptor structure + */ +typedef struct { + uint8_t bLength; //!< Size of this descriptor in bytes + uint8_t bDescriptorType; //!< Interface descriptor type + uint8_t bFirstInterface; //!< Number of interface + uint8_t bInterfaceCount; //!< value to select alternate setting + uint8_t bFunctionClass; //!< Class code assigned by the USB + uint8_t bFunctionSubClass; //!< Sub-class code assigned by the USB + uint8_t bFunctionProtocol; //!< Protocol code assigned by the USB + uint8_t iFunction; //!< Index of string descriptor +} usb_iad_desc_t; + +/** + * \brief Standard USB interface descriptor structure + */ +typedef struct { + uint8_t bLength; + uint8_t bDescriptorType; + uint8_t bInterfaceNumber; + uint8_t bAlternateSetting; + uint8_t bNumEndpoints; + uint8_t bInterfaceClass; + uint8_t bInterfaceSubClass; + uint8_t bInterfaceProtocol; + uint8_t iInterface; +} usb_iface_desc_t; + +/** + * \brief Standard USB endpoint descriptor stcuture + */ +typedef struct { + uint8_t bLength; + uint8_t bDescriptorType; + uint8_t bEndpointAddress; + uint8_t bmAttributes; + le16_t wMaxPacketSize; + uint8_t bInterval; +} usb_ep_desc_t; + + +/** + * \brief A standard USB string descriptor sructure + */ +typedef struct { + uint8_t bLength; + uint8_t bDescriptorType; +} usb_str_desc_t; + +typedef struct { + usb_str_desc_t desc; + le16_t string[1]; +} usb_str_lgid_desc_t; + +COMPILER_PACK_RESET(); + +//! @} + +#endif /* _USB_PROTOCOL_H_ */ diff --git a/DSTAT1/src/asf/common/utils/interrupt.h b/DSTAT1/src/asf/common/utils/interrupt.h new file mode 100644 index 0000000000000000000000000000000000000000..2221e9111002b08e04b607bfb3ff519127bad0bb --- /dev/null +++ b/DSTAT1/src/asf/common/utils/interrupt.h @@ -0,0 +1,135 @@ +/** + * \file + * + * \brief Global interrupt management for 8- and 32-bit AVR + * + * Copyright (c) 2010 Atmel Corporation. All rights reserved. + * + * \asf_license_start + * + * 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. The name of Atmel may not be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * 4. This software may only be redistributed and used in connection with an + * Atmel microcontroller product. + * + * THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE + * EXPRESSLY AND SPECIFICALLY DISCLAIMED. IN NO EVENT SHALL ATMEL 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. + * + * \asf_license_stop + * + */ +#ifndef UTILS_INTERRUPT_H +#define UTILS_INTERRUPT_H + +#include + +#if XMEGA || MEGA +# include "interrupt/interrupt_avr8.h" +#elif UC3 +# include "interrupt/interrupt_avr32.h" +#else +# error Unsupported device. +#endif + +/** + * \defgroup interrupt_group Global interrupt management + * + * This is a driver for global enabling and disabling of interrupts. + * + * @{ + */ + +#if defined(__DOXYGEN__) +/** + * \def CONFIG_INTERRUPT_FORCE_INTC + * \brief Force usage of the ASF INTC driver + * + * Predefine this symbol when preprocessing to force the use of the ASF INTC driver. + * This is useful to ensure compatibilty accross compilers and shall be used only when required + * by the application needs. + */ +# define CONFIG_INTERRUPT_FORCE_INTC +#endif + +//! \name Global interrupt flags +//@{ +/** + * \typedef irqflags_t + * \brief Type used for holding state of interrupt flag + */ + +/** + * \def cpu_irq_enable + * \brief Enable interrupts globally + */ + +/** + * \def cpu_irq_disable + * \brief Disable interrupts globally + */ + +/** + * \fn irqflags_t cpu_irq_save(void) + * \brief Get and clear the global interrupt flags + * + * Use in conjunction with \ref cpu_irq_restore. + * + * \return Current state of interrupt flags. + * + * \note This function leaves interrupts disabled. + */ + +/** + * \fn void cpu_irq_restore(irqflags_t flags) + * \brief Restore global interrupt flags + * + * Use in conjunction with \ref cpu_irq_save. + * + * \param flags State to set interrupt flag to. + */ + +/** + * \fn bool cpu_irq_is_enabled_flags(irqflags_t flags) + * \brief Check if interrupts are globally enabled in supplied flags + * + * \param flags Currents state of interrupt flags. + * + * \return True if interrupts are enabled. + */ + +/** + * \def cpu_irq_is_enabled + * \brief Check if interrupts are globally enabled + * + * \return True if interrupts are enabled. + */ +//@} + +//! @} + +/** + * \ingroup interrupt_group + * \defgroup interrupt_deprecated_group Deprecated interrupt definitions + */ + +#endif /* UTILS_INTERRUPT_H */ diff --git a/DSTAT1/src/asf/common/utils/interrupt/interrupt_avr8.h b/DSTAT1/src/asf/common/utils/interrupt/interrupt_avr8.h new file mode 100644 index 0000000000000000000000000000000000000000..c557d0cf155629536695726252527d46e488d1b6 --- /dev/null +++ b/DSTAT1/src/asf/common/utils/interrupt/interrupt_avr8.h @@ -0,0 +1,136 @@ +/** + * \file + * + * \brief Global interrupt management for 8-bit AVR + * + * Copyright (c) 2010 Atmel Corporation. All rights reserved. + * + * \asf_license_start + * + * 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. The name of Atmel may not be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * 4. This software may only be redistributed and used in connection with an + * Atmel microcontroller product. + * + * THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE + * EXPRESSLY AND SPECIFICALLY DISCLAIMED. IN NO EVENT SHALL ATMEL 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. + * + * \asf_license_stop + * + */ +#ifndef UTILS_INTERRUPT_INTERRUPT_H +#define UTILS_INTERRUPT_INTERRUPT_H + +#include +#include + +/** + * \weakgroup interrupt_group + * + * @{ + */ + +/** + * \def ISR + * \brief Define service routine for specified interrupt vector + * + * Usage: + * \code + * ISR(FOO_vect) + * { + * ... + * } + * \endcode + * + * \param vect Interrupt vector name as found in the device header files. + */ +#if defined(__DOXYGEN__) +# define ISR(vect) +#elif defined(__GNUC__) +# include +#elif defined(__ICCAVR__) +# define __ISR(x) _Pragma(#x) +# define ISR(vect) __ISR(vector=vect) __interrupt void handler_##vect(void) +#endif + +#if XMEGA +/** + * \brief Initialize interrupt vectors + * Enables all interrupt levels, with vectors located in the application section + * and fixed priority scheduling. + */ +#define irq_initialize_vectors() \ + PMIC.CTRL = PMIC_LOLVLEN_bm | PMIC_MEDLVLEN_bm | PMIC_HILVLEN_bm; +#endif + +#ifdef __GNUC__ +# define cpu_irq_enable() sei() +# define cpu_irq_disable() cli() +#else +# define cpu_irq_enable() __enable_interrupt() +# define cpu_irq_disable() __disable_interrupt() +#endif + +typedef uint8_t irqflags_t; + +static inline irqflags_t cpu_irq_save(void) +{ + irqflags_t flags = SREG; + cpu_irq_disable(); + return flags; +} + +static inline void cpu_irq_restore(irqflags_t flags) +{ + barrier(); + SREG = flags; +} + +static inline bool cpu_irq_is_enabled_flags(irqflags_t flags) +{ +#if XMEGA +# ifdef __GNUC__ + return flags & CPU_I_bm; +# else + return flags & I_bm; +# endif +#elif MEGA + return flags & (1 << SREG_I); +#endif +} + +#define cpu_irq_is_enabled() cpu_irq_is_enabled_flags(SREG) + +//! @} + +/** + * \weakgroup interrupt_deprecated_group + * @{ + */ +// Deprecated definitions. +#define Enable_global_interrupt() cpu_irq_enable() +#define Disable_global_interrupt() cpu_irq_disable() +#define Is_global_interrupt_enabled() cpu_irq_is_enabled() +//! @} + +#endif /* UTILS_INTERRUPT_INTERRUPT_H */ diff --git a/DSTAT1/src/asf/common/utils/make/Makefile.avr.in b/DSTAT1/src/asf/common/utils/make/Makefile.avr.in new file mode 100644 index 0000000000000000000000000000000000000000..f6742f345e7846d0cc70f40eb9dba9670ccc9395 --- /dev/null +++ b/DSTAT1/src/asf/common/utils/make/Makefile.avr.in @@ -0,0 +1,445 @@ +# List of available make goals: +# +# all Default target, builds the project +# clean Clean up the project +# rebuild Rebuild the project +# +# doc Build the documentation +# cleandoc Clean up the documentation +# rebuilddoc Rebuild the documentation +# +# +# Copyright (c) 2009-2010 Atmel Corporation. All rights reserved. +# +# \asf_license_start +# +# 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. The name of Atmel may not be used to endorse or promote products derived +# from this software without specific prior written permission. +# +# 4. This software may only be redistributed and used in connection with an +# Atmel microcontroller product. +# +# THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR IMPLIED +# WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE +# EXPRESSLY AND SPECIFICALLY DISCLAIMED. IN NO EVENT SHALL ATMEL 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. +# +# \asf_license_stop +# + +# Include the config.mk file from the current working path, e.g., where the +# user called make. +include config.mk + +# Tool to use to generate documentation from the source code +DOCGEN ?= doxygen + +# Look for source files relative to the top-level source directory +VPATH := $(PRJ_PATH) + +# Output target file +target := $(TARGET) + +# Output project name (target name minus suffix) +project := $(basename $(target)) + +# Output target file (typically ELF or static library) +ifeq ($(suffix $(target)),.a) +target_type := lib +else +ifeq ($(suffix $(target)),.elf) +target_type := elf +else +$(error "Target type $(target_type) is not supported") +endif +endif + +# Allow override of operating system detection. The user can add OS=Linux or +# OS=Windows on the command line to explicit set the host OS. +# +# This allows to work around broken uname utility on certain systems. +ifdef OS + ifeq ($(strip $(OS)), Linux) + os_type := Linux + endif + ifeq ($(strip $(OS)), Windows) + os_type := windows32_64 + endif +endif + +os_type ?= $(strip $(shell uname)) + +ifeq ($(os_type),windows32) +os := Windows +else +ifeq ($(os_type),windows64) +os := Windows +else +ifeq ($(os_type),windows32_64) +os ?= Windows +else +ifeq ($(os_type),) +os := Windows +else +# Default to Linux style operating system. Both Cygwin and mingw are fully +# compatible (for this Makefile) with Linux. +os := Linux +endif +endif +endif +endif + +# Output documentation directory and configuration file. +docdir := ../doxygen/html +doccfg := ../doxygen/doxyfile.doxygen + +CROSS ?= avr- +AR := $(CROSS)ar +AS := $(CROSS)as +CC := $(CROSS)gcc +CPP := $(CROSS)gcc -E +CXX := $(CROSS)g++ +LD := $(CROSS)g++ +NM := $(CROSS)nm +OBJCOPY := $(CROSS)objcopy +OBJDUMP := $(CROSS)objdump +SIZE := $(CROSS)size + +RM := rm +ifeq ($(os),Windows) +RMDIR := rmdir /S /Q +else +RMDIR := rmdir -p --ignore-fail-on-non-empty +endif + +# Strings for beautifying output +MSG_CLEAN_FILES = "RM *.o *.d" +MSG_CLEAN_DIRS = "RMDIR $(strip $(clean-dirs))" +MSG_CLEAN_DOC = "RMDIR $(docdir)" +MSG_MKDIR = "MKDIR $(dir $@)" + +MSG_INFO = "INFO " + +MSG_ARCHIVING = "AR $@" +MSG_ASSEMBLING = "AS $@" +MSG_BINARY_IMAGE = "OBJCOPY $@" +MSG_COMPILING = "CC $@" +MSG_COMPILING_CXX = "CXX $@" +MSG_EEPROM_IMAGE = "OBJCOPY $@" +MSG_EXTENDED_LISTING = "OBJDUMP $@" +MSG_IHEX_IMAGE = "OBJCOPY $@" +MSG_LINKING = "LN $@" +MSG_PREPROCESSING = "CPP $@" +MSG_SIZE = "SIZE $@" +MSG_SYMBOL_TABLE = "NM $@" + +MSG_GENERATING_DOC = "DOXYGEN $(docdir)" + +# Don't use make's built-in rules and variables +MAKEFLAGS += -rR + +# Don't print 'Entering directory ...' +MAKEFLAGS += --no-print-directory + +# Function for reversing the order of a list +reverse = $(if $(1),$(call reverse,$(wordlist 2,$(words $(1)),$(1)))) $(firstword $(1)) + +# Hide command output by default, but allow the user to override this +# by adding V=1 on the command line. +# +# This is inspired by the Kbuild system used by the Linux kernel. +ifdef V + ifeq ("$(origin V)", "command line") + VERBOSE = $(V) + endif +endif +ifndef VERBOSE + VERBOSE = 0 +endif + +ifeq ($(VERBOSE), 1) + Q = +else + Q = @ +endif + +arflags-gnu-y := $(ARFLAGS) +asflags-gnu-y := $(ASFLAGS) +cflags-gnu-y := $(CFLAGS) +cxxflags-gnu-y := $(CXXFLAGS) +cppflags-gnu-y := $(CPPFLAGS) +cpuflags-gnu-y := +dbgflags-gnu-y := $(DBGFLAGS) +libflags-gnu-y := $(foreach LIB,$(LIBS),-l$(LIB)) +ldflags-gnu-y := $(LDFLAGS) +flashflags-gnu-y := $(FLASHFLAGS) +eepromflags-gnu-y := $(EEPROMFLAGS) +clean-files := +clean-dirs := + +clean-files += $(wildcard $(target) $(project).map) +clean-files += $(wildcard $(project).hex $(project).eep) +clean-files += $(wildcard $(project).lss $(project).sym) +clean-files += $(wildcard $(build)) + +# Use pipes instead of temporary files for communication between processes +cflags-gnu-y += -pipe +asflags-gnu-y += -pipe +ldflags-gnu-y += -pipe + +# Archiver flags. +arflags-gnu-y += rcs + +# Always enable warnings. And be very careful about implicit +# declarations. +cflags-gnu-y += -Wall -Wstrict-prototypes -Wmissing-prototypes +cflags-gnu-y += -Werror-implicit-function-declaration +cxxflags-gnu-y += -Wall +# IAR doesn't allow arithmetic on void pointers, so warn about that. +cflags-gnu-y += -Wpointer-arith +cxxflags-gnu-y += -Wpointer-arith + +# Preprocessor flags. +cppflags-gnu-y += $(foreach INC,$(addprefix $(PRJ_PATH)/,$(INC_PATH)),-I$(INC)) +asflags-gnu-y += $(foreach INC,$(addprefix $(PRJ_PATH)/,$(INC_PATH)),'-Wa,-I$(INC)') + +# CPU specific flags. +cpuflags-gnu-y += -mmcu=$(MCU) + +# Dependency file flags. +depflags = -MD -MP -MQ $@ + +# Debug specific flags. +ifdef BUILD_DEBUG_LEVEL +dbgflags-gnu-y += -g$(BUILD_DEBUG_LEVEL) +else +dbgflags-gnu-y += -gdwarf-2 +endif + +# Optimization specific flags. +ifdef BUILD_OPTIMIZATION +optflags-gnu-y = -O$(BUILD_OPTIMIZATION) +else +optflags-gnu-y = $(OPTIMIZATION) +endif + +# Relax compilation and linking. +cflags-gnu-y += -mrelax +cxxflags-gnu-y += -mrelax +asflags-gnu-y += -mrelax +ldflags-gnu-y += -Wl,--relax + +# Always preprocess assembler files. +asflags-gnu-y += -x assembler-with-cpp +# Compile C files using the GNU99 standard. +cflags-gnu-y += -std=gnu99 +# Compile C++ files using the GNU++98 standard. +cxxflags-gnu-y += -std=gnu++98 + +# Use unsigned character type when compiling. +cflags-gnu-y += -funsigned-char +cxxflags-gnu-y += -funsigned-char + +# Separate each function and data into its own separate section to allow +# garbage collection of unused sections. +cflags-gnu-y += -ffunction-sections -fdata-sections +cxxflags-gnu-y += -ffunction-sections -fdata-sections + +# Garbage collect unreferred sections when linking. +ldflags-gnu-y += -Wl,--gc-sections + +# Output a link map file and a cross reference table +ldflags-gnu-y += -Wl,-Map=$(project).map,--cref + +# Add library search paths relative to the top level directory. +ldflags-gnu-y += $(foreach _LIB_PATH,$(addprefix $(PRJ_PATH)/,$(LIB_PATH)),-L$(_LIB_PATH)) + +a_flags = $(cpuflags-gnu-y) $(depflags) $(cppflags-gnu-y) $(asflags-gnu-y) -D__ASSEMBLY__ +c_flags = $(cpuflags-gnu-y) $(dbgflags-gnu-y) $(depflags) $(optflags-gnu-y) $(cppflags-gnu-y) $(cflags-gnu-y) +cxx_flags= $(cpuflags-gnu-y) $(dbgflags-gnu-y) $(depflags) $(optflags-gnu-y) $(cppflags-gnu-y) $(cxxflags-gnu-y) +l_flags = $(cpuflags-gnu-y) $(optflags-gnu-y) $(ldflags-gnu-y) +ar_flags = $(arflags-gnu-y) + +# Intel Hex file production flags +flashflags-gnu-y += -R .eeprom -R .usb_descriptor_table + +# Eeprom file production flags +eepromflags-gnu-y += -j .eeprom +eepromflags-gnu-y += --set-section-flags=.eeprom="alloc,load" +eepromflags-gnu-y += --change-section-lma .eeprom=0 + +# Source files list and part informations must already be included before +# running this makefile + +# Create object files list from source files list. +obj-y := $(addsuffix .o,$(basename $(CSRCS) $(ASSRCS))) +# Create dependency files list from source files list. +dep-files := $(wildcard $(foreach f,$(obj-y),$(basename $(f)).d)) + +clean-files += $(wildcard $(obj-y)) +clean-files += $(dep-files) + +clean-dirs += $(call reverse,$(sort $(wildcard $(dir $(obj-y))))) + +# Default target. +.PHONY: all +ifeq ($(target_type),lib) +all: $(target) $(project).lss $(project).sym +else +ifeq ($(target_type),elf) +all: $(target) $(project).hex $(project).lss $(project).sym +endif +endif + +# Clean up the project. +.PHONY: clean +clean: + @$(if $(strip $(clean-files)),echo $(MSG_CLEAN_FILES)) + $(if $(strip $(clean-files)),$(Q)$(RM) $(clean-files),) + @$(if $(strip $(clean-dirs)),echo $(MSG_CLEAN_DIRS)) +# Remove created directories, and make sure we only remove existing +# directories, since recursive rmdir might help us a bit on the way. +ifeq ($(os),Windows) + $(Q)$(if $(strip $(clean-dirs)), \ + $(RMDIR) $(strip $(subst /,\,$(clean-dirs)))) +else + $(Q)$(if $(strip $(clean-dirs)), \ + for directory in $(strip $(clean-dirs)); do \ + if [ -d "$$directory" ]; then \ + $(RMDIR) $$directory; \ + fi \ + done \ + ) +endif + +# Rebuild the project. +.PHONY: rebuild +rebuild: clean all + +.PHONY: objfiles +objfiles: $(obj-y) + +# Create object files from C source files. +%.o: %.c $(PRJ_PATH)/common/utils/make/Makefile.avr.in config.mk + $(Q)test -d $(dir $@) || echo $(MSG_MKDIR) +ifeq ($(os),Windows) + $(Q)test -d $(dir $@) || mkdir $(subst /,\,$(dir $@)) +else + $(Q)test -d $(dir $@) || mkdir -p $(dir $@) +endif + @echo $(MSG_COMPILING) + $(Q)$(CC) $(c_flags) -c $< -o $@ + +# Create object files from C++ source files. +%.o: %.cpp $(PRJ_PATH)/common/utils/make/Makefile.avr.in config.mk + $(Q)test -d $(dir $@) || echo $(MSG_MKDIR) +ifeq ($(os),Windows) + $(Q)test -d $(dir $@) || mkdir $(subst /,\,$(dir $@)) +else + $(Q)test -d $(dir $@) || mkdir -p $(dir $@) +endif + @echo $(MSG_COMPILING_CXX) + $(Q)$(CXX) $(cxx_flags) -c $< -o $@ + +# Preprocess and assemble: create object files from assembler source files. +%.o: %.s $(PRJ_PATH)/common/utils/make/Makefile.avr.in config.mk + $(Q)test -d $(dir $@) || echo $(MSG_MKDIR) +ifeq ($(os),Windows) + $(Q)test -d $(dir $@) || mkdir $(subst /,\,$(dir $@)) +else + $(Q)test -d $(dir $@) || mkdir -p $(dir $@) +endif + @echo $(MSG_ASSEMBLING) + $(Q)$(CC) $(a_flags) -c $< -o $@ + +# Preprocess and assemble: create object files from assembler source files. +%.o: %.S $(PRJ_PATH)/common/utils/make/Makefile.avr.in config.mk + $(Q)test -d $(dir $@) || echo $(MSG_MKDIR) +ifeq ($(os),Windows) + $(Q)test -d $(dir $@) || mkdir $(subst /,\,$(dir $@)) +else + $(Q)test -d $(dir $@) || mkdir -p $(dir $@) +endif + @echo $(MSG_ASSEMBLING) + $(Q)$(CC) $(a_flags) -c $< -o $@ + +# Include all dependency files to add depedency to all header files in use. +include $(dep-files) + +ifeq ($(target_type),lib) +# Archive object files into an archive +$(target): $(PRJ_PATH)/common/utils/make/Makefile.avr.in config.mk $(obj-y) + @echo $(MSG_ARCHIVING) + $(Q)$(AR) $(ar_flags) $@ $(obj-y) + @echo $(MSG_SIZE) + $(Q)$(SIZE) -Bxt $@ +else +ifeq ($(target_type),elf) +# Link the object files into an ELF file. Also make sure the target is rebuilt +# if the common Makefile.avr.in or project config.mk is changed. +$(target): $(PRJ_PATH)/common/utils/make/Makefile.avr.in config.mk $(obj-y) + @echo $(MSG_LINKING) + $(Q)$(CC) $(l_flags) $(obj-y) $(libflags-gnu-y) -o $@ + @echo $(MSG_SIZE) + $(Q)$(SIZE) -Ax $@ + $(Q)$(SIZE) -Bx $@ +endif +endif + +# Create extended function listing from target output file. +%.lss: $(target) + @echo $(MSG_EXTENDED_LISTING) + $(Q)$(OBJDUMP) -h -S $< > $@ + +# Create symbol table from target output file. +%.sym: $(target) + @echo $(MSG_SYMBOL_TABLE) + $(Q)$(NM) -n $< > $@ + +# Create Intel HEX image from ELF output file. +%.hex: $(target) + @echo $(MSG_IHEX_IMAGE) + $(Q)$(OBJCOPY) -O ihex $(flashflags-gnu-y) $< $@ + +# Create EEPROM Intel HEX image from ELF output file. +%.eep: $(target) + @echo $(MSG_EEPROM_IMAGE) + $(Q)$(OBJCOPY) $(eepromflags-gnu-y) -O ihex $< $@ || exit 0 + +# Provide information about the detected host operating system. +.SECONDARY: info-os +info-os: + @echo $(MSG_INFO)$(os) build host detected + +# Build Doxygen generated documentation. +.PHONY: doc +doc: + @echo $(MSG_GENERATING_DOC) + $(Q)cd $(dir $(doccfg)) && $(DOCGEN) $(notdir $(doccfg)) + +# Clean Doxygen generated documentation. +.PHONY: cleandoc +cleandoc: + @$(if $(wildcard $(docdir)),echo $(MSG_CLEAN_DOC)) + $(Q)$(if $(wildcard $(docdir)),$(RM) --recursive $(docdir)) + +# Rebuild the Doxygen generated documentation. +.PHONY: rebuilddoc +rebuilddoc: cleandoc doc diff --git a/DSTAT1/src/asf/common/utils/stdio/read.c b/DSTAT1/src/asf/common/utils/stdio/read.c new file mode 100644 index 0000000000000000000000000000000000000000..d8b032748a1415f1c586a5dd9042efece3daec4d --- /dev/null +++ b/DSTAT1/src/asf/common/utils/stdio/read.c @@ -0,0 +1,161 @@ +/** + * \file + * + * \brief System-specific implementation of the \ref _read function used by + * the standard library. + * + * Copyright (c) 2009-2011 Atmel Corporation. All rights reserved. + * + * \asf_license_start + * + * 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. The name of Atmel may not be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * 4. This software may only be redistributed and used in connection with an + * Atmel microcontroller product. + * + * THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE + * EXPRESSLY AND SPECIFICALLY DISCLAIMED. IN NO EVENT SHALL ATMEL 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. + * + * \asf_license_stop + * + */ + +#include "compiler.h" + +/** + * \defgroup group_common_utils_stdio Standard I/O (stdio) + * + * Common standard I/O driver that implements the stdio + * read and write functions on AVR devices. + * + * \{ + */ + +extern volatile void *volatile stdio_base; +void (*ptr_get)(void volatile*,int*); + + +// IAR common implementation +#if ( defined(__ICCAVR32__) || defined(__ICCAVR__) || defined(__ICCARM__) ) + +#include + +_STD_BEGIN + +#pragma module_name = "?__read" + +/*! \brief Reads a number of bytes, at most \a size, into the memory area + * pointed to by \a buffer. + * + * \param handle File handle to read from. + * \param buffer Pointer to buffer to write read bytes to. + * \param size Number of bytes to read. + * + * \return The number of bytes read, \c 0 at the end of the file, or + * \c _LLIO_ERROR on failure. + */ +size_t __read(int handle, unsigned char *buffer, size_t size) +{ + int nChars = 0; + // This implementation only reads from stdin. + // For all other file handles, it returns failure. + if (handle != _LLIO_STDIN) { + return _LLIO_ERROR; + } + for (; size > 0; --size) { + int c; + ptr_get(stdio_base,&c); + if (c < 0) + break; + *buffer++ = c; + ++nChars; + } + return nChars; +} + +/*! \brief This routine is required by IAR DLIB library since EWAVR V6.10 + * the implementation is empty to be compatible with old IAR version. + */ +int __close(int handle) +{ + return 0; +} + +/*! \brief This routine is required by IAR DLIB library since EWAVR V6.10 + * the implementation is empty to be compatible with old IAR version. + */ +int remove(const char* val) +{ + return 0; +} + +/*! \brief This routine is required by IAR DLIB library since EWAVR V6.10 + * the implementation is empty to be compatible with old IAR version. + */ +long __lseek(int handle, long val, int val2) +{ + return val; +} + +_STD_END + +// GCC AVR32 implementation +#elif (defined(__GNUC__) && !defined(XMEGA)) + + +int __attribute__((weak)) +_read (int file, char * ptr, int len) +{ + int nChars = 0; + + if (file != 0) + return -1; + + for (; len > 0; --len) { + int c; + ptr_get(stdio_base,&c); + if (c < 0) + break; + *ptr++ = c; + ++nChars; + } + return nChars; +} + +// GCC AVR implementation +#elif (defined(__GNUC__) && defined(XMEGA)) + +int _read (int *f); // Remove GCC compiler warning + +int _read (int *f) +{ + int c; + ptr_get(stdio_base,&c); + return c; +} + +/** + * \} + */ + +#endif diff --git a/DSTAT1/src/asf/common/utils/stdio/stdio_usb/stdio_usb.c b/DSTAT1/src/asf/common/utils/stdio/stdio_usb/stdio_usb.c new file mode 100644 index 0000000000000000000000000000000000000000..07e8d683b9161ebb5d365473696d8299c4762ebe --- /dev/null +++ b/DSTAT1/src/asf/common/utils/stdio/stdio_usb/stdio_usb.c @@ -0,0 +1,120 @@ +/** + * \file + * + * \brief USB CDC Standard I/O Serial Management. + * + * This module defines support routines for a stdio serial interface to the + * Atmel Software Framework (ASF) common USB CDC service. + * + * Copyright (c) 2011-2012 Atmel Corporation. All rights reserved. + * + * \asf_license_start + * + * 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. The name of Atmel may not be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * 4. This software may only be redistributed and used in connection with an + * Atmel microcontroller product. + * + * THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE + * EXPRESSLY AND SPECIFICALLY DISCLAIMED. IN NO EVENT SHALL ATMEL 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. + * + * \asf_license_stop + * + */ + + +#include "stdio_usb.h" + +static bool stdio_usb_interface_enable = false; + +int stdio_usb_putchar (volatile void * usart, int data) +{ + /* A negative return value should be used to indicate that data + * was not written, but this doesn't seem to work with GCC libc. + */ + if (!stdio_usb_interface_enable) { + return 0; // -1 + } + + return udi_cdc_putc (data) ? 0 : -1; +} + +void stdio_usb_getchar (void volatile * usart, int * data) +{ + /* A negative return value should be used to indicate that data + * was not read, but this doesn't seem to work with GCC libc. + */ + if (!stdio_usb_interface_enable) { + *data = 0; // -1 + return; + } + + *data = udi_cdc_getc (); +} + +void stdio_usb_vbus_event(bool b_high) +{ + if (b_high) { + // Attach USB Device + udc_attach (); + } else { + // VBUS not present + udc_detach (); + } +} + +bool stdio_usb_enable(void) +{ + stdio_usb_interface_enable = true; + return true; +} + +void stdio_usb_disable(void) +{ + stdio_usb_interface_enable = false; +} + +void stdio_usb_init (volatile void * usart) +{ + stdio_base = usart; + ptr_put = stdio_usb_putchar; + ptr_get = stdio_usb_getchar; + + /* + * Start and attach USB CDC device interface for devices with + * integrated USB interfaces. Assume the VBUS is present if + * VBUS monitoring is not available. + */ + udc_start (); + + if (! udc_include_vbus_monitoring ()) { + stdio_usb_vbus_event (true); + } + + // For AVR GCC libc print redirection uses fdevopen. + + #if defined(XMEGA) && defined(__GNUC__) + fdevopen((int (*)(char, FILE*))(_write),(int (*)(FILE*))(_read)); + #endif +} + diff --git a/DSTAT1/src/asf/common/utils/stdio/stdio_usb/stdio_usb.h b/DSTAT1/src/asf/common/utils/stdio/stdio_usb/stdio_usb.h new file mode 100644 index 0000000000000000000000000000000000000000..6088530646db5ce98a8a905e2b8196a0295bb986 --- /dev/null +++ b/DSTAT1/src/asf/common/utils/stdio/stdio_usb/stdio_usb.h @@ -0,0 +1,126 @@ +/** + * \file + * + * \brief USB Standard I/O Serial Management. + * + * This file defines a useful set of functions for the Stdio Serial + * interface on AVR devices. + * + * Copyright (c) 2011 Atmel Corporation. All rights reserved. + * + * \asf_license_start + * + * 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. The name of Atmel may not be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * 4. This software may only be redistributed and used in connection with an + * Atmel microcontroller product. + * + * THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE + * EXPRESSLY AND SPECIFICALLY DISCLAIMED. IN NO EVENT SHALL ATMEL 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. + * + * \asf_license_stop + * + */ + +#ifndef _stdio_usb_h_ +#define _stdio_usb_h_ + +/** + * \defgroup group_common_utils_stdio_stdio_usb USB/CDC Standard I/O (stdio) + * \ingroup group_common_utils_stdio + * + * Standard I/O (stdio) management component that implements a stdio + * USB CDC interface on AVR devices. + * + * \{ + */ + +#include + +#include + +#include +#include + +extern int _write (char c, int *f); +extern int _read (int *f); + + +//! Pointer to the base of the USART module instance to use for stdio. +extern volatile void *volatile stdio_base; +//! Pointer to the external low level write function. +extern int (*ptr_put)(void volatile*,int); +//! Pointer to the external low level read function. +extern void (*ptr_get)(void volatile*,int*); + +/*! \brief Sends a character with the USART. + * + * \param usart Base address of the USART instance. + * \param data Character to write. + * + * \return Status. + * \retval 0 The character was written. + * \retval -1 The function timed out before the transmitter became ready. + */ +int stdio_usb_putchar (volatile void * usart, int data); + +/*! \brief Waits until a character is received, and returns it. + * + * \param usart Base address of the USART instance. + * \param data Data to read + * + * \return Nothing. + */ +void stdio_usb_getchar (void volatile * usart, int * data); + +/*! \brief Callback for VBUS level change event. + * + * \param b_high 1 if VBus is present + * + * \return Nothing. + */ +void stdio_usb_vbus_event (bool b_high); + +/*! \brief Enables the stdio in USB Serial Mode. + * + * \return \c 1 if function was successfully done, otherwise \c 0. + */ +bool stdio_usb_enable(void); + +/*! \brief Disables the stdio in USB Serial Mode. + * + * \return Nothing. + */ +void stdio_usb_disable(void); + +/*! \brief Initializes the stdio in USB Serial Mode. + * + * \return Nothing. + */ +void stdio_usb_init (volatile void * usart); + +/** + * \} + */ + +#endif // _stdio_usb_h_ diff --git a/DSTAT1/src/asf/common/utils/stdio/write.c b/DSTAT1/src/asf/common/utils/stdio/write.c new file mode 100644 index 0000000000000000000000000000000000000000..b1e3fbfe1ff95a56ca0c834765215bf9ccfdbb97 --- /dev/null +++ b/DSTAT1/src/asf/common/utils/stdio/write.c @@ -0,0 +1,141 @@ +/** + * \file + * + * \brief System-specific implementation of the \ref _write function used by + * the standard library. + * + * Copyright (c) 2009-2011 Atmel Corporation. All rights reserved. + * + * \asf_license_start + * + * 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. The name of Atmel may not be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * 4. This software may only be redistributed and used in connection with an + * Atmel microcontroller product. + * + * THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE + * EXPRESSLY AND SPECIFICALLY DISCLAIMED. IN NO EVENT SHALL ATMEL 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. + * + * \asf_license_stop + * + */ + +#include "compiler.h" + +/** + * \addtogroup group_common_utils_stdio + * + * \{ + */ + +volatile void *volatile stdio_base; +int (*ptr_put)(void volatile*,int); + + +#if ( defined(__ICCAVR32__) || defined(__ICCAVR__)) + +#include + +_STD_BEGIN + +#pragma module_name = "?__write" + +/*! \brief Writes a number of bytes, at most \a size, from the memory area + * pointed to by \a buffer. + * + * If \a buffer is zero then \ref __write performs flushing of internal buffers, + * if any. In this case, \a handle can be \c -1 to indicate that all handles + * should be flushed. + * + * \param handle File handle to write to. + * \param buffer Pointer to buffer to read bytes to write from. + * \param size Number of bytes to write. + * + * \return The number of bytes written, or \c _LLIO_ERROR on failure. + */ +size_t __write(int handle, const unsigned char *buffer, size_t size) +{ + size_t nChars = 0; + + if (buffer == 0){ + // This means that we should flush internal buffers. + return 0; + } + + // This implementation only writes to stdout and stderr. + // For all other file handles, it returns failure. + if (handle != _LLIO_STDOUT && handle != _LLIO_STDERR) { + return _LLIO_ERROR; + } + + for (; size != 0; --size) { + if (ptr_put(stdio_base, *buffer++) < 0) { + return _LLIO_ERROR; + } + ++nChars; + } + + return nChars; +} + +_STD_END + + +#elif (defined(__GNUC__) && !defined(XMEGA)) + +int __attribute__((weak)) +_write (int file, char * ptr, int len) +{ + int nChars = 0; + + if ( (file != 1) + && (file != 2) && (file!=3)) + return -1; + + for (; len != 0; --len) { + if (ptr_put(stdio_base, *ptr++) < 0) { + return -1; + } + ++nChars; + } + return nChars; +} + +#elif (defined(__GNUC__) && defined(XMEGA)) + +int _write (char c, int *f); // Remove GCC compiler warning + +int _write (char c, int *f) +{ + if (ptr_put(stdio_base,c) < 0) + { + return -1; + } + return 1; +} + +/** + * \} + */ + +#endif diff --git a/DSTAT1/src/asf/xmega/drivers/cpu/ccp.h b/DSTAT1/src/asf/xmega/drivers/cpu/ccp.h new file mode 100644 index 0000000000000000000000000000000000000000..ed9f780aee47f4dc53d684e2a39d1b6eed517f7c --- /dev/null +++ b/DSTAT1/src/asf/xmega/drivers/cpu/ccp.h @@ -0,0 +1,118 @@ +/** + * \file + * + * \brief Configuration Change Protection write functions + * + * Copyright (c) 2010-2012 Atmel Corporation. All rights reserved. + * + * \asf_license_start + * + * 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. The name of Atmel may not be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * 4. This software may only be redistributed and used in connection with an + * Atmel microcontroller product. + * + * THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE + * EXPRESSLY AND SPECIFICALLY DISCLAIMED. IN NO EVENT SHALL ATMEL 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. + * + * \asf_license_stop + * + */ +#ifndef CPU_CCP_H +#define CPU_CCP_H +#include + +/** + * \defgroup ccp_group Configuration Change Protection + * + * See \ref ccp_quickstart. + * + * Function for writing to protected IO registers. + * @{ + */ + +#if defined(__DOXYGEN__) +//! \name IAR Memory Model defines. +//@{ + +/** + * \def CONFIG_MEMORY_MODEL_TINY + * \brief Configuration symbol to enable 8 bit pointers. + * + */ +# define CONFIG_MEMORY_MODEL_TINY + +/** + * \def CONFIG_MEMORY_MODEL_SMALL + * \brief Configuration symbol to enable 16 bit pointers. + * \note If no memory model is defined, SMALL is default. + * + */ +# define CONFIG_MEMORY_MODEL_SMALL + + +/** + * \def CONFIG_MEMORY_MODEL_LARGE + * \brief Configuration symbol to enable 24 bit pointers. + * + */ +# define CONFIG_MEMORY_MODEL_LARGE + +//@} +#endif + + +/** + * \brief Write to a CCP-protected 8-bit I/O register + * + * \param addr Address of the I/O register + * \param value Value to be written + * + * \note Using IAR Embedded workbench, the choice of memory model has an impact + * on calling convention. The memory model is not visible to the + * preprocessor, so it must be defined in the Assembler preprocessor directives. + */ +extern void ccp_write_io(void *addr, uint8_t value); + +/** @} */ + +/** + * \page ccp_quickstart Quick start guide for CCP driver + * + * This is the quick start guide for the \ref ccp_group + * "Configuration Change Protection (CCP) driver", with step-by-step + * instructions on how to use the driver. + * + * The use case contains a code fragment, and this can be copied into, e.g., + * the main application function. + * + * \section ccp_basic_use_case Basic use case + * In this use case, the CCP is used to write to the protected XMEGA Clock + * Control register. + * + * \subsection ccp_basic_use_case_setup_flow Workflow + * -# call CCP write io to change system clock selection: + * - \code ccp_write_io((uint8_t *)&CLK.CTRL, CLK_SCLKSEL_RC32M_gc); \endcode + */ + +#endif /* CPU_CCP_H */ diff --git a/DSTAT1/src/asf/xmega/drivers/cpu/ccp.s b/DSTAT1/src/asf/xmega/drivers/cpu/ccp.s new file mode 100644 index 0000000000000000000000000000000000000000..40f7d0cd3c26a3b10d122a523a776bfb0bae6b10 --- /dev/null +++ b/DSTAT1/src/asf/xmega/drivers/cpu/ccp.s @@ -0,0 +1,98 @@ +/** + * \file + * + * \brief Configuration Change Protection + * + * Copyright (c) 2009 Atmel Corporation. All rights reserved. + * + * \asf_license_start + * + * 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. The name of Atmel may not be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * 4. This software may only be redistributed and used in connection with an + * Atmel microcontroller product. + * + * THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE + * EXPRESSLY AND SPECIFICALLY DISCLAIMED. IN NO EVENT SHALL ATMEL 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. + * + * \asf_license_stop + * + */ +#include + +//! Value to write to CCP for access to protected IO registers. +#define CCP_IOREG 0xd8 + + /* + * GNU and IAR use different calling conventions. Since this is + * a very small and simple function to begin with, it's easier + * to implement it twice than to deal with the differences + * within a single implementation. + * + * Interrupts are disabled by hardware during the timed + * sequence, so there's no need to save/restore interrupt state. + */ + + PUBLIC_FUNCTION(ccp_write_io) + +#if defined(__GNUC__) + + out RAMPZ, r1 // Reset bits 23:16 of Z + movw r30, r24 // Load addr into Z + ldi r18, CCP_IOREG // Load magic CCP value + out CCP, r18 // Start CCP handshake + st Z, r22 // Write value to I/O register + ret // Return to caller + +#elif defined(__IAR_SYSTEMS_ASM__) + +# if !defined(CONFIG_MEMORY_MODEL_TINY) && !defined(CONFIG_MEMORY_MODEL_SMALL) \ + && !defined(CONFIG_MEMORY_MODEL_LARGE) +# define CONFIG_MEMORY_MODEL_SMALL +# endif + ldi r20, 0 + out RAMPZ, r20 // Reset bits 23:16 of Z +# if defined(CONFIG_MEMORY_MODEL_TINY) + mov r31, r20 // Reset bits 8:15 of Z + mov r30, r16 // Load addr into Z +# else + movw r30, r16 // Load addr into Z +# endif + ldi r21, CCP_IOREG // Load magic CCP value + out CCP, r21 // Start CCP handshake +# if defined(CONFIG_MEMORY_MODEL_TINY) + st Z, r17 // Write value to I/O register +# elif defined(CONFIG_MEMORY_MODEL_SMALL) + st Z, r18 // Write value to I/O register +# elif defined(CONFIG_MEMORY_MODEL_LARGE) + st Z, r19 // Write value to I/O register +# else +# error Unknown memory model in use, no idea how registers should be accessed +# endif + ret +#else +# error Unknown assembler +#endif + + END_FUNC(ccp_write_io) + END_FILE() diff --git a/DSTAT1/src/asf/xmega/drivers/cpu/xmega_reset_cause.h b/DSTAT1/src/asf/xmega/drivers/cpu/xmega_reset_cause.h new file mode 100644 index 0000000000000000000000000000000000000000..f3c45ddb481eb0a4dd85eaac60d3faf9e22030d1 --- /dev/null +++ b/DSTAT1/src/asf/xmega/drivers/cpu/xmega_reset_cause.h @@ -0,0 +1,103 @@ +/** + * \file + * + * \brief Chip-specific reset cause functions + * + * Copyright (c) 2010-2012 Atmel Corporation. All rights reserved. + * + * \asf_license_start + * + * 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. The name of Atmel may not be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * 4. This software may only be redistributed and used in connection with an + * Atmel microcontroller product. + * + * THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE + * EXPRESSLY AND SPECIFICALLY DISCLAIMED. IN NO EVENT SHALL ATMEL 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. + * + * \asf_license_stop + * + */ +#ifndef XMEGA_DRIVERS_CPU_RESET_CAUSE_H +#define XMEGA_DRIVERS_CPU_RESET_CAUSE_H + +#include "compiler.h" +#include "ccp.h" + +/** + * \ingroup reset_cause_group + * \defgroup xmega_reset_cause_group XMEGA reset cause + * + * See \ref reset_cause_quickstart + * + * @{ + */ + +/** + * \brief Chip-specific reset cause type capable of holding all chip reset + * causes. Typically reflects the size of the reset cause register. + */ +typedef uint8_t reset_cause_t; + +//! \internal \name Chip-specific reset causes +//@{ +//! \internal External reset cause +#define CHIP_RESET_CAUSE_EXTRST RST_EXTRF_bm +//! \internal brown-out detected reset cause, same as for CPU +#define CHIP_RESET_CAUSE_BOD_IO RST_BORF_bm +//! \internal Brown-out detected reset cause, same as for I/O +#define CHIP_RESET_CAUSE_BOD_CPU RST_BORF_bm +//! \internal On-chip debug system reset cause +#define CHIP_RESET_CAUSE_OCD RST_PDIRF_bm +//! \internal Power-on-reset reset cause +#define CHIP_RESET_CAUSE_POR RST_PORF_bm +//! \internal Software reset reset cause +#define CHIP_RESET_CAUSE_SOFT RST_SRF_bm +//! \internal Spike detected reset cause +#define CHIP_RESET_CAUSE_SPIKE RST_SDRF_bm +//! \internal Watchdog timeout reset cause +#define CHIP_RESET_CAUSE_WDT RST_WDRF_bm +//@} + +static inline reset_cause_t reset_cause_get_causes(void) +{ + return (reset_cause_t)RST.STATUS; +} + +static inline void reset_cause_clear_causes(reset_cause_t causes) +{ + RST.STATUS = causes; +} + +static inline void reset_do_soft_reset(void) +{ + ccp_write_io((void *)&RST.CTRL, RST_SWRST_bm); + + while (1) { + /* Intentionally empty. */ + } +} + +//! @} + +#endif /* XMEGA_DRIVERS_CPU_RESET_CAUSE_H */ diff --git a/DSTAT1/src/asf/xmega/drivers/ioport/ioport.c b/DSTAT1/src/asf/xmega/drivers/ioport/ioport.c new file mode 100644 index 0000000000000000000000000000000000000000..d769057b3026e08def88c2a8197e488a6d6d8789 --- /dev/null +++ b/DSTAT1/src/asf/xmega/drivers/ioport/ioport.c @@ -0,0 +1,65 @@ +/** + * \file + * + * \brief I/O Ports software driver interface. + * + * Copyright (c) 2010 Atmel Corporation. All rights reserved. + * + * \asf_license_start + * + * 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. The name of Atmel may not be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * 4. This software may only be redistributed and used in connection with an + * Atmel microcontroller product. + * + * THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE + * EXPRESSLY AND SPECIFICALLY DISCLAIMED. IN NO EVENT SHALL ATMEL 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. + * + * \asf_license_stop + * + */ +#include "ioport.h" + +void ioport_configure_port_pin(void *port, pin_mask_t pin_mask,port_pin_flags_t flags) +{ + uint8_t pin; + + for (pin = 0; pin < 8; pin++) { + if (pin_mask & (1 << pin)) { + *((uint8_t*)port+PORT_PIN0CTRL+pin)=flags; + } + } + /* Select direction and initial pin state */ + if (flags & IOPORT_DIR_OUTPUT) { + if (flags & IOPORT_INIT_HIGH) { + *((uint8_t*)port+PORT_OUTSET)=pin_mask; + } + else { + *((uint8_t*)port+PORT_OUTCLR)=pin_mask; + } + *((uint8_t*)port+PORT_DIRSET)=pin_mask; + } + else { + *((uint8_t*)port+PORT_DIRCLR)=pin_mask; + } +} diff --git a/DSTAT1/src/asf/xmega/drivers/ioport/ioport.h b/DSTAT1/src/asf/xmega/drivers/ioport/ioport.h new file mode 100644 index 0000000000000000000000000000000000000000..d1a77855241fbcc6d420145c9105fbf5fb14d992 --- /dev/null +++ b/DSTAT1/src/asf/xmega/drivers/ioport/ioport.h @@ -0,0 +1,421 @@ +/** + * \file + * + * \brief I/O Ports software driver interface. + * + * Copyright (c) 2010-2011 Atmel Corporation. All rights reserved. + * + * \asf_license_start + * + * 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. The name of Atmel may not be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * 4. This software may only be redistributed and used in connection with an + * Atmel microcontroller product. + * + * THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE + * EXPRESSLY AND SPECIFICALLY DISCLAIMED. IN NO EVENT SHALL ATMEL 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. + * + * \asf_license_stop + * + */ +#ifndef IOPORT_H +#define IOPORT_H + +#include + +// Some parts (XMEGAB3) do not have PORT A reference +#ifndef PORTA +# define PORTA (*(PORT_t *) 0x0600) +#endif + +/** + * \defgroup port_driver_group IO PORT Driver + * + * This is a driver implementation for the I/O ports peripheral. The I/O ports + * peripheral can be found on XMEGA devices and it controls and configures the + * I/O pins. + * @{ + */ + +/** + * \brief A bitmask representing a set of pins on a port + * + * Starting from pin 0 as the LSB, each bit in the mask corresponds to + * a pin on some port. Each '1' bit includes the corresponding pin in + * the set. + */ +typedef uint8_t pin_mask_t; + +/** + * \brief A PORT pin + * + * This type is used to describe the PORT pins on the part. + */ +typedef uint8_t port_pin_t; + +/** + * \brief Pin configuration flags + * + * This is a bitmask containing configuration flags for the pins that shall be + * configured. + */ +typedef uint16_t port_pin_flags_t; + +/** + * \brief A port id + * + * This type is used to describe the port id on the part (0 is PORTA). + */ +typedef uint8_t port_id_t; + +//! \name Input/Output Configuration Flags +//@{ +#define IOPORT_DIR_INPUT (0 << 8) //!< Pin is Input +#define IOPORT_DIR_OUTPUT (1 << 8) //!< Pin is Output +//@} + +//! \name Initial Output State Flags +//@{ +#define IOPORT_INIT_LOW (0 << 9) //!< Initial Ouptput State is Low +#define IOPORT_INIT_HIGH (1 << 9) //!< Initial Ouptput State is High +//@} + +//! \name Input/Sense Configuration Flags +//@{ +#define IOPORT_BOTHEDGES (0 << 0) //!< Sense Both Edges +#define IOPORT_RISING (1 << 0) //!< Sense Risign Edge +#define IOPORT_FALLING (2 << 0) //!< Sense Falling Edge +#define IOPORT_LEVEL (3 << 0) //!< Sense Low Level +#define IOPORT_INPUT_DISABLE (7 << 0) //!< Input Buffer Disabled +//@} + +//! \name Output and Pull Configuration Flags +//@{ +#define IOPORT_TOTEM (0 << 3) //!< Normal push/pull output +#define IOPORT_BUSKEEPER (1 << 3) //!< Bus Keeper +#define IOPORT_PULL_DOWN (2 << 3) //!< Pull-Down (when input) +#define IOPORT_PULL_UP (3 << 3) //!< Pull-Up (when input) +#define IOPORT_WIRED_OR (4 << 3) //!< Wired OR +#define IOPORT_WIRED_AND (5 << 3) //!< Wired AND +#define IOPORT_WIRED_OR_PULL_DOWN (6 << 3) //!< Wired OR and Pull-Down +#define IOPORT_WIRED_AND_PULL_UP (7 << 3) //!< Wired AND and Pull-Up +//@} + +//! \name Inverted I/O Configuration Flags +//@{ +#define IOPORT_INV_ENABLED (1 << 6) //!< I/O is Inverted +#define IOPORT_INV_DISABLE (0 << 6) //!< I/O is Not Inverted +//@} + +//! \name Slew Rate Limit Configuration Flags +//@{ +#define IOPORT_SRL_ENABLED (1 << 7) //!< Slew Rate Limit Enabled +#define IOPORT_SRL_DISABLED (0 << 7) //!< Slew Rate Limit Disabled +//@} + + +/** + * \brief Create a PORT pin number + * + * This macro creates a PORT pin number from a pin on a port. The PORT pin + * number can be used with the functions provided from this driver. + * + * \param port Port name e.g. PORTA. + * \param pin Pin number on the port, valid values are 0 to 7. + */ +#define IOPORT_CREATE_PIN(port, pin) ((PORT_##port) + (pin)) + +/** + * \brief Create a pointer to a port from a PORT pin number + * + * It is assumed that all ports are lined up after PORTA in the memory map like + * it is described in the XMEGA A manual. + * Otherwise we have to do a switch case here. + * + * \param pin PORT pin number. This number can be generated by the macro + * CREATE_PORT_PIN. + * \return Pointer to the port on which the pin is located. + */ +static inline PORT_t *ioport_pin_to_port(port_pin_t pin) +{ + // Each port has an offset of 0x20 + return (PORT_t *)((uintptr_t)&PORTA + (pin >> 3) * 0x20); +} + +/** + * \brief Create a pointer to a port from a PORT id number + * + * It is assumed that all ports are lined up after PORTA in the memory map like + * it is described in the XMEGA A manual. + * Otherwise we have to do a switch case here. + * + * \param port PORT id number. (PORTA is 0, PORTB is 1 ...) + * \return Pointer to the port on which the pin is located. + */ +static inline PORT_t *ioport_id_pin_to_port(port_id_t port) +{ + // Each port has an offset of 0x20 + return (PORT_t *)((uintptr_t)&PORTA + port * 0x20); +} + +/** + * \brief Generate port pin mask form PORT pin number + * + * \param pin PORT pin number. + * \return Pin mask. + */ +static inline pin_mask_t ioport_pin_to_mask(port_pin_t pin) +{ + return 1U << (pin & 0x7); +} + +/** + * \brief Configure the IO PORT pin function for a set of pins on a port + * + * \param port Pointer to the port + * \param pin_mask Mask containing the pins that should be configured + * \param flags Bitmask of flags specifying additional configuration + * parameters. + */ +extern void ioport_configure_port_pin(void *port, pin_mask_t pin_mask, + port_pin_flags_t flags); + +/** + * \brief Select the port function for a single pin + * + * \param pin The pin to configure + * \param flags Bitmask of flags specifying additional configuration + * parameters. + */ +static inline void ioport_configure_pin(port_pin_t pin, port_pin_flags_t flags) +{ + ioport_configure_port_pin(ioport_pin_to_port(pin), ioport_pin_to_mask(pin), flags); +} + + +/** + * \brief Configure a group of I/O pins on a specified port number + * + * \param port The port number + * \param pin_mask The pin mask to configure + * \param flags Bitmask of flags specifying additional configuration + * parameters. + */ +static inline void ioport_configure_group(port_id_t port, pin_mask_t pin_mask, port_pin_flags_t flags) +{ + ioport_configure_port_pin(ioport_id_pin_to_port(port), pin_mask, flags); +} + + +/** + * \internal + * \name PORT Pin Numbering + * + * These macros are used to generate PORT pin numbers for each port with the + * CREATE_PORT_PIN macro. Each port has 8 pins so e.g. the first pin on PORTB + * gets number 8, first pin on PORTC gets 16 ... + */ +//@{ +#define PORT_PORTA (0 * 8) +#define PORT_PORTB (1 * 8) +#define PORT_PORTC (2 * 8) +#define PORT_PORTD (3 * 8) +#define PORT_PORTE (4 * 8) +#define PORT_PORTF (5 * 8) +#define PORT_PORTG (6 * 8) +#define PORT_PORTH (7 * 8) +#define PORT_PORTJ (8 * 8) +#define PORT_PORTK (9 * 8) +#define PORT_PORTL (10 * 8) +#define PORT_PORTM (11 * 8) +#define PORT_PORTN (12 * 8) +#define PORT_PORTP (13 * 8) +#define PORT_PORTQ (14 * 8) +#define PORT_PORTR (15 * 8) +//@} + +/** + * \internal + * \name PORT fields struture offset + * + * These macros are used to compute the field offset nummber with the PORT_t struture. + */ +//@{ +#define PORT_DIR 0x00 //!< Data Direction +#define PORT_DIRSET 0x01 //!< Data Direction Set +#define PORT_DIRCLR 0x02 //!< Data Direction Clear +#define PORT_DIRTGL 0x03 //!< Data Direction Toggle +#define PORT_OUT 0x04 //!< Data Output Value +#define PORT_OUTSET 0x05 //!< Data Output Value Set +#define PORT_OUTCLR 0x06 //!< Data Output Value Clear +#define PORT_OUTTGL 0x07 //!< Data Output Value Toggle +#define PORT_IN 0x08 //!< Data Input Value +#define PORT_INTCTRL 0x09 //!< Interrupt Control +#define PORT_INT0MASK 0x0A //!< Interrupt 0 Mask +#define PORT_INT1MASK 0x0B //!< Interrupt 1 Mask +#define PORT_INTFLAGS 0x0C //!< Interrupt Flags +#define PORT_PIN0CTRL 0x10 //!< Pin 0 Configuration +#define PORT_PIN1CTRL 0x11 //!< Pin 1 Configuration +#define PORT_PIN2CTRL 0x12 //!< Pin 2 Configuration +#define PORT_PIN3CTRL 0x13 //!< Pin 3 Configuration +#define PORT_PIN4CTRL 0x14 //!< Pin 4 Configuration +#define PORT_PIN5CTRL 0x15 //!< Pin 5 Configuration +#define PORT_PIN6CTRL 0x16 //!< Pin 6 Configuration +#define PORT_PIN7CTRL 0x17 //!< Pin 7 Configuration +//@} + + +/** + * \brief Drive a PORT pin to a given state + * + * This function will only have an effect if \a pin is configured as + * an output. + * + * \param pin A number identifying the pin to act on. + * \param value The desired state of the pin. \a true means drive the + * pin high (towards Vdd), while \a false means drive the pin low + * (towards Vss). + */ +static inline void ioport_set_value(port_pin_t pin, bool value) +{ + PORT_t *port = ioport_pin_to_port(pin); + if (value) + port->OUTSET=ioport_pin_to_mask(pin); + else + port->OUTCLR=ioport_pin_to_mask(pin); +} + +/** + * \brief Drive a PORT pin to a low level + * + * This function will only have an effect if \a pin is configured as + * an output. + * + * \param pin A number identifying the pin to act on. + */ +static inline void ioport_set_pin_low(port_pin_t pin) +{ + PORT_t *port = ioport_pin_to_port(pin); + port->OUTCLR=ioport_pin_to_mask(pin); +} + +/** + * \brief Drive a PORT pin to a high level + * + * This function will only have an effect if \a pin is configured as + * an output. + * + * \param pin A number identifying the pin to act on. + */ +static inline void ioport_set_pin_high(port_pin_t pin) +{ + PORT_t *port = ioport_pin_to_port(pin); + port->OUTSET=ioport_pin_to_mask(pin); +} + +/** + * \brief Read the current state of a PORT pin + * + * \param pin A number identifying the pin to read. + * \retval true The pin is currently high (close to Vdd) + * \retval false The pin is currently low (close to Vss) + */ +static inline bool ioport_get_value(port_pin_t pin) +{ + PORT_t *port = ioport_pin_to_port(pin); + return port->IN&ioport_pin_to_mask(pin); +} + +/** + * \brief Read the current state of a PORT pin and test high level + * + * \param pin A number identifying the pin to read. + * \retval true The pin is currently high (close to Vdd) + * \retval false The pin is currently low (close to Vss) + */ +static inline bool ioport_pin_is_high(port_pin_t pin) +{ + PORT_t *port = ioport_pin_to_port(pin); + return port->IN&ioport_pin_to_mask(pin); +} + +/** + * \brief Read the current state of a PORT pin and test high level + * + * \param pin A number identifying the pin to read. + * \retval true The pin is currently high (close to Vdd) + * \retval false The pin is currently low (close to Vss) + */ +static inline bool ioport_pin_is_low(port_pin_t pin) +{ + PORT_t *port = ioport_pin_to_port(pin); + return (~port->IN&ioport_pin_to_mask(pin)); +} +/** + * \brief Toggle the current state of a PORT pin + * + * \param pin A number identifying the pin to act on. + */ +static inline void ioport_toggle_pin(port_pin_t pin) +{ + pin_mask_t pin_mask = ioport_pin_to_mask(pin); + PORT_t *port = ioport_pin_to_port(pin); + port->OUTTGL = pin_mask; +} + +/*! \brief Drives a group of I/O pin of a port to high level. + * + * \param port_id The port number. + * \param port_mask The mask. + */ +static inline void ioport_set_group_high(port_id_t port_id,pin_mask_t port_mask) +{ + PORT_t *port = ioport_id_pin_to_port(port_id); + port->OUTSET = port_mask; +} + +/*! \brief Drives a group of I/O pin of a port to low level. + * + * \param port_id The port number. + * \param port_mask The mask. + */ +static inline void ioport_set_group_low(port_id_t port_id,pin_mask_t port_mask) +{ + PORT_t *port = ioport_id_pin_to_port(port_id); + port->OUTCLR = port_mask; +} + +/*! \brief Toggles a group of I/O pin of a port. + * + * \param port_id The port number. + * \param port_mask The mask. + */ +static inline void ioport_tgl_group(port_id_t port_id,pin_mask_t port_mask) +{ + PORT_t *port = ioport_id_pin_to_port(port_id); + port->OUTTGL = port_mask; +} + +/*@}*/ + +#endif /* IOPORT_H */ diff --git a/DSTAT1/src/asf/xmega/drivers/nvm/nvm.c b/DSTAT1/src/asf/xmega/drivers/nvm/nvm.c new file mode 100644 index 0000000000000000000000000000000000000000..7ca3713311b2c23aaa5b6d447ca41cd7ae79134b --- /dev/null +++ b/DSTAT1/src/asf/xmega/drivers/nvm/nvm.c @@ -0,0 +1,755 @@ +/** + * \file + * + * \brief Non Volatile Memory controller driver + * + * Copyright (C) 2010-2012 Atmel Corporation. All rights reserved. + * + * \asf_license_start + * + * 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. The name of Atmel may not be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * 4. This software may only be redistributed and used in connection with an + * Atmel microcontroller product. + * + * THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE + * EXPRESSLY AND SPECIFICALLY DISCLAIMED. IN NO EVENT SHALL ATMEL 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. + * + * \asf_license_stop + * + */ +#include "compiler.h" +#include "ccp.h" +#include "nvm.h" +#include + +/** + * \weakgroup nvm_signature_group + * @{ + */ + +/** + * \brief Read the device serial + * + * This function returns the device serial stored in the device. + * + * \note This function is modifying the NVM.CMD register. + * If the application are using program space access in interrupts + * (__flash pointers in IAR EW or pgm_read_byte in GCC) interrupts + * needs to be disabled when running EEPROM access functions. If not + * the program space reads will be corrupted. + * + * \retval storage Pointer to the structure where to store the device serial + */ +void nvm_read_device_serial(struct nvm_device_serial *storage) +{ + storage->lotnum0 = nvm_read_production_signature_row( + nvm_get_production_signature_row_offset(LOTNUM0)); + storage->lotnum1 = nvm_read_production_signature_row( + nvm_get_production_signature_row_offset(LOTNUM1)); + storage->lotnum2 = nvm_read_production_signature_row( + nvm_get_production_signature_row_offset(LOTNUM2)); + storage->lotnum3 = nvm_read_production_signature_row( + nvm_get_production_signature_row_offset(LOTNUM3)); + storage->lotnum4 = nvm_read_production_signature_row( + nvm_get_production_signature_row_offset(LOTNUM4)); + storage->lotnum5 = nvm_read_production_signature_row( + nvm_get_production_signature_row_offset(LOTNUM5)); + + storage->wafnum = nvm_read_production_signature_row( + nvm_get_production_signature_row_offset(WAFNUM)); + + storage->coordx0 = nvm_read_production_signature_row( + nvm_get_production_signature_row_offset(COORDX0)); + storage->coordx1 = nvm_read_production_signature_row( + nvm_get_production_signature_row_offset(COORDX1)); + storage->coordy0 = nvm_read_production_signature_row( + nvm_get_production_signature_row_offset(COORDY0)); + storage->coordy1 = nvm_read_production_signature_row( + nvm_get_production_signature_row_offset(COORDY1)); +} + +//! @} + +/** + * \weakgroup nvm_eeprom_group + * @{ + */ + +/** + * \brief Read one byte from EEPROM using IO mapping. + * + * This function reads one byte from EEPROM using IO-mapped access. + * If memory mapped EEPROM is enabled, this function will not work. + * + * \param addr EEPROM address, between 0 and EEPROM_SIZE + * + * \return Byte value read from EEPROM. + */ +uint8_t nvm_eeprom_read_byte(eeprom_addr_t addr) +{ + Assert(addr <= EEPROM_SIZE); + + /* Wait until NVM is ready */ + nvm_wait_until_ready(); + + /* Set address to read from */ + NVM.ADDR2 = 0x00; + NVM.ADDR1 = (addr >> 8) & 0xFF; + NVM.ADDR0 = addr & 0xFF; + + /* Issue EEPROM Read command */ + nvm_issue_command(NVM_CMD_READ_EEPROM_gc); + + return NVM.DATA0; +} + +/** + * \brief Read buffer within the eeprom + * + * \param address the address to where to read + * \param buf pointer to the data + * \param len the number of bytes to read + */ +void nvm_eeprom_read_buffer(eeprom_addr_t address, void *buf, uint16_t len) +{ + nvm_wait_until_ready(); + eeprom_enable_mapping(); + memcpy( buf,(void*)(address+MAPPED_EEPROM_START), len ); + eeprom_disable_mapping(); +} + + +/** + * \brief Write one byte to EEPROM using IO mapping. + * + * This function writes one byte to EEPROM using IO-mapped access. + * If memory mapped EEPROM is enabled, this function will not work. + * This function will cancel all ongoing EEPROM page buffer loading + * operations, if any. + * + * \param address EEPROM address (max EEPROM_SIZE) + * \param value Byte value to write to EEPROM. + */ +void nvm_eeprom_write_byte(eeprom_addr_t address, uint8_t value) +{ + uint8_t old_cmd; + + /* Flush buffer to make sure no unintentional data is written and load + * the "Page Load" command into the command register. + */ + old_cmd = NVM.CMD; + nvm_eeprom_flush_buffer(); + // Wait until NVM is ready + nvm_wait_until_ready(); + + NVM.CMD = NVM_CMD_LOAD_EEPROM_BUFFER_gc; + + Assert(address <= EEPROM_SIZE); + + // Set address to write to + NVM.ADDR2 = 0x00; + NVM.ADDR1 = (address >> 8) & 0xFF; + NVM.ADDR0 = address & 0xFF; + + // Load data to write, which triggers the loading of EEPROM page buffer + NVM.DATA0 = value; + + /* Issue EEPROM Atomic Write (Erase&Write) command. Load command, write + * the protection signature and execute command. + */ + NVM.CMD = NVM_CMD_ERASE_WRITE_EEPROM_PAGE_gc; + nvm_exec(); + NVM.CMD = old_cmd; +} + +/** + * \brief Write buffer within the eeprom + * + * \param address the address to where to write + * \param buf pointer to the data + * \param len the number of bytes to write + */ +void nvm_eeprom_erase_and_write_buffer(eeprom_addr_t address, const void *buf, uint16_t len) +{ + while (len) { + if (((address%EEPROM_PAGE_SIZE)==0) && (len>=EEPROM_PAGE_SIZE)) { + // A full page can be written + nvm_eeprom_load_page_to_buffer((uint8_t*)buf); + nvm_eeprom_atomic_write_page(address/EEPROM_PAGE_SIZE); + address += EEPROM_PAGE_SIZE; + buf = (uint8_t*)buf + EEPROM_PAGE_SIZE; + len -= EEPROM_PAGE_SIZE; + } else { + nvm_eeprom_write_byte(address++, *(uint8_t*)buf); + buf = (uint8_t*)buf + 1; + len--; + } + } +} + + +/** + * \brief Flush temporary EEPROM page buffer. + * + * This function flushes the EEPROM page buffers. This function will cancel + * any ongoing EEPROM page buffer loading operations, if any. + * This function also works for memory mapped EEPROM access. + * + * \note An EEPROM write operations will automatically flush the buffer for you. + * \note The function does not preserve the value of the NVM.CMD register + */ +void nvm_eeprom_flush_buffer(void) +{ + // Wait until NVM is ready + nvm_wait_until_ready(); + + // Flush EEPROM page buffer if necessary + if ((NVM.STATUS & NVM_EELOAD_bm) != 0) { + NVM.CMD = NVM_CMD_ERASE_EEPROM_BUFFER_gc; + nvm_exec(); + } +} + +/** + * \brief Load single byte into temporary page buffer. + * + * This function loads one byte into the temporary EEPROM page buffers. + * If memory mapped EEPROM is enabled, this function will not work. + * Make sure that the buffer is flushed before starting to load bytes. + * Also, if multiple bytes are loaded into the same location, they will + * be ANDed together, thus 0x55 and 0xAA will result in 0x00 in the buffer. + * + * \note Only one page buffer exist, thus only one page can be loaded with + * data and programmed into one page. If data needs to be written to + * different pages, the loading and writing needs to be repeated. + * + * \param byte_addr EEPROM Byte address, between 0 and EEPROM_PAGE_SIZE. + * \param value Byte value to write to buffer. + */ +void nvm_eeprom_load_byte_to_buffer(uint8_t byte_addr, uint8_t value) +{ + uint8_t old_cmd; + old_cmd = NVM.CMD; + + // Wait until NVM is ready + nvm_wait_until_ready(); + + NVM.CMD = NVM_CMD_LOAD_EEPROM_BUFFER_gc; + + // Set address + NVM.ADDR2 = 0x00; + NVM.ADDR1 = 0x00; + NVM.ADDR0 = byte_addr & 0xFF; + + // Set data, which triggers loading of EEPROM page buffer + NVM.DATA0 = value; + + NVM.CMD = old_cmd; +} + + +/** + * \brief Load entire page into temporary EEPROM page buffer. + * + * This function loads an entire EEPROM page from an SRAM buffer to + * the EEPROM page buffers. If memory mapped EEPROM is enabled, this + * function will not work. Make sure that the buffer is flushed before + * starting to load bytes. + * + * \note Only the lower part of the address is used to address the buffer. + * Therefore, no address parameter is needed. In the end, the data + * is written to the EEPROM page given by the address parameter to the + * EEPROM write page operation. + * + * \param values Pointer to SRAM buffer containing an entire page. + */ +void nvm_eeprom_load_page_to_buffer(const uint8_t *values) +{ + uint8_t old_cmd; + old_cmd = NVM.CMD; + + // Wait until NVM is ready + nvm_wait_until_ready(); + + NVM.CMD = NVM_CMD_LOAD_EEPROM_BUFFER_gc; + + /* Set address to zero, as only the lower bits matters. ADDR0 is + * maintained inside the loop below. + */ + NVM.ADDR2 = 0x00; + NVM.ADDR1 = 0x00; + + // Load multible bytes into page buffer + uint8_t i; + for (i = 0; i < EEPROM_PAGE_SIZE; ++i) { + NVM.ADDR0 = i; + NVM.DATA0 = *values; + ++values; + } + NVM.CMD = old_cmd; +} + +/** + * \brief Erase and write bytes from page buffer into EEPROM. + * + * This function writes the contents of an already loaded EEPROM page + * buffer into EEPROM memory. + * + * As this is an atomic write, the page in EEPROM will be erased + * automatically before writing. Note that only the page buffer locations + * that have been loaded will be used when writing to EEPROM. Page buffer + * locations that have not been loaded will be left untouched in EEPROM. + * + * \param page_addr EEPROM Page address, between 0 and EEPROM_SIZE/EEPROM_PAGE_SIZE + */ +void nvm_eeprom_atomic_write_page(uint8_t page_addr) +{ + // Wait until NVM is ready + nvm_wait_until_ready(); + + // Calculate page address + uint16_t address = (uint16_t)(page_addr * EEPROM_PAGE_SIZE); + + Assert(address <= EEPROM_SIZE); + + // Set address + NVM.ADDR2 = 0x00; + NVM.ADDR1 = (address >> 8) & 0xFF; + NVM.ADDR0 = address & 0xFF; + + // Issue EEPROM Atomic Write (Erase&Write) command + nvm_issue_command(NVM_CMD_ERASE_WRITE_EEPROM_PAGE_gc); +} + +/** + * \brief Write (without erasing) EEPROM page. + * + * This function writes the contents of an already loaded EEPROM page + * buffer into EEPROM memory. + * + * As this is a split write, the page in EEPROM will _not_ be erased + * before writing. + * + * \param page_addr EEPROM Page address, between 0 and EEPROM_SIZE/EEPROM_PAGE_SIZE + */ +void nvm_eeprom_split_write_page(uint8_t page_addr) +{ + // Wait until NVM is ready + nvm_wait_until_ready(); + + // Calculate page address + uint16_t address = (uint16_t)(page_addr * EEPROM_PAGE_SIZE); + + Assert(address <= EEPROM_SIZE); + + // Set address + NVM.ADDR2 = 0x00; + NVM.ADDR1 = (address >> 8) & 0xFF; + NVM.ADDR0 = address & 0xFF; + + // Issue EEPROM Split Write command + nvm_issue_command(NVM_CMD_WRITE_EEPROM_PAGE_gc); +} + +/** + * \brief Fill temporary EEPROM page buffer with value. + * + * This fills the the EEPROM page buffers with a given value. + * If memory mapped EEPROM is enabled, this function will not work. + * + * \note Only the lower part of the address is used to address the buffer. + * Therefore, no address parameter is needed. In the end, the data + * is written to the EEPROM page given by the address parameter to the + * EEPROM write page operation. + * + * \param value Value to copy to the page buffer. + */ +void nvm_eeprom_fill_buffer_with_value(uint8_t value) +{ + uint8_t old_cmd; + old_cmd = NVM.CMD; + + nvm_eeprom_flush_buffer(); + // Wait until NVM is ready + nvm_wait_until_ready(); + + NVM.CMD = NVM_CMD_LOAD_EEPROM_BUFFER_gc; + + /* Set address to zero, as only the lower bits matters. ADDR0 is + * maintained inside the loop below. + */ + NVM.ADDR2 = 0x00; + NVM.ADDR1 = 0x00; + + // Load multible bytes into page buffer + uint8_t i; + for (i = 0; i < EEPROM_PAGE_SIZE; ++i) { + NVM.ADDR0 = i; + NVM.DATA0 = value; + } + NVM.CMD = old_cmd; +} + +/** + * \brief Erase bytes from EEPROM page. + * + * This function erases bytes from one EEPROM page, so that every location + * written to in the page buffer reads 0xFF. + * + * \param page_addr EEPROM Page address, between 0 and EEPROM_SIZE/EEPROM_PAGE_SIZE + */ +void nvm_eeprom_erase_bytes_in_page(uint8_t page_addr) +{ + // Wait until NVM is ready + nvm_wait_until_ready(); + + // Calculate page address + uint16_t address = (uint16_t)(page_addr * EEPROM_PAGE_SIZE); + + Assert(address <= EEPROM_SIZE); + + // Set address + NVM.ADDR2 = 0x00; + NVM.ADDR1 = (address >> 8) & 0xFF; + NVM.ADDR0 = address & 0xFF; + + // Issue EEPROM Erase command + nvm_issue_command(NVM_CMD_ERASE_EEPROM_PAGE_gc); +} + +/** + * \brief Erase EEPROM page. + * + * This function erases one EEPROM page, so that every location reads 0xFF. + * + * \param page_addr EEPROM Page address, between 0 and EEPROM_SIZE/EEPROM_PAGE_SIZE + */ +void nvm_eeprom_erase_page(uint8_t page_addr) +{ + // Mark all addresses to be deleted + nvm_eeprom_fill_buffer_with_value(0xff); + // Erase bytes + nvm_eeprom_erase_bytes_in_page(page_addr); +} + + +/** + * \brief Erase bytes from all EEPROM pages. + * + * This function erases bytes from all EEPROM pages, so that every location + * written to in the page buffer reads 0xFF. + */ +void nvm_eeprom_erase_bytes_in_all_pages(void) +{ + // Wait until NVM is ready + nvm_wait_until_ready(); + + // Issue EEPROM Erase All command + nvm_issue_command(NVM_CMD_ERASE_EEPROM_gc); +} + +/** + * \brief Erase entire EEPROM memory. + * + * This function erases the entire EEPROM memory block to 0xFF. + */ +void nvm_eeprom_erase_all(void) +{ + // Mark all addresses to be deleted + nvm_eeprom_fill_buffer_with_value(0xff); + // Erase all pages + nvm_eeprom_erase_bytes_in_all_pages(); +} + +//! @} + + +//! @} + + +/** + * \weakgroup nvm_flash_group + * @{ + */ + +/** + * \brief Issue flash range CRC command + * + * This function sets the FLASH range CRC command in the NVM.CMD register. + * It then loads the start and end byte address of the part of FLASH to + * generate a CRC-32 for into the ADDR and DATA registers and finally performs + * the execute command. + * + * \note Should only be called from the CRC module. The function saves and + * restores the NVM.CMD register, but if this + * function is called from an interrupt, interrupts must be disabled + * before this function is called. + * + * \param start_addr end byte address + * \param end_addr start byte address + */ +void nvm_issue_flash_range_crc(flash_addr_t start_addr, flash_addr_t end_addr) +{ + uint8_t old_cmd; + // Save current nvm command + old_cmd = NVM.CMD; + + // Load the NVM CMD register with the Flash Range CRC command + NVM.CMD = NVM_CMD_FLASH_RANGE_CRC_gc; + + // Load the start byte address in the NVM Address Register + NVM.ADDR0 = start_addr & 0xFF; + NVM.ADDR1 = (start_addr >> 8) & 0xFF; +#if (FLASH_SIZE >= 0x10000UL) + NVM.ADDR2 = (start_addr >> 16) & 0xFF; +#endif + + // Load the end byte address in NVM Data Register + NVM.DATA0 = end_addr & 0xFF; + NVM.DATA1 = (end_addr >> 8) & 0xFF; +#if (FLASH_SIZE >= 0x10000UL) + NVM.DATA2 = (end_addr >> 16) & 0xFF; +#endif + + // Execute command + ccp_write_io((uint8_t *)&NVM.CTRLA, NVM_CMDEX_bm); + + // Restore command register + NVM.CMD = old_cmd; +} + +/** + * \brief Read buffer within the application section + * + * \param address the address to where to read + * \param buf pointer to the data + * \param len the number of bytes to read + */ +void nvm_flash_read_buffer(flash_addr_t address, void *buf, uint16_t len) +{ +#if (FLASH_SIZE>0x10000) + uint32_t opt_address = address; +#else + uint16_t opt_address = (uint16_t)address; +#endif + nvm_wait_until_ready(); + while ( len ) { + *(uint8_t*)buf = nvm_flash_read_byte(opt_address); + buf=(uint8_t*)buf+1; + opt_address++; + len--; + } +} + +/** + * \brief Read buffer within the user section + * + * \param address the address to where to read + * \param buf pointer to the data + * \param len the number of bytes to read + */ +void nvm_user_sig_read_buffer(flash_addr_t address, void *buf, uint16_t len) +{ + uint16_t opt_address = (uint16_t)address&(FLASH_PAGE_SIZE-1); + while ( len ) { + *(uint8_t*)buf = nvm_read_user_signature_row(opt_address); + buf=(uint8_t*)buf+1; + opt_address++; + len--; + } +} + +/** + * \brief Write specific parts of user flash section + * + * \param address the address to where to write + * \param buf pointer to the data + * \param len the number of bytes to write + * \param b_blank_check if True then the page flash is checked before write + * to run or not the erase page command. + * + * Set b_blank_check to false if all application flash is erased before. + */ +void nvm_user_sig_write_buffer(flash_addr_t address, const void *buf, + uint16_t len, bool b_blank_check) +{ + uint16_t w_value; + uint16_t page_pos; + uint16_t opt_address = (uint16_t)address; + bool b_flag_erase = false; + + while ( len ) { + for (page_pos=0; page_pos0x10000) + uint32_t page_address; + uint32_t opt_address = address; +#else + uint16_t page_address; + uint16_t opt_address = (uint16_t)address; +#endif + + // Compute the start of the page to be modified + page_address = opt_address-(opt_address%FLASH_PAGE_SIZE); + + // For each page + while ( len ) { + b_flag_erase = false; + + nvm_wait_until_ready(); + for (page_pos=0; page_pos +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * \defgroup nvm_group NVM driver + * + * See \ref xmega_nvm_quickstart + * + * \brief Low-level driver implementation for the AVR XMEGA Non Volatile + * Memory Controller (NVM). + * + * The XMEGA NVM controller interfaces the internal non-volatile memories + * in the XMEGA devices. Program memory, EEPROM and signature row is can be + * interfaced by the module. See the documentation of each sub-module for + * more information. + * + * \note If using GCC and the flash sub-module, remember to configure + * the boot section in the make file. More information in the sub-module + * documentation. + * + * \section xmega_nvm_quickstart_section Quick Start Guide + * See \ref xmega_nvm_quickstart + */ + +/** + * \defgroup nvm_generic_group NVM driver generic module handling + * \ingroup nvm_group + * \brief Support functions for the NVM driver. + * + * These functions are helper functions for the functions of the + * \ref nvm_group "NVM driver". + * + * @{ + */ + +/** + * \brief Wait for any NVM access to finish. + * + * This function is blocking and waits for any NVM access to finish. + * Use this function before any NVM accesses, if you are not certain that + * any previous operations are finished yet. + */ +static inline void nvm_wait_until_ready( void ) +{ + do { + // Block execution while waiting for the NVM to be ready + } while ((NVM.STATUS & NVM_NVMBUSY_bm) == NVM_NVMBUSY_bm); +} + +/** + * \brief Non-Volatile Memory Execute Command + * + * This function sets the CCP register before setting the CMDEX bit in the + * NVM.CTRLA register. + * + * \note The correct NVM command must be set in the NVM.CMD register before + * calling this function. + */ +static inline void nvm_exec(void) +{ + ccp_write_io((uint8_t *)&NVM.CTRLA, NVM_CMDEX_bm); +} + +/** + * \brief Non-Volatile Memory Execute Specific Command + * + * This function sets a command in the NVM.CMD register, then performs an + * execute command by writing the CMDEX bit to the NVM.CTRLA register. + * + * \note The function saves and restores the NVM.CMD register, but if this + * function is called from an interrupt, interrupts must be disabled + * before this function is called. + * + * \param nvm_command NVM Command to execute. + */ +static inline void nvm_issue_command(NVM_CMD_t nvm_command) +{ + uint8_t old_cmd; + + old_cmd = NVM.CMD; + NVM.CMD = nvm_command; + ccp_write_io((uint8_t *)&NVM.CTRLA, NVM_CMDEX_bm); + NVM.CMD = old_cmd; +} + +/** + * \brief Read one byte using the LDI instruction + * \internal + * + * This function sets the specified NVM_CMD, reads one byte using at the + * specified byte address with the LPM instruction. NVM_CMD is restored after + * use. + * + * \note Interrupts should be disabled before running this function + * if program memory/NVM controller is accessed from ISRs. + * + * \param nvm_cmd NVM commad to load before running LPM + * \param address Byte offset into the signature row + */ +uint8_t nvm_read_byte(uint8_t nvm_cmd, uint16_t address); + + +/** + * \brief Perform SPM write + * \internal + * + * This function sets the specified NVM_CMD, sets CCP and then runs the SPM + * instruction to write to flash. + * + * \note Interrupts should be disabled before running this function + * if program memory/NVM controller is accessed from ISRs. + * + * \param addr Address to perform the SPM on. + * \param nvm_cmd NVM command to use in the NVM_CMD register + */ +void nvm_common_spm(uint32_t addr, uint8_t nvm_cmd); + +//! @} + +/** + * \defgroup nvm_signature_group NVM driver signature handling + * \ingroup nvm_group + * \brief Handling of signature rows + * + * Functions for handling signature rows. The following is supported: + * - Reading values from production and user signature row + * - Reading device id + * - Reading device revision + * - Reading device serial + * + * \note Some of these functions are modifying the NVM.CMD register. + * If the application are using program space access in interrupts + * (__flash pointers in IAR EW or pgm_read_byte in GCC) interrupts + * needs to be disabled when running EEPROM access functions. If not, + * the program space reads will be corrupted. See documentation for + * each individual function. + * \note Do not use the functions of this module in an interrupt service + * routine (ISR), since the functions can take several milliseconds to + * complete and hence block the interrupt for several milliseconds. + * In addition the functions of this module are modifying the page buffer + * which will corrupt any ongoing EEPROM handing used outside an ISR. + * @{ + */ + +/** + * \brief Structure containing the device ID + * + * This structure can be used to store the device ID of a device. + */ +struct nvm_device_id { + union { + struct { + uint8_t devid0; + uint8_t devid1; + uint8_t devid2; + }; + uint8_t byte[3]; + }; +}; + +/** + * \brief Structure containing the device serial + * + * This structure can be used to store the serial number of a device. + */ +struct nvm_device_serial { + union { + struct { + uint8_t lotnum0; + uint8_t lotnum1; + uint8_t lotnum2; + uint8_t lotnum3; + uint8_t lotnum4; + uint8_t lotnum5; + uint8_t wafnum; + uint8_t coordx0; + uint8_t coordx1; + uint8_t coordy0; + uint8_t coordy1; + }; + uint8_t byte[11]; + }; +}; + +/** + * \brief Get offset of calibration bytes in the production signature row + * + * \param regname Name of register within the production signature row + * \retval Offset of register into the production signature row + */ +#if defined(__GNUC__) +# define nvm_get_production_signature_row_offset(regname) \ + offsetof(NVM_PROD_SIGNATURES_t, regname) +#elif defined(__ICCAVR__) +# define nvm_get_production_signature_row_offset(regname) (regname##_offset) +#else +# error Unknown compiler +#endif + + +/** + * \brief Read one byte from the production signature row + * + * This function reads one byte from the production signature row of the device + * at the given address. + * + * \note This function is modifying the NVM.CMD register. + * If the application are using program space access in interrupts + * (__flash pointers in IAR EW or pgm_read_byte in GCC) interrupts + * needs to be disabled when running EEPROM access functions. If not + * the program space reads will be corrupted. + * + * \param address Byte offset into the signature row + */ +static inline uint8_t nvm_read_production_signature_row(uint8_t address) +{ + return nvm_read_byte(NVM_CMD_READ_CALIB_ROW_gc, address); +} + +/** + * \brief Read one byte from the user signature row + * + * This function reads one byte from the user signature row of the device + * at the given address. + * + * \note This function is modifying the NVM.CMD register. + * If the application are using program space access in interrupts + * (__flash pointers in IAR EW or pgm_read_byte in GCC) interrupts + * needs to be disabled when running EEPROM access functions. If not + * the program space reads will be corrupted. + * + * \param address Byte offset into the signature row + */ +static inline uint8_t nvm_read_user_signature_row(uint16_t address) +{ + return nvm_read_byte(NVM_CMD_READ_USER_SIG_ROW_gc, address); +} + +/** + * \brief Read the device id + * + * This function returns the device ID stored in the device. + * + * \retval storage Pointer to the structure where to store the device id + */ +static inline void nvm_read_device_id(struct nvm_device_id *storage) +{ + storage->devid0 = MCU.DEVID0; + storage->devid1 = MCU.DEVID1; + storage->devid2 = MCU.DEVID2; +} + +/** + * \brief Read the device revision + * + * This function returns the device revision stored in the device. + * + * \retval unsigned 8 bit value with the current device revision. + */ +static inline uint8_t nvm_read_device_rev(void) +{ + return MCU.REVID; +} + +void nvm_read_device_serial(struct nvm_device_serial *storage); + +//! @} + + +/** + * \defgroup nvm_eeprom_group NVM driver EEPROM handling + * \ingroup nvm_group + * \brief Functions for handling internal EEPROM memory. + * + * The internal EEPROM can be used to store data that will persist after + * power is removed. This can typically be used to store calibration data, + * application state, encryption keys or other data that need to be preserved + * when power is removed. + * + * The functions in this module uses IO register access to manipulate the + * EEPROM. + * + * \note The functions in this module are modifying the NVM.CMD register. + * If the application are using program space access in interrupts + * (__flash pointers in IAR EW or pgm_read_byte in GCC) interrupts + * needs to be disabled when running EEPROM access functions. If not + * the program space reads will be corrupted. + * @{ + */ + +#ifndef EEPROM_PAGE_SIZE +# if XMEGA_A || XMEGA_AU || XMEGA_B || XMEGA_C || XMEGA_D +# define EEPROM_PAGE_SIZE 32 +# else +# error Unknown EEPROM page size +# endif +#endif + +#ifndef CONFIG_NVM_IGNORE_XMEGA_A3_D3_REVB_ERRATA +# if XMEGA_A3 || XMEGA_D3 +# error This NVM driver does not support rev B of XMEGA A3/D3 devices. \ + Set CONFIG_NVM_IGNORE_XMEGA_A3_D3_REVB_ERRATA to disable this message +# endif +#endif + +/** + * Data type for holding eeprom memory addresses. + */ +typedef uint16_t eeprom_addr_t; + + +/*! \brief Enable EEPROM mapping into data space. + * + * This macro enables mapping of EEPROM into data space. + * EEPROM starts at EEPROM_START in data memory. Read access + * can be done similar to ordinary SRAM access. + * + * \note This disables IO-mapped access to EEPROM, although page erase and + * write operations still needs to be done through IO register. + */ +static inline void eeprom_enable_mapping(void) +{ + NVM_CTRLB = NVM_CTRLB | NVM_EEMAPEN_bm; +} + + +/*! \brief Disable EEPROM mapping into data space. + * + * This macro disables mapping of EEPROM into data space. + * IO mapped access is now enabled. + */ +static inline void eeprom_disable_mapping(void) +{ + NVM_CTRLB = NVM_CTRLB & ~NVM_EEMAPEN_bm; +} + + +uint8_t nvm_eeprom_read_byte(eeprom_addr_t addr); +void nvm_eeprom_write_byte(eeprom_addr_t address, uint8_t value); +void nvm_eeprom_read_buffer(eeprom_addr_t address, void *buf, uint16_t len); +void nvm_eeprom_erase_and_write_buffer(eeprom_addr_t address, const void *buf, uint16_t len); + +void nvm_eeprom_flush_buffer(void); +void nvm_eeprom_load_byte_to_buffer(uint8_t byte_addr, uint8_t value); +void nvm_eeprom_load_page_to_buffer(const uint8_t *values); +void nvm_eeprom_atomic_write_page(uint8_t page_addr); +void nvm_eeprom_split_write_page(uint8_t page_addr); +void nvm_eeprom_fill_buffer_with_value(uint8_t value); +void nvm_eeprom_erase_bytes_in_page(uint8_t page_addr); +void nvm_eeprom_erase_page(uint8_t page_addr); +void nvm_eeprom_erase_bytes_in_all_pages(void); +void nvm_eeprom_erase_all(void); + +//! @} + +/** + * \defgroup nvm_flash_group NVM driver flash handling + * \ingroup nvm_group + * \brief Functions for handling internal flash memory. + * + * The internal flash memory on the XMEGA devices consists of the application + * section, the application table section and the bootloader section. + * All these sections can store program code for the MCU, but if there is + * available space, they can be used for storing other persistent data. + * + * Writing the flash memory can only be done one page at a time. It consists + * of loading the data to the internal page buffer and then running one of + * the write commands. If the page has not been erased before writing, the + * data will not be written correctly. + * + * In order to be able to write to flash memory the programming commands need + * to be run from the boot section. + * - When using IAR this is handled automatically by the linker script. + * - When using GCC this needs to be specified manually in the make files. For + * example the ATxmega128A1 has the boot section at the word address 0x10000 + * the corresponding byte address of 0x20000 needs to be added to the + * config.mk makefile: + * LDFLAGS += -Wl,--section-start=.BOOT=0x20000 + * See the device datasheet for the correct address for other devices. + * + * \note If using GCC and the flash sub-module, remember to configure + * the boot section in the make file. + * + * \note The functions in this module are modifying the NVM.CMD register. + * If the application are using program space access in interrupts + * (__flash pointers in IAR EW or pgm_read_byte in GCC) interrupts + * needs to be disabled when running EEPROM access functions. If not + * the program space reads will be corrupted. + * @{ + */ + +/** + * \brief Size of a flash page in bytes + * + * The page size in bytes taken from the toolchain header files. + * + * \note Page size is currently missing from the IAR header files, so it needs + * to be defined in the driver until it is fixed. + */ +#ifdef __DOXYGEN__ +# define FLASH_SIZE +# define FLASH_PAGE_SIZE +#else + +// 16K devices +# if part_is_defined(ATxmega16A4) | \ + part_is_defined(ATxmega16A4U) | \ + part_is_defined(ATxmega16D4) | \ + part_is_defined(ATxmega16C4) +# define FLASH_SIZE (16*1024L) +# define FLASH_PAGE_SIZE (256) + +// 32K devices +# elif part_is_defined(ATxmega32A4) | \ + part_is_defined(ATxmega32A4U) | \ + part_is_defined(ATxmega32D4) | \ + part_is_defined(ATxmega32C4) +# define FLASH_SIZE (32*1024L) +# define FLASH_PAGE_SIZE (256) + +// 64K devices +# elif part_is_defined(ATxmega64A1) | \ + part_is_defined(ATxmega64A1U) | \ + part_is_defined(ATxmega64A3) | \ + part_is_defined(ATxmega64A3U) | \ + part_is_defined(ATxmega64A4U) | \ + part_is_defined(ATxmega64B1) | \ + part_is_defined(ATxmega64B3) | \ + part_is_defined(ATxmega64D3) | \ + part_is_defined(ATxmega64D4) +# define FLASH_SIZE (64*1024L) +# define FLASH_PAGE_SIZE (256) + +// 128K devices +# elif part_is_defined(ATxmega128A1) | \ + part_is_defined(ATxmega128A1U) | \ + part_is_defined(ATxmega128A3) | \ + part_is_defined(ATxmega128A3U) | \ + part_is_defined(ATxmega128A4U) | \ + part_is_defined(ATxmega128B1) | \ + part_is_defined(ATxmega128B3) | \ + part_is_defined(ATxmega128D3) | \ + part_is_defined(ATxmega128D4) +# define FLASH_SIZE (128*1024L) +# define FLASH_PAGE_SIZE (512) + +// 192K devices +# elif part_is_defined(ATxmega192A3U) | \ + part_is_defined(ATxmega192D3) +# define FLASH_SIZE (192*1024L) +# define FLASH_PAGE_SIZE (512) + +// 256K devices +# elif part_is_defined(ATxmega256A3) | \ + part_is_defined(ATxmega256A3U) | \ + part_is_defined(ATxmega256A3B) | \ + part_is_defined(ATxmega256A3BU) | \ + part_is_defined(ATxmega256C3) | \ + part_is_defined(ATxmega256D3) +# define FLASH_SIZE (256*1024L) +# define FLASH_PAGE_SIZE (512) + +// 384K devices +# elif part_is_defined(ATxmega384C3) +# define FLASH_SIZE (384*1024L) +# define FLASH_PAGE_SIZE (512) +# elif part_is_defined(ATxmega384D3) +# define FLASH_SIZE (384*1024L) +# define FLASH_PAGE_SIZE (512) +# else +# error Flash page size needs to be defined. +# endif +#endif + +/** + * Data type for holding flash memory addresses. + * + */ +#if (FLASH_SIZE >= 0x10000UL) // Note: Xmega with 64KB of flash have 4KB boot flash +typedef uint32_t flash_addr_t; +#else +typedef uint16_t flash_addr_t; +#endif + +/** + * Flash pointer type to use for accessing flash memory with IAR + */ +#if (FLASH_SIZE >= 0x10000UL) // Note: Xmega with 64KB of flash have 4KB boot flash +# define IAR_FLASH_PTR __farflash +#else +# define IAR_FLASH_PTR __flash +#endif + +/** + * \brief Load byte from flash memory + * + * Load one word of flash using byte addressing. IAR has __flash pointers + * and GCC have pgm_read_byte_xx functions which load data from flash memory. + * This function used for compatibility between the compilers. + * + * \param addr Byte address to load + * \return Byte from program memory + */ +static inline uint8_t nvm_flash_read_byte(flash_addr_t addr) +{ +#if defined(__GNUC__) + return pgm_read_byte_far(addr); +#elif defined(__ICCAVR__) + uint8_t IAR_FLASH_PTR *flashptr = (uint8_t IAR_FLASH_PTR *)addr; + return *flashptr; +#else +# error Unknown compiler +#endif +} + +/** + * \brief Load word from flash memory + * + * Load one word of flash using byte addressing. IAR has __flash pointers + * and GCC have pgm_read_byte_xx functions which load data from flash memory. + * This function used for compatibility between the compilers. + * + * \param addr Byte address to load (last bit is ignored) + * \return Word from program memory + */ +static inline uint16_t nvm_flash_read_word(flash_addr_t addr) +{ +#if defined(__GNUC__) + return pgm_read_word_far(addr); +#elif defined(__ICCAVR__) + uint16_t IAR_FLASH_PTR *flashptr = (uint16_t IAR_FLASH_PTR *)addr; + return *flashptr; +#endif +} + + +/** + * \brief Flush flash page buffer + * + * Clear the NVM controller page buffer for flash. This needs to be called + * before using \ref nvm_flash_load_word_to_buffer if it has not already been + * cleared. + * + */ +static inline void nvm_flash_flush_buffer(void) +{ + nvm_wait_until_ready(); + nvm_common_spm(0, NVM_CMD_ERASE_FLASH_BUFFER_gc); +} + + +/** + * \brief Load word into flash page buffer + * + * Clear the NVM controller page buffer for flash. This needs to be called + * before using \ref nvm_flash_load_word_to_buffer if it has not already been + * cleared. + * + * \param word_addr Address to store data. The upper bits beyond the page size + * is ignored. \ref FLASH_PAGE_SIZE + * \param data Data word to load into the page buffer + */ +void nvm_flash_load_word_to_buffer(uint32_t word_addr, uint16_t data); + + +/** + * \brief Erase entire application section + * + * Erase all of the application section. + */ +static inline void nvm_flash_erase_app(void) +{ + nvm_wait_until_ready(); + nvm_common_spm(0, NVM_CMD_ERASE_APP_gc); +} + +/** + * \brief Erase a page within the application section + * + * Erase one page within the application section + * + * \param page_addr Byte address to the page to delete + */ +static inline void nvm_flash_erase_app_page(flash_addr_t page_addr) +{ + nvm_wait_until_ready(); + nvm_common_spm(page_addr, NVM_CMD_ERASE_APP_PAGE_gc); +} + +/** + * \brief Write a page within the application section + * + * Write a page within the application section with the data stored in the + * page buffer. The page needs to be erased before the write to avoid + * corruption of the data written. + * + * \param page_addr Byte address to the page to delete + */ +static inline void nvm_flash_split_write_app_page(flash_addr_t page_addr) +{ + nvm_wait_until_ready(); + nvm_common_spm(page_addr, NVM_CMD_WRITE_APP_PAGE_gc); +} + +/** + * \brief Erase and write a page within the application section + * + * Erase and the write a page within the application section with the data + * stored in the page buffer. Erase and write is done in an atomic operation. + * + * \param page_addr Byte address to the page to delete + */ +static inline void nvm_flash_atomic_write_app_page(flash_addr_t page_addr) +{ + nvm_wait_until_ready(); + nvm_common_spm(page_addr, NVM_CMD_ERASE_WRITE_APP_PAGE_gc); +} + +void nvm_issue_flash_range_crc(flash_addr_t start_addr, flash_addr_t end_addr); + +void nvm_flash_read_buffer(flash_addr_t address, void *buf, uint16_t len); + +void nvm_flash_erase_and_write_buffer(flash_addr_t address, const void *buf, + uint16_t len, bool b_blank_check); + +/** + * \brief Erase a page within the boot section + * + * Erase one page within the boot section + * + * \param page_addr Byte address to the page to delete + */ +static inline void nvm_flash_erase_boot_page(flash_addr_t page_addr) +{ + nvm_wait_until_ready(); + nvm_common_spm(page_addr, NVM_CMD_ERASE_BOOT_PAGE_gc); +} + +/** + * \brief Write a page within the boot section + * + * Write a page within the boot section with the data stored in the + * page buffer. The page needs to be erased before the write to avoid + * corruption of the data written. + * + * \param page_addr Byte address to the page to delete + */ +static inline void nvm_flash_split_write_boot_page(flash_addr_t page_addr) +{ + nvm_wait_until_ready(); + nvm_common_spm(page_addr, NVM_CMD_WRITE_BOOT_PAGE_gc); +} + +/** + * \brief Erase and write a page within the boot section + * + * Erase and the write a page within the boot section with the data + * stored in the page buffer. Erase and write is done in an atomic operation. + * + * \param page_addr Byte address to the page to delete + */ +static inline void nvm_flash_atomic_write_boot_page(flash_addr_t page_addr) +{ + nvm_wait_until_ready(); + nvm_common_spm(page_addr, NVM_CMD_ERASE_WRITE_BOOT_PAGE_gc); +} + +void nvm_user_sig_read_buffer(flash_addr_t address, void *buf, uint16_t len); +void nvm_user_sig_write_buffer(flash_addr_t address, const void *buf, + uint16_t len, bool b_blank_check); + +/** + * \brief Erase the user calibration section page + * + * Erase the user calibration section page. There is only one page, so no + * paramaters are needed. + */ +static inline void nvm_flash_erase_user_section(void) +{ + nvm_wait_until_ready(); + nvm_common_spm(0, NVM_CMD_ERASE_USER_SIG_ROW_gc); +} + +/** + * \brief Write the user calibration section page + * + * Write a the user calibratino section page with the data stored in the + * page buffer. The page needs to be erased before the write to avoid + * corruption of the data written. There is only one page, so no + * paramaters are needed. + */ +static inline void nvm_flash_write_user_page(void) +{ + nvm_wait_until_ready(); + nvm_common_spm(0, NVM_CMD_WRITE_USER_SIG_ROW_gc); +} + +//! @} + +/** + * \defgroup nvm_fuse_lock_group NVM driver fuse and lock bits handling + * \ingroup nvm_group + * \brief Functions for reading fuses and writing lock bits. + * + * The Fuses are used to set important system functions and can only be written + * from an external programming interface. The application software can read + * the fuses. The fuses are used to configure reset sources such as Brown-out + * Detector and Watchdog, Start-up configuration, JTAG enable and JTAG user ID. + * + * The Lock bits are used to set protection level on the different flash + * sections. They are used to block read and/or write on the different flash + * sections. Lock bits can be written from en external programmer and from the + * application software to set a more strict protection level, but not to set a + * less strict protection level. Chip erase is the only way to erase the lock + * bits. The lock bits are erased after the rest of the flash memory is erased. + * An unprogrammed fuse or lock bit will have the value one, while a programmed + * fuse or lock bit will have the value zero. + * Both fuses and lock bits are reprogrammable like the Flash Program memory. + * + * \note The functions in this module are modifying the NVM.CMD register. + * If the application are using program space access in interrupts + * (__flash pointers in IAR EW or pgm_read_byte in GCC) interrupts + * needs to be disabled when running EEPROM access functions. If not + * the program space reads will be corrupted. + * @{ + */ + +// The different fuse bytes +enum fuse_byte_t { + FUSEBYTE0 = 0, + FUSEBYTE1 = 1, + FUSEBYTE2 = 2, + FUSEBYTE3 = 3, // not used on current devices + FUSEBYTE4 = 4, + FUSEBYTE5 = 5, +}; + +uint8_t nvm_fuses_read(enum fuse_byte_t fuse); + +/** + * \brief Program the lock bits. + * + * Program the lock bits to the given values. Lock bits can only be programmed + * to a more secure setting than previously programmed. To clear lock bits, a + * flash erase has to be issued. + * + * \param blbb_lock Boot loader section lock bits to program + * \param blba_lock Application section lock bits to program + * \param blbat_lock Application table section lock bits to program + * \param lb_lock Flash/eeprom lock bits to program + */ +static inline void nvm_lock_bits_write(enum NVM_BLBB_enum blbb_lock, + enum NVM_BLBA_enum blba_lock, enum NVM_BLBAT_enum blbat_lock, + enum NVM_LB_enum lb_lock) +{ + nvm_wait_until_ready(); + NVM.DATA0 = (uint8_t)blbb_lock | (uint8_t)blba_lock | (uint8_t)blbat_lock | + (uint8_t)lb_lock; + nvm_issue_command(NVM_CMD_WRITE_LOCK_BITS_gc); +} + +/** + * \brief Program the BLBB lock bits. + * + * Program the lock bits for the boot loader section (BLBB). Other lock bits + * (BLBA, BLBAT and LB) are not altered (ie. programmed to NOLOCK). + * + * \param blbb_lock Boot loader section lock bits to program + */ +static inline void nvm_blbb_lock_bits_write(enum NVM_BLBB_enum blbb_lock) +{ + nvm_lock_bits_write(blbb_lock, NVM_BLBA_NOLOCK_gc, NVM_BLBAT_NOLOCK_gc, + NVM_LB_NOLOCK_gc); +} + +/** + * \brief Program the BLBA lock bits. + * + * Program the lock bits for the application section (BLBA). Other lock bits + * (BLBB, BLBAT and LB) are not altered (ie. programmed to NOLOCK). + * + * \param blba_lock Application section lock bits to program + */ +static inline void nvm_blba_lock_bits_write(enum NVM_BLBA_enum blba_lock) +{ + nvm_lock_bits_write(NVM_BLBB_NOLOCK_gc, blba_lock, NVM_BLBAT_NOLOCK_gc, + NVM_LB_NOLOCK_gc); +} + +/** + * \brief Program the BLBAT lock bits. + * + * Program the lock bits for the application table section (BLBAT). Other lock + * bits (BLBB, BLBA and LB) are not altered (ie. programmed to NOLOCK). + * + * \param blbat_lock Application table section lock bits to program + */ +static inline void nvm_blbat_lock_bits_write(enum NVM_BLBAT_enum blbat_lock) +{ + nvm_lock_bits_write(NVM_BLBB_NOLOCK_gc, NVM_BLBA_NOLOCK_gc, blbat_lock, + NVM_LB_NOLOCK_gc); +} + +/** + * \brief Program the LB lock bits. + * + * Program the lock bits for the flash and eeprom (LB). Other lock bits + * (BLBB, BLBA and BLBAT) are not altered (ie. programmed to NOLOCK). + * + * \param lb_lock Flash/eeprom lock bits to program + */ +static inline void nvm_lb_lock_bits_write(enum NVM_LB_enum lb_lock) +{ + nvm_lock_bits_write(NVM_BLBB_NOLOCK_gc, NVM_BLBA_NOLOCK_gc, + NVM_BLBAT_NOLOCK_gc, lb_lock); +} + +//! @} + +/** + * \page xmega_nvm_quickstart Quick Start Guide for the XMEGA NVM Driver + * + * This is the quick start guide for the \ref nvm_group "NVM Driver", with + * step-by-step instructions on how to configure and use the driver for + * specific use cases. + * + * The section described below can be compiled into e.g. the main application + * loop or any other function that will need to interface non-volatile memory. + * + * \section xmega_nvm_quickstart_basic Basic usage of the NVM driver + * This section will present three use cases of the NVM driver. The first will + * write a page to EEPROM and verify that it has been written, the second will + * access the BOD-level fuse to verify that the level is correctly set, and the + * third will read a chunk from the user signature row. + * + * \section xmega_nvm_quickstart_eeprom_case Use case 1: EEPROM + * + * The NVM driver has functions for interfacing many types of non-volatile + * memory, including flash, EEPROM, fuses and lock bits. The example code + * below will write a page to the internal EEPROM, and read it back to verify, + * using memory mapped I/O. + * + * \section xmega_nvm_quickstart_eeprom_case_setup_steps Setup steps + * There are no setup steps required for this use case. + * + * \subsection nvm_quickstart_eeprom_case_example_code Example code + * + * \code + * #define EXAMPLE_PAGE 2 + * #define EXAMPLE_ADDR EXAMPLE_PAGE * EEPROM_PAGE_SIZE + * + * uint8_t write_page[EEPROM_PAGE_SIZE]; + * uint8_t read_page[EEPROM_PAGE_SIZE]; + * + * fill_page_with_known_data(write_page); + * fill_page_with_zeroes(read_page); + * + * nvm_eeprom_load_page_to_buffer(write_page); + * nvm_eeprom_atomic_write_page(EXAMPLE_PAGE); + * + * nvm_eeprom_read_buffer(EXAMPLE_ADDR, + * read_page, EEPROM_PAGE_SIZE); + * + * check_if_pages_are_equal(write_page, read_page); + * \endcode + * + * \subsection nvm_quickstart_eeprom_case_workflow Workflow + * + * -# We define where we would like to store our data, and we arbitrarily + * choose page 2 of EEPROM: + * - \code + * #define EXAMPLE_PAGE 2 + * #define EXAMPLE_ADDR EXAMPLE_PAGE * EEPROM_PAGE_SIZE + * \endcode + * -# Define two tables, one which contains the data which we will write, + * and one which we will read the data into: + * - \code + * uint8_t write_page[EEPROM_PAGE_SIZE]; + * uint8_t read_page[EEPROM_PAGE_SIZE]; + * \endcode + * -# Fill the tables with our data, and zero out the read table: + * - \code + * fill_page_with_known_data(write_page); + * fill_page_with_zeroes(read_page); + * \endcode + * - \note These functions are undeclared, you should replace them with + * your own appropriate functions. + * -# We load our page into a temporary EEPROM page buffer: + * - \code + * nvm_eeprom_load_page_to_buffer(write_page); + * \endcode + * - \attention The function used above will not work if memory mapping + * is enabled. + * -# Do an atomic write of the page from buffer into the specified page: + * - \code + * nvm_eeprom_atomic_write_page(EXAMPLE_PAGE); + * \endcode + * - \note The function \ref nvm_eeprom_atomic_write_page() erases the + * page before writing the new one. For non-atomic (split) + * writing without deleting, see \ref nvm_eeprom_split_write_page() + * -# Read the page back into our read_page[] table: + * - \code + * nvm_eeprom_read_buffer(EXAMPLE_ADDR, + * read_page, EEPROM_PAGE_SIZE); + * \endcode + * -# Verify that the page is equal to the one that was written earlier: + * - \code + * check_if_pages_are_equal(write_page, read_page); + * \endcode + * - \note This function is not declared, you should replace it with your + * own appropriate function. + * + * \section xmega_nvm_quickstart_fuse_case Use case 2: Fuses + * + * The NVM driver has functions for reading fuses. + * See \ref nvm_fuse_lock_group. + * + * We would like to check whether the Brown-out Detection level is set to + * 2.1V. This is set by programming the fuses when the chip is connected + * to a suitable programmer. The fuse is a part of FUSEBYTE5. If the BODLVL + * is correct, we turn on LED0. + * + * \section xmega_nvm_quickstart_fuse_case_setup_steps Setup steps + * There are no setup steps required for this use case. + * + * \subsection nvm_quickstart_fuse_case_example_code Example code + * \code + * uint8_t fuse_value; + * fuse_value = nvm_fuses_read(FUSEBYTE5); + * + * if ((fuse_value & NVM_FUSES_BODLVL_gm) == BODLVL_2V1_gc) { + * gpio_set_pin_low(LED0_GPIO); + * } + * \endcode + * + * \subsection nvm_quickstart_fuse_case_workflow Workflow + * + * -# Create a variable to store the fuse contents: + * - \code + * uint8_t fuse_value; + * \endcode + * -# The fuse value we are interested in, BODLVL, is stored in FUSEBYTE5. + * We call the function \ref nvm_fuses_read() to read the fuse into our + * variable: + * - \code + * fuse_value = nvm_fuses_read(FUSEBYTE5); + * \endcode + * -# This ends the reading portion, but we would like to see whether the + * BOD-level is correct, and if it is, light up an LED: + * - \code + * if ((fuse_value & NVM_FUSES_BODLVL_gm) == BODLVL_2V1_gc) { + * gpio_set_pin_low(LED0_GPIO); + * } + * \endcode + * + * \section xmega_nvm_quickstart_signature_case Use case 3: Signature row + * + * The NVM driver has functions for reading the signature row of the device. + * Here we will simply read 16 bytes from the user signature row, assuming + * we need what is stored there. + * + * \section xmega_nvm_quickstart_signature_row_setup_steps Setup steps + * There are no setup steps required for this use case. + * + * \subsection xmega_nvm_quickstart_signature_row_example_code Example code + * + * \code + * #define START_ADDR 0x10 + * #define DATA_LENGTH 16 + * + * uint8_t values[LENGTH]; + * uint8_t i; + * + * for (i = 0; i < DATA_LENGTH; i++) { + * values[i] = nvm_read_user_signature_row(START_ADDR + i); + * } + * \endcode + * + * \subsection nvm_quickstart_signature_case_workflow Workflow + * + * -# Define starting address and length of data segment, and create + * variables needed to store and process the data: + * - \code + * #define START_ADDR 0x10 + * #define DATA_LENGTH 16 + * + * uint8_t values[LENGTH]; + * uint8_t i; + * \endcode + * -# Iterate through the user signature row, and store our desired data: + * - \code + * for (i = 0; i < DATA_LENGTH; i++) { + * values[i] = nvm_read_user_signature_row(START_ADDR + i); + * } + * \endcode + * + */ + +#ifdef __cplusplus +} +#endif + +#endif /* NVM_H */ diff --git a/DSTAT1/src/asf/xmega/drivers/nvm/nvm_asm.s b/DSTAT1/src/asf/xmega/drivers/nvm/nvm_asm.s new file mode 100644 index 0000000000000000000000000000000000000000..328b55b00dfd37b260ef5d40f57de5e0ac9bd854 --- /dev/null +++ b/DSTAT1/src/asf/xmega/drivers/nvm/nvm_asm.s @@ -0,0 +1,195 @@ +/** + * \file + * + * \brief Non Volatile Memory controller driver + * + * Copyright (c) 2010 Atmel Corporation. All rights reserved. + * + * \asf_license_start + * + * 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. The name of Atmel may not be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * 4. This software may only be redistributed and used in connection with an + * Atmel microcontroller product. + * + * THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE + * EXPRESSLY AND SPECIFICALLY DISCLAIMED. IN NO EVENT SHALL ATMEL 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. + * + * \asf_license_stop + * + */ +#include + +#if defined(__GNUC__) +//! Value to write to CCP for access to protected IO registers. +# define CCP_SPM_gc 0x9D + +//! NVM busy flag +# define NVM_NVMBUSY_bp 7 + +//! NVM command for loading flash buffer +# define NVM_CMD_LOAD_FLASH_BUFFER_gc 0x23 +#elif defined(__IAR_SYSTEMS_ASM__) +// All values are defined for IAR +#else +# error Unknown assembler +#endif + +#ifndef __DOXYGEN__ + PUBLIC_FUNCTION(nvm_read_byte) +#if defined(__GNUC__) + lds r20, NVM_CMD ; Store NVM command register + mov ZL, r22 ; Load byte index into low byte of Z. + mov ZH, r23 ; Load high byte into Z. + sts NVM_CMD, r24 ; Load prepared command into NVM Command register. + lpm r24, Z ; Perform an LPM to read out byte + sts NVM_CMD, r20 ; Restore NVM command register +#elif defined(__IAR_SYSTEMS_ASM__) + lds r20, NVM_CMD ; Store NVM command register + mov ZL, r18 ; Load byte index into low byte of Z. + mov ZH, r19 ; Load high byte into Z. + sts NVM_CMD, r16 ; Load prepared command into NVM Command register. + lpm r16, Z ; Perform an LPM to read out byte + sts NVM_CMD, r20 ; Restore NVM command register +#endif + + ret + + END_FUNC(nvm_read_byte) + +// IAR forgets about include files after each module, so need to include again +#if defined(__IAR_SYSTEMS_ASM__) +# include +#endif + + /** + * \brief Perform SPM command + */ + PUBLIC_FUNCTION_SEGMENT(nvm_common_spm, BOOT) + +#if defined(__GNUC__) + /** + * For GCC: + * \param address uint32_t r22:r25 + * \param nvm_cmd uint8_t r20 + */ + in r25, RAMPZ ; Store RAMPZ. Highest address byte is ignored, so using that + out RAMPZ, r24 ; Load R24 into RAMPZ + movw ZL, r22 ; Load R22:R23 into Z. + lds r24, NVM_CMD ; Store NVM command register (r24 is no longer needed) + sts NVM_CMD, r20 ; Load prepared command into NVM Command register. + ldi r23, CCP_SPM_gc ; Prepare Protect SPM signature (r23 is no longer needed) + sts CCP, r23 ; Enable SPM operation (this disables interrupts for 4 cycles). + spm ; Self-program. + sts NVM_CMD, r24 ; Restore NVM command register + out RAMPZ, r25 ; Restore RAMPZ register. +#elif defined(__IAR_SYSTEMS_ASM__) + /** + * For IAR: + * \param address uint32_t r16:r19 + * \param nvm_cmd uint8_t r20 + */ + in r19, RAMPZ ; Store RAMPZ. Highest address byte is ignored, so using that + out RAMPZ, r18 ; Load R18 into RAMPZ + movw ZL, r16 ; Load R16:R17 into Z. + lds r18, NVM_CMD ; Store NVM command register (r18 is no longer needed) + sts NVM_CMD, r20 ; Load prepared command into NVM Command register. + ldi r19, CCP_SPM_gc ; Prepare Protect SPM signature (r19 is no longer needed) + sts CCP, r19 ; Enable SPM operation (this disables interrupts for 4 cycles). + spm ; Self-program. + sts NVM_CMD, r18 ; Restore NVM command register + out RAMPZ, r19 ; Restore RAMPZ register. +#endif + + ret + + END_FUNC(nvm_common_spm) + +// IAR forgets about include files after each module, so need to include again +#if defined(__IAR_SYSTEMS_ASM__) +# include +#endif + + /** + * \brief Load byte to page buffer + * + */ + PUBLIC_FUNCTION_SEGMENT(nvm_flash_load_word_to_buffer, BOOT) + +#if defined(__GNUC__) + /** + * For GCC: + * \param word_addr uint32_t r22:r25 + * \param data uint16_t r20:r21 + */ +wait_nvm: + lds r18, NVM_STATUS + sbrc r18, NVM_NVMBUSY_bp + rjmp wait_nvm + + in r25, RAMPZ ; Store RAMPZ. Highest address byte is ignored, so using that + out RAMPZ, r24 ; Load R24 into RAMPZ + movw ZL, r22 ; Load R22:R23 into Z. + + lds r24, NVM_CMD ; Store NVM command register (r24 is no longer needed) + ldi r18, NVM_CMD_LOAD_FLASH_BUFFER_gc + sts NVM_CMD, r18 ; Load prepared command into NVM Command register. + + movw r0, r20 ; Load R20:R21 into R0:R1 + spm ; Self-program. + + clr r1 ; Clear R1 for GCC _zero_reg_ to function properly. + sts NVM_CMD, r24 ; Restore NVM command register + out RAMPZ, r25 ; Restore RAMPZ register. +#elif defined(__IAR_SYSTEMS_ASM__) + /** + * For IAR: + * \param word_addr uint32_t r16:r19 + * \param data uint16_t r20:r21 + */ +wait_nvm: + lds r19, NVM_STATUS + sbrc r19, NVM_NVMBUSY_bp + rjmp wait_nvm + + in r19, RAMPZ ; Store RAMPZ. Highest byte is ignored, so using that + out RAMPZ, r18 ; Load R18 into RAMPZ + movw ZL, r16 ; Load R16:R17 into Z. + + lds r18, NVM_CMD ; Store NVM command register (r18 is no longer needed) + ldi r17, NVM_CMD_LOAD_FLASH_BUFFER_gc + sts NVM_CMD, r17 ; Load prepared command into NVM Command register. + + movw r0, r20 ; Load R20:R21 into R0:R1 + spm ; Self-program. + + sts NVM_CMD, r18 ; Restore NVM command register + out RAMPZ, r19 ; Restore RAMPZ register. +#endif + + ret + + END_FUNC(nvm_flash_load_word_to_buffer) + + END_FILE() +#endif // __DOXYGEN__ diff --git a/DSTAT1/src/asf/xmega/drivers/pmic/pmic.h b/DSTAT1/src/asf/xmega/drivers/pmic/pmic.h new file mode 100644 index 0000000000000000000000000000000000000000..fd7d242bbb395556b85d6cc96d29b59506ca6121 --- /dev/null +++ b/DSTAT1/src/asf/xmega/drivers/pmic/pmic.h @@ -0,0 +1,347 @@ +/** + * \file + * + * \brief Programmable Multilevel Interrupt Controller driver + * + * Copyright (c) 2010 Atmel Corporation. All rights reserved. + * + * \asf_license_start + * + * 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. The name of Atmel may not be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * 4. This software may only be redistributed and used in connection with an + * Atmel microcontroller product. + * + * THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE + * EXPRESSLY AND SPECIFICALLY DISCLAIMED. IN NO EVENT SHALL ATMEL 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. + * + * \asf_license_stop + * + */ +#ifndef PMIC_H +#define PMIC_H + +#include +#include + +/** + * \defgroup pmic_group Programmable Multilevel Interrupt Controller + * + * See \ref pmic_quickstart. + * + * This is a low-level driver implementation for the AVR XMEGA Programmable + * Multilevel Interrupt Controller. + * + * \note If these functions are used in interrupt service routines (ISRs), any + * non-ISR code or ISR code for lower level interrupts must ensure that the + * operations are atomic, i.e., by disabling interrupts during the function + * calls. + * @{ + */ + +/** + * \brief Interrupt level bitmasks + * + * \note These may be OR'ed, e.g., if multiple levels are to be enabled or + * disabled. + */ +enum pmic_level { + PMIC_LVL_LOW = PMIC_LOLVLEN_bm, //!< Low-level interrupts + PMIC_LVL_MEDIUM = PMIC_MEDLVLEN_bm, //!< Medium-level interrupts + PMIC_LVL_HIGH = PMIC_HILVLEN_bm, //!< High-level interrupts + /** + * \brief Non-maskable interrupts + * \note These cannot be enabled nor disabled. + */ + PMIC_LVL_NMI = PMIC_NMIEX_bp, +}; + +//! Interrupt vector locations +enum pmic_vector { + PMIC_VEC_APPLICATION, //!< Application section + PMIC_VEC_BOOT, //!< Boot section + PMIC_NR_OF_VECTORS, //!< Number of interrupt vector locations +}; + +//! Interrupt scheduling schemes +enum pmic_schedule { + PMIC_SCH_FIXED_PRIORITY, //!< Default, fixed priority scheduling + PMIC_SCH_ROUND_ROBIN, //!< Round-robin scheduling + PMIC_NR_OF_SCHEDULES, //!< Number of interrupt scheduling schemes +}; + +/** + * \brief Initialize the PMIC + * + * Enables all interrupt levels, with vectors located in the application section + * and fixed priority scheduling. + */ +static inline void pmic_init(void) +{ + PMIC.CTRL = PMIC_LVL_LOW | PMIC_LVL_MEDIUM | + PMIC_LVL_HIGH; +} + +/** + * \brief Enable interrupts with specified \a level(s). + * + * \param level Interrupt level(s) to enable. + */ +static inline void pmic_enable_level(enum pmic_level level) +{ + Assert((level & PMIC_LVL_NMI)); + + PMIC.CTRL |= level; +} + +/** + * \brief Disable interrupts with specified \a level(s). + * + * \param level Interrupt level(s) to disable. + */ +static inline void pmic_disable_level(enum pmic_level level) +{ + Assert((level & PMIC_LVL_NMI)); + + PMIC.CTRL &= ~level; +} + +/** + * \brief Check if specified interrupt \a level(s) is enabled. + * + * \param level Interrupt level(s) to check. + * + * \return True if interrupt level(s) is enabled. + */ +static inline bool pmic_level_is_enabled(enum pmic_level level) +{ + Assert((level & PMIC_LVL_NMI)); + + return PMIC.CTRL & level; +} + +/** + * \brief Get currently enabled level(s) + * + * \return Bitmask with currently enabled levels. + */ +static inline enum pmic_level pmic_get_enabled_levels(void) +{ + return (enum pmic_level)(PMIC.CTRL & (PMIC_LVL_LOW | PMIC_LVL_MEDIUM + | PMIC_LVL_HIGH)); +} + +/** + * \brief Check if an interrupt level(s) is currently executing. + * + * \param level Interrupt level(s) to check. + * + * \return True if interrupt level(s) is currently executing. + */ +static inline bool pmic_level_is_executing(enum pmic_level level) +{ + return PMIC.STATUS & level; +} + +/** + * \brief Set interrupt scheduling for low-level interrupts. + * + * \param schedule Interrupt scheduling method to set. + * + * \note The low-priority vector, INTPRI, must be set to 0 when round-robin + * scheduling is disabled to return to default interrupt priority order. + */ +static inline void pmic_set_scheduling(enum pmic_schedule schedule) +{ + Assert(schedule < PMIC_NR_OF_SCHEDULES); + + switch (schedule) { + case PMIC_SCH_FIXED_PRIORITY: + PMIC.CTRL &= ~PMIC_RREN_bm; + PMIC.INTPRI = 0; + break; + + case PMIC_SCH_ROUND_ROBIN: + PMIC.CTRL |= PMIC_RREN_bm; + break; + + default: + break; + }; +} + +/** + * \brief Set location of interrupt vectors. + * + * \param vector Location to use for interrupt vectors. + */ +static inline void pmic_set_vector_location(enum pmic_vector vector) +{ + uint8_t ctrl = PMIC.CTRL; + + Assert(vector < PMIC_NR_OF_VECTORS); + + switch (vector) { + case PMIC_VEC_APPLICATION: + ctrl &= ~PMIC_IVSEL_bm; + break; + + case PMIC_VEC_BOOT: + ctrl |= PMIC_IVSEL_bm; + break; + + default: + break; + } + + ccp_write_io((uint8_t*)&PMIC.CTRL, ctrl); +} + +//! @} + +/** + * \page pmic_quickstart Quick start guide for PMIC driver + * + * This is the quick start guide for the \ref pmic_group "PMIC driver" and + * the closely related \ref interrupt_group "global interrupt driver", with + * step-by-step instructions on how to configure and use the drivers in a + * selection of use cases. + * + * The use cases contain several code fragments. The code fragments in the + * steps for setup can be copied into a custom initialization function, while + * the steps for usage can be copied into, e.g., the main application function. + * + * \section pmic_basic_use_case Basic use case + * In this basic use case, the PMIC is configured for: + * - all interrupt levels enabled + * - round-robin scheduling + * + * This will allow for interrupts from other modules being used. + * + * \section pmic_basic_use_case_setup Setup steps + * + * \subsection pmic_basic_use_case_setup_prereq Prerequisites + * For the setup code of this use case to work, the following must + * be added to the project: + * -# Interrupts for the module requiering the PMIC module have to be + * enabled. + * -# An Interrupt Service Routine (ISR) for a given interrupt vector has to be + * defined, where the interrupt vectors available are defined by toolchain and + * listed in the subsection 'Interrupt Vector Summary' in the data sheet. + * \code + * ISR(interrupt_vector){ + * //Interrupt Service Routine + * } + * \endcode + * + * \subsection pmic_basic_use_case_setup_code Example code + * Add to the initialization code: + * \code + * pmic_init(); + * pmic_set_scheduling(PMIC_SCH_ROUND_ROBIN); + * cpu_irq_enable(); + * \endcode + * + * \subsection pmic_basic_use_case_setup_flow Workflow + * -# call the PMIC driver's own init function to enable all interrupt levels: + * - \code pmic_init(); \endcode + * -# enable round-robin instead of fixed priority interrupt scheduling: + * - \code pmic_set_scheduling(PMIC_SCH_ROUND_ROBIN); \endcode + * -# enable interrupts globally: + * - \code cpu_irq_enable(); \endcode + * - \attention Interrupts will not trigger without this step. + * + * \section pmic_use_cases Advanced use cases + * For more advanced use of the PMIC driver, see the following use cases: + * - \subpage pmic_use_case_1 : atomic operations + */ + +/** + * \page pmic_use_case_1 Use case #1 + * + * In this use case, the PMIC is configured for: + * - all interrupt levels enabled + * + * This will allow for interrupts from other modules being used. + * + * This use case shows how to make an operation which consists of multiple + * instructions uninterruptible, i.e., into an atomic operation. This is often + * necessary if there is a risk that data can be accessed by interrupt handlers + * while other code is accessing it, and at least one of them modifies it. + * + * \section pmic_use_case_1_setup Setup steps + * + * \subsection pmic_basic_use_case_setup_prereq Prerequisites + * For the setup code of this use case to work, the following must + * be added to the project: + * -# Interrupts for the module requiering the PMIC module have to be + * enabled. + * -# An Interrupt Service Routine (ISR) for a given interrupt vector has to be + * defined, where the interrupt vectors available are defined by toolchain and + * listed in the subsection 'Interrupt Vector Summary' in the data sheet. + * \code + * ISR(interrupt_vector){ + * //Interrupt Service Routine + * } + * \endcode + * + * \subsection pmic_use_case_1_setup_code Example code + * Add to application initialization: + * \code + * pmic_init(); + * cpu_irq_enable(); + * \endcode + * + * \subsection pmic_use_case_1_setup_flow Workflow + * -# call the PMIC driver's own init function to enable all interrupt levels: + * - \code pmic_init(); \endcode + * -# set global interrupt enable flag: + * - \code cpu_irq_enable(); \endcode + * + * \section pmic_use_case_1_usage Usage steps + * + * \subsection pmic_use_case_1_usage_code Example code + * \code + * Add to application: + * void atomic_operation(void) + * { + * irqflags_t flags; + * + * flags = cpu_irq_save(); + * + * // Uninterruptible block of code + * + * cpu_irq_restore(flags); + * } + * \endcode + * + * \subsection pmic_use_case_1_usage_flow Workflow + * -# allocate temporary storage for interrupt enable: + * - \code irqflags_t flags; \endcode + * -# clear global interrupt enable flag while saving its previous state: + * - \code flags = cpu_irq_save(); \endcode + * -# restore the previous state of global interrupt flag after operation: + * - \code cpu_irq_restore(flags); \endcode + */ + +#endif /* PMIC_H */ diff --git a/DSTAT1/src/asf/xmega/drivers/rtc/rtc.c b/DSTAT1/src/asf/xmega/drivers/rtc/rtc.c new file mode 100644 index 0000000000000000000000000000000000000000..1f6a597fdf65ec2c0051ede89041e43bb47874c7 --- /dev/null +++ b/DSTAT1/src/asf/xmega/drivers/rtc/rtc.c @@ -0,0 +1,226 @@ +/** + * \file + * + * \brief AVR XMEGA Real Time Counter driver + * + * Copyright (c) 2010 Atmel Corporation. All rights reserved. + * + * \asf_license_start + * + * 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. The name of Atmel may not be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * 4. This software may only be redistributed and used in connection with an + * Atmel microcontroller product. + * + * THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE + * EXPRESSLY AND SPECIFICALLY DISCLAIMED. IN NO EVENT SHALL ATMEL 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. + * + * \asf_license_stop + * + */ +#include +#include +#include +#include + +#ifdef CONFIG_RTC_OVERFLOW_INT_LEVEL +# define RTC_OVERFLOW_INT_LEVEL CONFIG_RTC_OVERFLOW_INT_LEVEL +#else +# define RTC_OVERFLOW_INT_LEVEL RTC_OVFINTLVL_LO_gc +#endif + +#ifdef CONFIG_RTC_COMPARE_INT_LEVEL +# define RTC_COMPARE_INT_LEVEL CONFIG_RTC_COMPARE_INT_LEVEL +#else +# define RTC_COMPARE_INT_LEVEL RTC_COMPINTLVL_LO_gc +#endif + +/** + * \internal + * \brief Driver private struct + */ +struct rtc_data_struct { + //! High value of counter + uint16_t counter_high; + //! High value of alarm time + uint16_t alarm_high; + //! Low value of alarm time + uint16_t alarm_low; + //! Callback function to use on alarm + rtc_callback_t callback; +}; + +/** + * \internal + * \brief Driver private data + */ +struct rtc_data_struct rtc_data; + +/** + * \internal + * \brief Check if RTC is busy synchronizing + */ +static __always_inline bool rtc_is_busy(void) +{ + return RTC.STATUS & RTC_SYNCBUSY_bm; +} + +/** + * \brief Check if pending alarm have triggered + * + * \retval true Alarm have triggered + * \retval false Alarm is pending + */ +__always_inline bool rtc_alarm_has_triggered(void) +{ + return !(RTC.INTCTRL & RTC_COMPARE_INT_LEVEL ); +} + +/** + * \brief Set current time + * + * \param time Time value to set + */ +void rtc_set_time(uint32_t time) +{ + RTC.CTRL = RTC_PRESCALER_OFF_gc; + + while (rtc_is_busy()); + + RTC.CNT = time; + rtc_data.counter_high = time >> 16; + RTC.CTRL = CONFIG_RTC_PRESCALER; +} + +/** + * \brief Get current time + * + * \return Current time value + * + * \note Due to errate, this can return old values shortly after waking up from + * sleep. + */ +uint32_t rtc_get_time(void) +{ + irqflags_t flags; + uint16_t count_high; + uint16_t count_low; + + flags = cpu_irq_save(); + count_high = rtc_data.counter_high; + count_low = RTC.CNT; + // Test for possible pending increase of high count value + if ((count_low == 0) && (RTC.INTFLAGS & RTC_OVFIF_bm)) + count_high++; + cpu_irq_restore(flags); + + return ((uint32_t)count_high << 16) | count_low; +} + +/** + * \brief Set alarm time + * + * Will set absolute alarm time that will call the callback specifed by \ref + * rtc_set_callback on completion. Or possibly use \ref + * rtc_alarm_has_triggered to check for it. + * + * Any pending alarm will be overwritten with this function. + * + * \param time Absolute time value. See also \ref rtc_min_alarm_time + * \pre Needs interrupts disabled if used from several contexts + */ +void rtc_set_alarm(uint32_t time) +{ + RTC.INTCTRL = RTC_OVERFLOW_INT_LEVEL; + RTC.COMP = time; + rtc_data.alarm_low = time; + rtc_data.alarm_high = time >> 16; + + while (rtc_is_busy()); + + RTC.INTFLAGS = RTC_COMPIF_bm; + RTC.INTCTRL = (uint8_t)RTC_COMPARE_INT_LEVEL + | (uint8_t)RTC_OVERFLOW_INT_LEVEL; +} + +/** + * \brief Set callback to call on alarm + * + * \param callback Callback function pointer + */ +void rtc_set_callback(rtc_callback_t callback) +{ + rtc_data.callback = callback; +} + +/** + * \brief Initialize the RTC + * + * Start up the RTC and start counting from 0 + */ +void rtc_init(void) +{ + sysclk_enable_module(SYSCLK_PORT_GEN, SYSCLK_RTC); + CLK.RTCCTRL = CONFIG_RTC_CLOCK_SOURCE | CLK_RTCEN_bm; + RTC.PER = 0xffff; + RTC.CNT = 0; + /* Since overflow interrupt is needed all the time we limit sleep to + * power-save. + */ + sleepmgr_lock_mode(SLEEPMGR_PSAVE); + RTC.INTCTRL = RTC_OVERFLOW_INT_LEVEL; + RTC.CTRL = CONFIG_RTC_PRESCALER; +} + +/** + * \internal + * \brief Overflow interrupt handling high counter + */ +ISR(RTC_OVF_vect) +{ + rtc_data.counter_high++; +} + +/** + * \internal + * \brief Compare interrupt used for alarm + */ +ISR(RTC_COMP_vect) +{ + if (rtc_data.counter_high >= rtc_data.alarm_high) { + RTC.INTCTRL = RTC_OVERFLOW_INT_LEVEL; + if (rtc_data.callback) { + uint32_t count = ((uint32_t)rtc_data.counter_high << 16) + | RTC.CNT; + uint32_t alarm = ((uint32_t)rtc_data.alarm_high << 16) + | rtc_data.alarm_low; + /* Workaround for errata. Count might not be updated + * when waking up from sleep, so in this case use alarm + * time pluss one. + */ + if (alarm >= count) + count = alarm + 1; + rtc_data.callback(count); + } + } +} diff --git a/DSTAT1/src/asf/xmega/drivers/rtc/rtc.h b/DSTAT1/src/asf/xmega/drivers/rtc/rtc.h new file mode 100644 index 0000000000000000000000000000000000000000..befc4647987e843de546c126fee9570ec4162060 --- /dev/null +++ b/DSTAT1/src/asf/xmega/drivers/rtc/rtc.h @@ -0,0 +1,292 @@ +/** + * \file + * + * \brief AVR XMEGA Real Time Counter driver definitions + * + * Copyright (c) 2010 Atmel Corporation. All rights reserved. + * + * \asf_license_start + * + * 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. The name of Atmel may not be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * 4. This software may only be redistributed and used in connection with an + * Atmel microcontroller product. + * + * THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE + * EXPRESSLY AND SPECIFICALLY DISCLAIMED. IN NO EVENT SHALL ATMEL 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. + * + * \asf_license_stop + * + */ +#ifndef DRIVERS_RTC_RTC_H +#define DRIVERS_RTC_RTC_H + +#include +#include + +/** + * \defgroup rtc_group Real Time Counter (RTC) + * + * See \ref rtc_quickstart. + * + * This is a driver implementation for the XMEGA RTC. + * + * \section rtc_min_alarm_time Minimum allowed alarm time + * + * If current time is close to a time unit roll over, there is a risk to miss + * this when using a value of 0. + * + * A safe use of this can be in an alarm callback. + * + * @{ + */ + +/** + * \def CONFIG_RTC_COMPARE_INT_LEVEL + * \brief Configuration symbol for interrupt level to use on alarm + * + * Possible values: + * - RTC_COMPINTLVL_LO_gc + * - RTC_COMPINTLVL_MED_gc + * - RTC_COMPINTLVL_HI_gc + */ +#ifdef __DOXYGEN__ +# define CONFIG_RTC_COMPARE_INT_LEVEL +#endif + +/** + * \def CONFIG_RTC_OVERFLOW_INT_LEVEL + * \brief Configuration symbol for interrupt level to use on overflow + * + * Possible values: + * - RTC_OVFINTLVL_LO_gc + * - RTC_OVFINTLVL_MED_gc + * - RTC_OVFINTLVL_HI_gc + */ +#ifdef __DOXYGEN__ +# define CONFIG_RTC_OVERFLOW_INT_LEVEL +#endif + +/** + * \def CONFIG_RTC_PRESCALER + * \brief Configuration symbol for prescaler to use + * + * Possible values: + * - RTC_PRESCALER_DIV1_gc + * - RTC_PRESCALER_DIV2_gc + * - RTC_PRESCALER_DIV8_gc + * - RTC_PRESCALER_DIV16_gc + * - RTC_PRESCALER_DIV64_gc + * - RTC_PRESCALER_DIV256_gc + * - RTC_PRESCALER_DIV1024_gc + */ +#ifdef __DOXYGEN__ +# define CONFIG_RTC_PRESCALER +#endif + +/** + * \def CONFIG_RTC_CLOCK_SOURCE + * \brief Configuration symbol for which clock source to use + * + * Possible values: + * - CLK_RTCSRC_ULP_gc + * - CLK_RTCSRC_TOSC_gc + * - CLK_RTCSRC_RCOSC_gc + * - CLK_RTCSRC_TOSC32_gc + */ +#ifdef __DOXYGEN__ +# define CONFIG_RTC_CLOCK_SOURCE +#endif + +/** + * \brief Callback definition for alarm callback + * + * \param time The time of the alarm + */ +typedef void (*rtc_callback_t)(uint32_t time); + +void rtc_set_callback(rtc_callback_t callback); +void rtc_set_time(uint32_t time); +uint32_t rtc_get_time(void); +void rtc_set_alarm(uint32_t time); +bool rtc_alarm_has_triggered(void); + +/** + * \brief Set alarm relative to current time + * + * \param offset Offset to current time. This is minimum value, so the alarm + * might happen at up to one time unit later. See also \ref + * rtc_min_alarm_time + * + * \note Due to errata, this can be unsafe to do shortly after waking up from + * sleep. + */ +static inline void rtc_set_alarm_relative(uint32_t offset) +{ + rtc_set_alarm(rtc_get_time() + offset); +} + +extern void rtc_init(void); + +//! @} + +/** + * \page rtc_quickstart Quick start guide for RTC driver + * + * This is the quick start guide for the \ref rtc_group "RTC driver", with + * step-by-step instructions on how to configure and use the drivers in a + * selection of use cases. + * + * The use cases contain several code fragments. The code fragments in the + * steps for setup can be copied into a custom initialization function, while + * the steps for usage can be copied into, e.g., the main application function. + * + * \section rtc_basic_use_case Basic use case + * In this basic use case, the RTC is configured for: + * - Clock source: 1 kHz from internal 32 kHz ULP + * - Prescaling: RTC clock/1024 + * + * \section rtc_basic_use_case_setup Setup steps + * + * \subsection rtc_basic_use_case_setup_code Example code + * Content of conf_rtc.h: + * \code + * #define CONFIG_RTC_PRESCALER RTC_PRESCALER_DIV1024_gc + * #define CONFIG_RTC_CLOCK_SOURCE CLK_RTCSRC_ULP_gc + * \endcode + * Add to the initialization code: + * \code + * sysclk_init(); + * rtc_init(); + * \endcode + * + * \subsection rtc_basic_use_case_setup_flow Workflow + * -# Ensure that conf_rtc.h is present for the driver. + * - \note This configuration file is used by the driver and + * should not be included by the user. + * -# Initialize system clock: + * - \code sysclk_init(); \endcode + * -# Call RTC driver's own init function to start up the RTC and start + * counting from zero: + * - \code rtc_init(); \endcode + * + * \section rtc_basic_use_case_usage Usage steps + * + * \subsection rtc_basic_use_case_usage_code Example code + * Add to, e.g., main loop in application C-file: + * \code + * rtc_get_time(); + * \endcode + * + * \subsection rtc_basic_use_case_usage_flow Workflow + * -# Get current time of the RTC: + * - \code rtc_get_time(); \endcode + * + * \section rtc_use_cases Advanced use cases + * For more advanced use of the RTC driver, see the following use cases: + * - \subpage rtc_use_case_1 : + */ + +/** + * \page rtc_use_case_1 Use case #1 + * + * In this use case, the RTC is configured for: + * - Clock source: 1 kHz from internal 32 kHz ULP + * - Prescaling: RTC clock/1024 + * + * This use case shows how to set an alarm for the RTC. + * + * \section rtc_use_case_1_setup Setup steps + * + * \subsection rtc_basic_use_case_setup_prereq Prerequisites + * For the setup code of this use case to work, the following must + * be added to the project: + * -# PMIC for interrupt handling. + * -# Sleep Managager. + * -# A \ref rtc_callback_t "callback" function, called alarm, that + * reschedules the alarm must be provided by the user: + * \code + * static void alarm(uint32_t time) + * { + * rtc_set_alarm(time); + * } + * \endcode + * + * \subsection rtc_use_case_1_setup_code Example code + * Content of conf_rtc.h: + * \code + * #define CONFIG_RTC_PRESCALER RTC_PRESCALER_DIV1024_gc + * #define CONFIG_RTC_CLOCK_SOURCE CLK_RTCSRC_ULP_gc + * \endcode + * Add to application initialization: + * \code + * pmic_init(); + * sysclk_init(); + * sleepmgr_init(); + * rtc_init(); + * rtc_set_callback(alarm); + * cpu_irq_enable(); + * \endcode + * + * \subsection rtc_use_case_1_setup_flow Workflow + * -# Ensure that conf_rtc.h is present for the driver. + * - \note This configuration file is used by the driver and + * should not be included by the user. + * -# Call the init function of the PMIC driver to enable all interrupt levels: + * - \code pmic_init(); \endcode + * -# Initialize system clock: + * - \code sysclk_init(); \endcode + * -# Call the init function of the sleep manager driver to be able to sleep + * waiting for alarm: + * - \code sleepmgr_init(); \endcode + * -# Call RTC driver's own init function to start up the RTC and start + * counting from zero: + * - \code rtc_init(); \endcode + * -# Set callback function to call on alarm: + * - \code rtc_set_callback(alarm); \endcode + * - \note The callback function alarm must be defined by the user. + * -# Enable interrupts globally: + * - \code cpu_irq_enable(); \endcode + * + * \section rtc_use_case_1_usage Usage steps + * + * \subsection rtc_use_case_1_usage_code Example code + * \code + * rtc_set_alarm_relative(0); + * while (true) { + * sleepmgr_enter_sleep(); + * } + * \endcode + * + * \subsection rtc_use_case_1_usage_flow Workflow + * -# Set the alarm to trigget on next time unit roll over: + * - \code rtc_set_alarm_relative(0); \endcode + * -# Sleep between each triggered alarm: + * - \code + * while (true) { + * sleepmgr_enter_sleep(); + * } + * \endcode + */ + +#endif /* RTC_H */ diff --git a/DSTAT1/src/asf/xmega/drivers/sleep/sleep.h b/DSTAT1/src/asf/xmega/drivers/sleep/sleep.h new file mode 100644 index 0000000000000000000000000000000000000000..19ef9bb1947d5ca515f789c9e55dd57c8620f54d --- /dev/null +++ b/DSTAT1/src/asf/xmega/drivers/sleep/sleep.h @@ -0,0 +1,164 @@ +/** + * \file + * + * \brief Sleep controller driver + * + * Copyright (c) 2010 Atmel Corporation. All rights reserved. + * + * \asf_license_start + * + * 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. The name of Atmel may not be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * 4. This software may only be redistributed and used in connection with an + * Atmel microcontroller product. + * + * THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE + * EXPRESSLY AND SPECIFICALLY DISCLAIMED. IN NO EVENT SHALL ATMEL 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. + * + * \asf_license_stop + * + */ +#ifndef SLEEP_H +#define SLEEP_H + +#include + +/** + * \defgroup sleep_group Sleep controller driver + * + * This is a low-level driver implementation for the AVR XMEGA sleep controller. + * + * \note To minimize the code overhead, these functions do not feature + * interrupt-protected access since they are likely to be called inside + * interrupt handlers or in applications where such protection is not + * necessary. If such protection is needed, it must be ensured by the calling + * code. + * + * \section xmega_sleep_quickstart_section Quick Start Guide + * See \ref xmega_sleep_quickstart + * @{ + */ + +#if defined(__ICCAVR__) || defined(__DOXYGEN__) +# include +//! Macro for issuing the sleep instruction. +# define sleep_enter() __sleep() + +/** + * \brief Enable sleep + */ +static inline void sleep_enable(void) +{ + SLEEP.CTRL |= SLEEP_SEN_bm; +} + +/** + * \brief Disable sleep + */ +static inline void sleep_disable(void) +{ + SLEEP.CTRL &= ~SLEEP_SEN_bm; +} + +#elif defined(__GNUC__) +# include +# define sleep_enter() sleep_cpu() + +#else +# error Unsupported compiler. +#endif + +/** + * \brief Set new sleep mode + * + * \param mode Sleep mode, from the device IO header file. + */ +static inline void sleep_set_mode(enum SLEEP_SMODE_enum mode) +{ + SLEEP.CTRL = mode | (SLEEP.CTRL & ~SLEEP_SMODE_gm); +} + +//! @} + +/** + * \page xmega_sleep_quickstart Quick Start Guide for the XMEGA Sleep Driver + * + * This is the quick start guide for the \ref sleep_group "Sleep Driver", with + * step-by-step instructions on how to configure and use the driver for a + * specific use case. + * + * The section described below can be copied into, e.g. the main application + * loop or any other function that will need to control and execute different + * sleep modes on the device. + * + * \section xmega_sleep_quickstart_basic Basic usage of the sleep driver + * This use case will prepare the device to enter the Power Down sleep mode and + * then enter the sleep mode. After waking up it will disable sleep. + * + * \section xmega_sleep_basic_usage Usage steps + * \subsection xmega_sleep_basic_usage_code Example code + * Add to, e.g., the main loop in the application C-file: + * \code + * sleep_set_mode(SLEEP_SMODE_PDOWN_gc); + * sleep_enable(); + * sleep_enter(); + * sleep_disable(); + * \endcode + * + * \subsection xmega_sleep_basic_usage Workflow + * -# Set what sleep mode to use, the different sleep modes can be found in the + * device header file under the enum definition SLEEP_SMODE_enum: + * - \code sleep_set_mode(SLEEP_SMODE_PDOWN_gc); \endcode + * -# Enable that the device are allowed to go to sleep: + * - \code sleep_enable(); \endcode + * - \note This function has to be called in order for the device to go to + * sleep. This is a safety feature to stop the device to go to sleep + * unintentionally, even though it is possible to have this enabled at all times + * it is recommended to enable sleep mode only when you intend to go to sleep + * within a few clock cycles. + * -# Enter sleep mode: + * - \code sleep_enter(); \endcode + * - \attention Make sure to enable global interrupt and the interrupt you + * plan to use as wake-up source for your device, do also pay special + * attention to what wake-up sources are available for the different sleep + * modes. Failing to enable interrupts may result in indefinite sleep until + * power is cycled! + * -# When the device is woken from sleep it will execute the interrupt handler + * related to the wakeup-source (interrupt source) and continue on the next line + * of code after the \ref sleep_enter() call. Make sure to disable sleep when + * waking up. + * - \code sleep_disable(); \endcode + * + * \subsection xmega_sleep_basic_sleep_modes Sleep Modes + * Possible sleep modes depend on the device that is used. Please refer to the + * device datasheet and header file to find these definitions. + * + * As an example the ATxmega32A4U device has the following sleep modes: + * - Idle sleep: SLEEP_SMODE_IDLE_gc + * - Power Down: SLEEP_SMODE_PDOWN_gc + * - Power Save: SLEEP_SMODE_PSAVE_gc + * - Standby: SLEEP_SMODE_STDBY_gc + * - Extended standby: SLEEP_SMODE_ESTDBY_gc + */ + +#endif /* SLEEP_H */ diff --git a/DSTAT1/src/asf/xmega/drivers/spi/spi.c b/DSTAT1/src/asf/xmega/drivers/spi/spi.c new file mode 100644 index 0000000000000000000000000000000000000000..186e497b869df479b272412d30b4faa9f0f167e9 --- /dev/null +++ b/DSTAT1/src/asf/xmega/drivers/spi/spi.c @@ -0,0 +1,114 @@ +/***************************************************************************** + * + * \file + * + * \brief SPI software driver functions. + * + * Copyright (c) 2010 Atmel Corporation. All rights reserved. + * + * \asf_license_start + * + * 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. The name of Atmel may not be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * 4. This software may only be redistributed and used in connection with an + * Atmel microcontroller product. + * + * THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE + * EXPRESSLY AND SPECIFICALLY DISCLAIMED. IN NO EVENT SHALL ATMEL 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. + * + * \asf_license_stop + * + *****************************************************************************/ + +#include "spi.h" + +/*! \brief Calculates the SPI baudrate divider. + * + * \param baudrate The expected baudrate on the SPI. + * \param clkper_hz SPI module input clock frequency (Peripheral clock, Hz). + * \param spi The SPI module address + * + * \return Status of operation. + * \retval >=0 Success. + * \retval <0 Error. + */ +int8_t spi_xmega_set_baud_div(SPI_t *spi, uint32_t baudrate, uint32_t clkper_hz) +{ + uint32_t divisor; + uint8_t divisor_8bit; + uint8_t ctrl; + + // Sanity check, requested baudrate is lower than system clock + Assert(clkper_hz > baudrate); + + /* + * Get wanted divisor rounded up so we don't get speed higher than + * requested baudrate. + */ + divisor = (clkper_hz + baudrate - 1) / baudrate; + + if (divisor > 128) { + /* + * Highest possible divisor is 128 so fail since we can't get + * low enough baudrate. + */ + return -1; + } + + /* + * We now know that the divisor is 128 or lower so move it into a 8-bit + * variable to make sure the following comparison is more optimized. + */ + divisor_8bit = divisor; + + /* + * For divisor values between the possible ones round up to the closest + * higher one to avoid higher baudrate than requested. + */ + if (divisor_8bit > 64) { + ctrl = SPI_PRESCALER_DIV128_gc; + } + else if (divisor_8bit > 32) { + ctrl = SPI_PRESCALER_DIV64_gc; + } + else if (divisor_8bit > 16) { + ctrl = SPI_CLK2X_bm | SPI_PRESCALER_DIV64_gc; + } + else if (divisor_8bit > 8) { + ctrl = SPI_PRESCALER_DIV16_gc; + } + else if (divisor_8bit > 4) { + ctrl = SPI_CLK2X_bm | SPI_PRESCALER_DIV16_gc; + } + else if (divisor_8bit > 2) { + ctrl = SPI_PRESCALER_DIV4_gc; + } + else { + ctrl = SPI_CLK2X_bm | SPI_PRESCALER_DIV4_gc; + } + + // Update register and make sure to clear out any leftover bits + spi->CTRL = (spi->CTRL & ~(SPI_CLK2X_bm | SPI_PRESCALER_gm)) | ctrl; + + return 1; +} diff --git a/DSTAT1/src/asf/xmega/drivers/spi/spi.h b/DSTAT1/src/asf/xmega/drivers/spi/spi.h new file mode 100644 index 0000000000000000000000000000000000000000..2fac1037bd6c8179ef6178a93c0fdc1ee5633f83 --- /dev/null +++ b/DSTAT1/src/asf/xmega/drivers/spi/spi.h @@ -0,0 +1,161 @@ +/***************************************************************************** + * + * \file + * + * \brief SPI driver for AVR. + * + * This file defines a useful set of functions for the SPI interface on AVR + * devices. + * + * Copyright (c) 2009 Atmel Corporation. All rights reserved. + * + * \asf_license_start + * + * 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. The name of Atmel may not be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * 4. This software may only be redistributed and used in connection with an + * Atmel microcontroller product. + * + * THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE + * EXPRESSLY AND SPECIFICALLY DISCLAIMED. IN NO EVENT SHALL ATMEL 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. + * + * \asf_license_stop + * + ******************************************************************************/ + + +#ifndef _SPI_H_ +#define _SPI_H_ + +/** + * \defgroup group_xmega_drivers_spi SPI - Serial Peripheral Interface + * + * Driver for the Serial Peripheral Interface (SPI). + * Provides functions for configuring and using the SPI. + * + * \{ + */ + +#include "compiler.h" +#include "status_codes.h" +#include "ioport.h" + +/*! \brief Calculates the SPI baudrate divider. + * + * \param baudrate The expected baudrate on the SPI. + * \param clkper_hz SPI module input clock frequency (Peripheral clock, Hz). + * \param spi The SPI module address + * + * \return Divider or error code. + * \retval >=0 Success. + * \retval <0 Error. + */ +int8_t spi_xmega_set_baud_div(SPI_t *spi, uint32_t baudrate, uint32_t clkper_hz); + +/*! \brief Enables the SPI. + * + * \param spi Base address of the SPI instance. + */ +static inline void spi_enable(SPI_t *spi) +{ + spi->CTRL |= SPI_ENABLE_bm; +} + +/*! \brief Disables the SPI. + * + * Ensures that nothing is transferred while setting up buffers. + * + * \param spi Base address of the SPI instance. + * + * \warning This may cause data loss if used on a slave SPI. + */ +static inline void spi_disable(SPI_t *spi) +{ + spi->CTRL &= ~SPI_ENABLE_bm; +} + +/*! \brief Tests if the SPI is enabled. + * + * \param spi Base address of the SPI instance. + * + * \return \c 1 if the SPI is enabled, otherwise \c 0. + */ +static inline bool spi_is_enabled(SPI_t *spi) +{ + return spi->CTRL & SPI_ENABLE_bm ? true : false; +} + +/*! \brief Put one data byte to a SPI peripheral. + * + * \param spi Base address of the SPI instance. + * \param data The data byte to be loaded + * + */ +static inline void spi_put(SPI_t *spi, uint8_t data) +{ + spi->DATA = data; +} + +/*! \brief Get one data byte to a SPI peripheral. + * + * \param spi Base address of the SPI instance. + * \return The data byte + * + */ +static inline uint8_t spi_get(SPI_t *spi) +{ + return spi->DATA; +} + +/*! \brief Tests if the SPI contains a received character. + * + * \param spi Base address of the SPI instance. + * + * \return \c 1 if the SPI Receive Holding Register is full, otherwise \c 0. + */ +static inline bool spi_is_tx_ok(SPI_t *spi) +{ + return spi->STATUS & SPI_IF_bm ? true : false; +} + +/*! \brief Activate SPI master mode of a SPI peripheral + * + * \param spi Base address of the SPI instance. + * + * \warning This may cause data loss if used on a slave SPI. + */ +static inline void spi_enable_master_mode(SPI_t *spi) +{ + spi->CTRL |= SPI_MASTER_bm; +} + +/*! \name Part Specific SPI Driver + */ +//! @{ +//! @} + +/** + * \} + */ + +#endif // _SPI_H_ diff --git a/DSTAT1/src/asf/xmega/drivers/tc/tc.c b/DSTAT1/src/asf/xmega/drivers/tc/tc.c new file mode 100644 index 0000000000000000000000000000000000000000..14e5823ad42ee38cb31f052ec3c63e642a4db9f3 --- /dev/null +++ b/DSTAT1/src/asf/xmega/drivers/tc/tc.c @@ -0,0 +1,1076 @@ +/** + * \file + * + * \brief AVR XMEGA TC Driver + * + * Copyright (c) 2010 Atmel Corporation. All rights reserved. + * + * \asf_license_start + * + * 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. The name of Atmel may not be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * 4. This software may only be redistributed and used in connection with an + * Atmel microcontroller product. + * + * THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE + * EXPRESSLY AND SPECIFICALLY DISCLAIMED. IN NO EVENT SHALL ATMEL 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. + * + * \asf_license_stop + * + */ +#include + +#include "interrupt.h" +#include "compiler.h" +#include "parts.h" + +#include "tc.h" +#include "sysclk.h" +#include "sleepmgr.h" +#include "status_codes.h" + +#if defined(TCC0) || defined(__DOXYGEN__) +//! \internal Local storage of Timer Counter TCC0 interrupt callback function +static tc_callback_t tc_tcc0_ovf_callback; +static tc_callback_t tc_tcc0_err_callback; +static tc_callback_t tc_tcc0_cca_callback; +static tc_callback_t tc_tcc0_ccb_callback; +static tc_callback_t tc_tcc0_ccc_callback; +static tc_callback_t tc_tcc0_ccd_callback; + + +/** + * \internal + * \brief Interrupt handler for Timer Counter C0 overflow + * + * This function will handle interrupt on Timer Counter CO overflow and + * call the callback function. + */ +ISR(TCC0_OVF_vect) +{ + if (tc_tcc0_ovf_callback) { + tc_tcc0_ovf_callback(); + } +} + +/** + * \internal + * \brief Interrupt handler for Timer Counter C0 error + * + * This function will handle interrupt on Timer Counter CO error and + * call the callback function. + */ +ISR(TCC0_ERR_vect) +{ + if (tc_tcc0_err_callback) { + tc_tcc0_err_callback(); + } +} + +/** + * \internal + * \brief Interrupt handler for Timer Counter C0 Compare/CaptureA + * + * This function will handle interrupt on Timer Counter CO Compare/CaptureA and + * call the callback function. + */ +ISR(TCC0_CCA_vect) +{ + if (tc_tcc0_cca_callback) { + tc_tcc0_cca_callback(); + } +} + +/** + * \internal + * \brief Interrupt handler for Timer Counter C0 Compare/CaptureB + * + * This function will handle interrupt on Timer Counter CO Compare/CaptureB and + * call the callback function. + */ +ISR(TCC0_CCB_vect) +{ + if (tc_tcc0_ccb_callback) { + tc_tcc0_ccb_callback(); + } +} + +/** + * \internal + * \brief Interrupt handler for Timer Counter C0 Compare/CaptureC + * + * This function will handle interrupt on Timer Counter CO Compare/CaptureC and + * call the callback function. + */ +ISR(TCC0_CCC_vect) +{ + if (tc_tcc0_ccc_callback) { + tc_tcc0_ccc_callback(); + } +} + +/** + * \internal + * \brief Interrupt handler for Timer Counter C0 Compare/CaptureD + * + * This function will handle interrupt on Timer Counter CO Compare/CaptureD and + * call the callback function. + */ +ISR(TCC0_CCD_vect) +{ + if (tc_tcc0_ccd_callback) { + tc_tcc0_ccd_callback(); + } +} + +#endif + +#if defined(TCC1) || defined(__DOXYGEN__) +//! \internal Local storage of Timer Counter TCC1 interrupt callback function +static tc_callback_t tc_tcc1_ovf_callback; +static tc_callback_t tc_tcc1_err_callback; +static tc_callback_t tc_tcc1_cca_callback; +static tc_callback_t tc_tcc1_ccb_callback; + +/** + * \internal + * \brief Interrupt handler for Timer Counter C1 overflow + * + * This function will handle interrupt on Timer Counter C1 overflow and + * call the callback function. + */ +ISR(TCC1_OVF_vect) +{ + if (tc_tcc1_ovf_callback) { + tc_tcc1_ovf_callback(); + } +} + +/** + * \internal + * \brief Interrupt handler for Timer Counter C1 error + * + * This function will handle interrupt on Timer Counter C1 error and + * call the callback function. + */ +ISR(TCC1_ERR_vect) +{ + if (tc_tcc1_err_callback) { + tc_tcc1_err_callback(); + } +} + +/** + * \internal + * \brief Interrupt handler for Timer Counter C1 Compare/CaptureA + * + * This function will handle interrupt on Timer Counter C1 Compare/CaptureA and + * call the callback function. + */ +ISR(TCC1_CCA_vect) +{ + if (tc_tcc1_cca_callback) { + tc_tcc1_cca_callback(); + } +} + +/** + * \internal + * \brief Interrupt handler for Timer Counter C1 Compare/CaptureB + * + * This function will handle interrupt on Timer Counter C1 Compare/CaptureB and + * call the callback function. + */ +ISR(TCC1_CCB_vect) +{ + if (tc_tcc1_ccb_callback) { + tc_tcc1_ccb_callback(); + } +} + +#endif + +#if defined(TCD0) || defined(__DOXYGEN__) +//! \internal Local storage of Timer Counter TCD0 interrupt callback function +static tc_callback_t tc_tcd0_ovf_callback; +static tc_callback_t tc_tcd0_err_callback; +static tc_callback_t tc_tcd0_cca_callback; +static tc_callback_t tc_tcd0_ccb_callback; +static tc_callback_t tc_tcd0_ccc_callback; +static tc_callback_t tc_tcd0_ccd_callback; + + +/** + * \internal + * \brief Interrupt handler for Timer Counter D0 overflow + * + * This function will handle interrupt on Timer Counter D0 overflow and + * call the callback function. + */ +ISR(TCD0_OVF_vect) +{ + if (tc_tcd0_ovf_callback) { + tc_tcd0_ovf_callback(); + } +} + +/** + * \internal + * \brief Interrupt handler for Timer Counter D0 error + * + * This function will handle interrupt on Timer Counter D0 error and + * call the callback function. + */ +ISR(TCD0_ERR_vect) +{ + if (tc_tcd0_err_callback) { + tc_tcd0_err_callback(); + } +} + +/** + * \internal + * \brief Interrupt handler for Timer Counter D0 Compare/CaptureA + * + * This function will handle interrupt on Timer Counter D0 Compare/CaptureA and + * call the callback function. + */ +ISR(TCD0_CCA_vect) +{ + if (tc_tcd0_cca_callback) { + tc_tcd0_cca_callback(); + } +} + +/** + * \internal + * \brief Interrupt handler for Timer Counter D0 Compare/CaptureB + * + * This function will handle interrupt on Timer Counter D0 Compare/CaptureB and + * call the callback function. + */ +ISR(TCD0_CCB_vect) +{ + if (tc_tcd0_ccb_callback) { + tc_tcd0_ccb_callback(); + } +} + +/** + * \internal + * \brief Interrupt handler for Timer Counter D0 Compare/CaptureC + * + * This function will handle interrupt on Timer Counter D0 Compare/CaptureC and + * call the callback function. + */ +ISR(TCD0_CCC_vect) +{ + if (tc_tcd0_ccc_callback) { + tc_tcd0_ccc_callback(); + } +} + +/** + * \internal + * \brief Interrupt handler for Timer Counter D0 Compare/CaptureD + * + * This function will handle interrupt on Timer Counter D0 Compare/CaptureD and + * call the callback function. + */ +ISR(TCD0_CCD_vect) +{ + if (tc_tcd0_ccd_callback) { + tc_tcd0_ccd_callback(); + } +} + +#endif + +#if defined(TCD1) || defined(__DOXYGEN__) +//! \internal Local storage of Timer Counter TCD1 interrupt callback function +static tc_callback_t tc_tcd1_ovf_callback; +static tc_callback_t tc_tcd1_err_callback; +static tc_callback_t tc_tcd1_cca_callback; +static tc_callback_t tc_tcd1_ccb_callback; + +/** + * \internal + * \brief Interrupt handler for Timer Counter D1 overflow + * + * This function will handle interrupt on Timer Counter D1 overflow and + * call the callback function. + */ +ISR(TCD1_OVF_vect) +{ + if (tc_tcd1_ovf_callback) { + tc_tcd1_ovf_callback(); + } +} + +/** + * \internal + * \brief Interrupt handler for Timer Counter D1 error + * + * This function will handle interrupt on Timer Counter D1 error and + * call the callback function. + */ +ISR(TCD1_ERR_vect) +{ + if (tc_tcd1_err_callback) { + tc_tcd1_err_callback(); + } +} + +/** + * \internal + * \brief Interrupt handler for Timer Counter D1 Compare/CaptureA + * + * This function will handle interrupt on Timer Counter D1 Compare/CaptureA and + * call the callback function. + */ +ISR(TCD1_CCA_vect) +{ + if (tc_tcd1_cca_callback) { + tc_tcd1_cca_callback(); + } +} + +/** + * \internal + * \brief Interrupt handler for Timer Counter D1 Compare/CaptureB + * + * This function will handle interrupt on Timer Counter D1 Compare/CaptureB and + * call the callback function. + */ +ISR(TCD1_CCB_vect) +{ + if (tc_tcd1_ccb_callback) { + tc_tcd1_ccb_callback(); + } +} + +#endif + + +#if defined(TCE0) || defined(__DOXYGEN__) +//! \internal Local storage of Timer Counter TCE0 interrupt callback function +static tc_callback_t tc_tce0_ovf_callback; +static tc_callback_t tc_tce0_err_callback; +static tc_callback_t tc_tce0_cca_callback; +static tc_callback_t tc_tce0_ccb_callback; +static tc_callback_t tc_tce0_ccc_callback; +static tc_callback_t tc_tce0_ccd_callback; + + +/** + * \internal + * \brief Interrupt handler for Timer Counter E0 overflow + * + * This function will handle interrupt on Timer Counter E0 overflow and + * call the callback function. + */ +ISR(TCE0_OVF_vect) +{ + if (tc_tce0_ovf_callback) { + tc_tce0_ovf_callback(); + } +} + +/** + * \internal + * \brief Interrupt handler for Timer Counter E0 error + * + * This function will handle interrupt on Timer Counter E0 error and + * call the callback function. + */ +ISR(TCE0_ERR_vect) +{ + if (tc_tce0_err_callback) { + tc_tce0_err_callback(); + } +} + +/** + * \internal + * \brief Interrupt handler for Timer Counter E0 Compare/CaptureA + * + * This function will handle interrupt on Timer Counter E0 Compare/CaptureA and + * call the callback function. + */ +ISR(TCE0_CCA_vect) +{ + if (tc_tce0_cca_callback) { + tc_tce0_cca_callback(); + } +} + +/** + * \internal + * \brief Interrupt handler for Timer Counter E0 Compare/CaptureB + * + * This function will handle interrupt on Timer Counter E0 Compare/CaptureB and + * call the callback function. + */ +ISR(TCE0_CCB_vect) +{ + if (tc_tce0_ccb_callback) { + tc_tce0_ccb_callback(); + } +} + +/** + * \internal + * \brief Interrupt handler for Timer Counter E0 Compare/CaptureC + * + * This function will handle interrupt on Timer Counter E0 Compare/CaptureC and + * call the callback function. + */ +ISR(TCE0_CCC_vect) +{ + if (tc_tce0_ccc_callback) { + tc_tce0_ccc_callback(); + } +} + +/** + * \internal + * \brief Interrupt handler for Timer Counter E0 Compare/CaptureD + * + * This function will handle interrupt on Timer Counter E0 Compare/CaptureD and + * call the callback function. + */ +ISR(TCE0_CCD_vect) +{ + if (tc_tce0_ccd_callback) { + tc_tce0_ccd_callback(); + } +} + +#endif + +#if defined(TCE1) || defined(__DOXYGEN__) +//! \internal Local storage of Timer Counter TCE1 interrupt callback function +static tc_callback_t tc_tce1_ovf_callback; +static tc_callback_t tc_tce1_err_callback; +static tc_callback_t tc_tce1_cca_callback; +static tc_callback_t tc_tce1_ccb_callback; + +/** + * \internal + * \brief Interrupt handler for Timer Counter E1 overflow + * + * This function will handle interrupt on Timer Counter E1 overflow and + * call the callback function. + */ +ISR(TCE1_OVF_vect) +{ + if (tc_tce1_ovf_callback) { + tc_tce1_ovf_callback(); + } +} + +/** + * \internal + * \brief Interrupt handler for Timer Counter E1 error + * + * This function will handle interrupt on Timer Counter E1 error and + * call the callback function. + */ +ISR(TCE1_ERR_vect) +{ + if (tc_tce1_err_callback) { + tc_tce1_err_callback(); + } +} + +/** + * \internal + * \brief Interrupt handler for Timer Counter E1 Compare/CaptureA + * + * This function will handle interrupt on Timer Counter E1 Compare/CaptureA and + * call the callback function. + */ +ISR(TCE1_CCA_vect) +{ + if (tc_tce1_cca_callback) { + tc_tce1_cca_callback(); + } +} + +/** + * \internal + * \brief Interrupt handler for Timer Counter E1 Compare/CaptureB + * + * This function will handle interrupt on Timer Counter E1 Compare/CaptureB and + * call the callback function. + */ +ISR(TCE1_CCB_vect) +{ + if (tc_tce1_ccb_callback) { + tc_tce1_ccb_callback(); + } +} + +#endif + +#if defined(TCF0) || defined(__DOXYGEN__) +//! \internal Local storage of Timer Counter TCF0 interrupt callback function +static tc_callback_t tc_tcf0_ovf_callback; +static tc_callback_t tc_tcf0_err_callback; +static tc_callback_t tc_tcf0_cca_callback; +static tc_callback_t tc_tcf0_ccb_callback; +static tc_callback_t tc_tcf0_ccc_callback; +static tc_callback_t tc_tcf0_ccd_callback; + + +/** + * \internal + * \brief Interrupt handler for Timer Counter E0 overflow + * + * This function will handle interrupt on Timer Counter F0 overflow and + * call the callback function. + */ +ISR(TCF0_OVF_vect) +{ + if (tc_tcf0_ovf_callback) { + tc_tcf0_ovf_callback(); + } +} + +/** + * \internal + * \brief Interrupt handler for Timer Counter F0 error + * + * This function will handle interrupt on Timer Counter F0 error and + * call the callback function. + */ +ISR(TCF0_ERR_vect) +{ + if (tc_tcf0_err_callback) { + tc_tcf0_err_callback(); + } +} + +/** + * \internal + * \brief Interrupt handler for Timer Counter F0 Compare/CaptureA + * + * This function will handle interrupt on Timer Counter F0 Compare/CaptureA and + * call the callback function. + */ +ISR(TCF0_CCA_vect) +{ + if (tc_tcf0_cca_callback) { + tc_tcf0_cca_callback(); + } +} + +/** + * \internal + * \brief Interrupt handler for Timer Counter F0 Compare/CaptureB + * + * This function will handle interrupt on Timer Counter F0 Compare/CaptureB and + * call the callback function. + */ +ISR(TCF0_CCB_vect) +{ + if (tc_tcf0_ccb_callback) { + tc_tcf0_ccb_callback(); + } +} + +/** + * \internal + * \brief Interrupt handler for Timer Counter F0 Compare/CaptureC + * + * This function will handle interrupt on Timer Counter F0 Compare/CaptureC and + * call the callback function. + */ +ISR(TCF0_CCC_vect) +{ + if (tc_tcf0_ccc_callback) { + tc_tcf0_ccc_callback(); + } +} + +/** + * \internal + * \brief Interrupt handler for Timer Counter F0 Compare/CaptureD + * + * This function will handle interrupt on Timer Counter F0 Compare/CaptureD and + * call the callback function. + */ +ISR(TCF0_CCD_vect) +{ + if (tc_tcf0_ccd_callback) { + tc_tcf0_ccd_callback(); + } +} + +#endif + +#if defined(TCF1) || defined(__DOXYGEN__) +//! \internal Local storage of Timer Counter TCF1 interrupt callback function +static tc_callback_t tc_tcf1_ovf_callback; +static tc_callback_t tc_tcf1_err_callback; +static tc_callback_t tc_tcf1_cca_callback; +static tc_callback_t tc_tcf1_ccb_callback; + +/** + * \internal + * \brief Interrupt handler for Timer Counter F1 overflow + * + * This function will handle interrupt on Timer Counter F1 overflow and + * call the callback function. + */ +ISR(TCF1_OVF_vect) +{ + if (tc_tcf1_ovf_callback) { + tc_tcf1_ovf_callback(); + } +} + +/** + * \internal + * \brief Interrupt handler for Timer Counter F1 error + * + * This function will handle interrupt on Timer Counter F1 error and + * call the callback function. + */ +ISR(TCF1_ERR_vect) +{ + if (tc_tcf1_err_callback) { + tc_tcf1_err_callback(); + } +} + +/** + * \internal + * \brief Interrupt handler for Timer Counter F1 Compare/CaptureA + * + * This function will handle interrupt on Timer Counter F1 Compare/CaptureA and + * call the callback function. + */ +ISR(TCF1_CCA_vect) +{ + if (tc_tcf1_cca_callback) { + tc_tcf1_cca_callback(); + } +} + +/** + * \internal + * \brief Interrupt handler for Timer Counter F1 Compare/CaptureB + * + * This function will handle interrupt on Timer Counter F1 Compare/CaptureB and + * call the callback function. + */ +ISR(TCF1_CCB_vect) +{ + if (tc_tcf1_ccb_callback) { + tc_tcf1_ccb_callback(); + } +} + +#endif + +/** + * \brief Enable TC + * + * Enables the TC. + * + * \param tc Pointer to TC module + * + * \note + * unmask TC clock (sysclk), but does not configure the TC clock source. + */ +void tc_enable(volatile void *tc) +{ + irqflags_t iflags = cpu_irq_save(); + +#ifdef TCC0 + if ((uintptr_t) tc == (uintptr_t) & TCC0) { + sysclk_enable_module(SYSCLK_PORT_C, SYSCLK_TC0); + sysclk_enable_module(SYSCLK_PORT_C, SYSCLK_HIRES); + } else +#endif +#ifdef TCC1 + if ((uintptr_t) tc == (uintptr_t) & TCC1) { + sysclk_enable_module(SYSCLK_PORT_C, SYSCLK_TC1); + sysclk_enable_module(SYSCLK_PORT_C, SYSCLK_HIRES); + } else +#endif +#ifdef TCD0 + if ((uintptr_t) tc == (uintptr_t) & TCD0) { + sysclk_enable_module(SYSCLK_PORT_D, SYSCLK_TC0); + sysclk_enable_module(SYSCLK_PORT_D, SYSCLK_HIRES); + } else +#endif +#ifdef TCD1 + if ((uintptr_t) tc == (uintptr_t) & TCD1) { + sysclk_enable_module(SYSCLK_PORT_D, SYSCLK_TC1); + sysclk_enable_module(SYSCLK_PORT_D, SYSCLK_HIRES); + } else +#endif +#ifdef TCE0 + if ((uintptr_t) tc == (uintptr_t) & TCE0) { + sysclk_enable_module(SYSCLK_PORT_E, SYSCLK_TC0); + sysclk_enable_module(SYSCLK_PORT_E, SYSCLK_HIRES); + } else +#endif +#ifdef TCE1 + if ((uintptr_t) tc == (uintptr_t) & TCE1) { + sysclk_enable_module(SYSCLK_PORT_E, SYSCLK_TC1); + sysclk_enable_module(SYSCLK_PORT_E, SYSCLK_HIRES); + } else +#endif +#ifdef TCF0 + if ((uintptr_t) tc == (uintptr_t) & TCF0) { + sysclk_enable_module(SYSCLK_PORT_F, SYSCLK_TC0); + sysclk_enable_module(SYSCLK_PORT_F, SYSCLK_HIRES); + } else +#endif +#ifdef TCF1 + if ((uintptr_t) tc == (uintptr_t) & TCF1) { + sysclk_enable_module(SYSCLK_PORT_F, SYSCLK_TC1); + sysclk_enable_module(SYSCLK_PORT_F, SYSCLK_HIRES); + } else +#endif + { + cpu_irq_restore(iflags); + return; + } + sleepmgr_lock_mode(SLEEPMGR_IDLE); + cpu_irq_restore(iflags); +} + + +/** + * \brief Disable TC + * + * Disables the TC. + * + * \param tc Pointer to TC module + * + * \note + * mask TC clock (sysclk). + */ +void tc_disable(volatile void *tc) +{ + irqflags_t iflags = cpu_irq_save(); + + sleepmgr_unlock_mode(SLEEPMGR_IDLE); + +#ifdef TCC0 + if ((uintptr_t) tc == (uintptr_t) & TCC0) { + sysclk_disable_module(SYSCLK_PORT_C, SYSCLK_TC0); + sysclk_disable_module(SYSCLK_PORT_C, SYSCLK_HIRES); + } else +#endif +#ifdef TCC1 + if ((uintptr_t) tc == (uintptr_t) & TCC1) { + sysclk_disable_module(SYSCLK_PORT_C, SYSCLK_TC1); + sysclk_disable_module(SYSCLK_PORT_C, SYSCLK_HIRES); + } else +#endif +#ifdef TCD0 + if ((uintptr_t) tc == (uintptr_t) & TCD0) { + sysclk_disable_module(SYSCLK_PORT_D, SYSCLK_TC0); + sysclk_disable_module(SYSCLK_PORT_D, SYSCLK_HIRES); + } else +#endif +#ifdef TCD1 + if ((uintptr_t) tc == (uintptr_t) & TCD1) { + sysclk_disable_module(SYSCLK_PORT_D, SYSCLK_TC1); + sysclk_disable_module(SYSCLK_PORT_D, SYSCLK_HIRES); + } else +#endif +#ifdef TCE0 + if ((uintptr_t) tc == (uintptr_t) & TCE0) { + sysclk_disable_module(SYSCLK_PORT_E, SYSCLK_TC0); + sysclk_disable_module(SYSCLK_PORT_E, SYSCLK_HIRES); + } else +#endif +#ifdef TCE1 + if ((uintptr_t) tc == (uintptr_t) & TCE1) { + sysclk_disable_module(SYSCLK_PORT_E, SYSCLK_TC1); + sysclk_disable_module(SYSCLK_PORT_E, SYSCLK_HIRES); + } else +#endif +#ifdef TCF0 + if ((uintptr_t) tc == (uintptr_t) & TCF0) { + sysclk_disable_module(SYSCLK_PORT_F, SYSCLK_TC0); + sysclk_disable_module(SYSCLK_PORT_F, SYSCLK_HIRES); + } else +#endif +#ifdef TCF1 + if ((uintptr_t) tc == (uintptr_t) & TCF1) { + sysclk_disable_module(SYSCLK_PORT_F, SYSCLK_TC1); + sysclk_disable_module(SYSCLK_PORT_F, SYSCLK_HIRES); + } else +#endif + { + cpu_irq_restore(iflags); + return; + } + cpu_irq_restore(iflags); +} + +void tc_set_overflow_interrupt_callback(volatile void *tc, + tc_callback_t callback) +{ +#ifdef TCC0 + if ((uintptr_t) tc == (uintptr_t) & TCC0) { + tc_tcc0_ovf_callback = callback; + } else +#endif +#ifdef TCC1 + if ((uintptr_t) tc == (uintptr_t) & TCC1) { + tc_tcc1_ovf_callback = callback; + } else +#endif +#ifdef TCD0 + if ((uintptr_t) tc == (uintptr_t) & TCD0) { + tc_tcd0_ovf_callback = callback; + } else +#endif +#ifdef TCD1 + if ((uintptr_t) tc == (uintptr_t) & TCD1) { + tc_tcd1_ovf_callback = callback; + } else +#endif +#ifdef TCE0 + if ((uintptr_t) tc == (uintptr_t) & TCE0) { + tc_tce0_ovf_callback = callback; + } else +#endif +#ifdef TCE1 + if ((uintptr_t) tc == (uintptr_t) & TCE1) { + tc_tce1_ovf_callback = callback; + } else +#endif +#ifdef TCF0 + if ((uintptr_t) tc == (uintptr_t) & TCF0) { + tc_tcf0_ovf_callback = callback; + } else +#endif +#ifdef TCF1 + if ((uintptr_t) tc == (uintptr_t) & TCF1) { + tc_tcf1_ovf_callback = callback; + } else +#endif + {} +} + +void tc_set_error_interrupt_callback(volatile void *tc, tc_callback_t callback) +{ +#ifdef TCC0 + if ((uintptr_t) tc == (uintptr_t) & TCC0) { + tc_tcc0_err_callback = callback; + } else +#endif +#ifdef TCC1 + if ((uintptr_t) tc == (uintptr_t) & TCC1) { + tc_tcc1_err_callback = callback; + } else +#endif +#ifdef TCD0 + if ((uintptr_t) tc == (uintptr_t) & TCD0) { + tc_tcd0_err_callback = callback; + } else +#endif +#ifdef TCD1 + if ((uintptr_t) tc == (uintptr_t) & TCD1) { + tc_tcd1_err_callback = callback; + } else +#endif +#ifdef TCE0 + if ((uintptr_t) tc == (uintptr_t) & TCE0) { + tc_tce0_err_callback = callback; + } else +#endif +#ifdef TCE1 + if ((uintptr_t) tc == (uintptr_t) & TCE1) { + tc_tce1_err_callback = callback; + } else +#endif +#ifdef TCF0 + if ((uintptr_t) tc == (uintptr_t) & TCF0) { + tc_tcf0_err_callback = callback; + } else +#endif +#ifdef TCF1 + if ((uintptr_t) tc == (uintptr_t) & TCF1) { + tc_tcf1_err_callback = callback; + } else +#endif + {} +} + +void tc_set_cca_interrupt_callback(volatile void *tc, tc_callback_t callback) +{ +#ifdef TCC0 + if ((uintptr_t) tc == (uintptr_t) & TCC0) { + tc_tcc0_cca_callback = callback; + } else +#endif +#ifdef TCC1 + if ((uintptr_t) tc == (uintptr_t) & TCC1) { + tc_tcc1_cca_callback = callback; + } else +#endif +#ifdef TCD0 + if ((uintptr_t) tc == (uintptr_t) & TCD0) { + tc_tcd0_cca_callback = callback; + } else +#endif +#ifdef TCD1 + if ((uintptr_t) tc == (uintptr_t) & TCD1) { + tc_tcd1_cca_callback = callback; + } else +#endif +#ifdef TCE0 + if ((uintptr_t) tc == (uintptr_t) & TCE0) { + tc_tce0_cca_callback = callback; + } else +#endif +#ifdef TCE1 + if ((uintptr_t) tc == (uintptr_t) & TCE1) { + tc_tce1_cca_callback = callback; + } else +#endif +#ifdef TCF0 + if ((uintptr_t) tc == (uintptr_t) & TCF0) { + tc_tcf0_cca_callback = callback; + } else +#endif +#ifdef TCF1 + if ((uintptr_t) tc == (uintptr_t) & TCF1) { + tc_tcf1_cca_callback = callback; + } else +#endif + {} +} + +void tc_set_ccb_interrupt_callback(volatile void *tc, tc_callback_t callback) +{ +#ifdef TCC0 + if ((uintptr_t) tc == (uintptr_t) & TCC0) { + tc_tcc0_ccb_callback = callback; + } else +#endif +#ifdef TCC1 + if ((uintptr_t) tc == (uintptr_t) & TCC1) { + tc_tcc1_ccb_callback = callback; + } else +#endif +#ifdef TCD0 + if ((uintptr_t) tc == (uintptr_t) & TCD0) { + tc_tcd0_ccb_callback = callback; + } else +#endif +#ifdef TCD1 + if ((uintptr_t) tc == (uintptr_t) & TCD1) { + tc_tcd1_ccb_callback = callback; + } else +#endif +#ifdef TCE0 + if ((uintptr_t) tc == (uintptr_t) & TCE0) { + tc_tce0_ccb_callback = callback; + } else +#endif +#ifdef TCE1 + if ((uintptr_t) tc == (uintptr_t) & TCE1) { + tc_tce1_ccb_callback = callback; + } else +#endif +#ifdef TCF0 + if ((uintptr_t) tc == (uintptr_t) & TCF0) { + tc_tcf0_ccb_callback = callback; + } else +#endif +#ifdef TCF1 + if ((uintptr_t) tc == (uintptr_t) & TCF1) { + tc_tcf1_ccb_callback = callback; + } else +#endif + {} +} + +void tc_set_ccc_interrupt_callback(volatile void *tc, tc_callback_t callback) +{ +#ifdef TCC0 + if ((uintptr_t) tc == (uintptr_t) & TCC0) { + tc_tcc0_ccc_callback = callback; + } else +#endif + +#ifdef TCD0 + if ((uintptr_t) tc == (uintptr_t) & TCD0) { + tc_tcd0_ccc_callback = callback; + } else +#endif + +#ifdef TCE0 + if ((uintptr_t) tc == (uintptr_t) & TCE0) { + tc_tce0_ccc_callback = callback; + } else +#endif + +#ifdef TCF0 + if ((uintptr_t) tc == (uintptr_t) & TCF0) { + tc_tcf0_ccc_callback = callback; + } else +#endif + {} + +} + + +void tc_set_ccd_interrupt_callback(volatile void *tc, tc_callback_t callback) +{ +#ifdef TCC0 + if ((uintptr_t) tc == (uintptr_t) & TCC0) { + tc_tcc0_ccd_callback = callback; + } else +#endif + +#ifdef TCD0 + if ((uintptr_t) tc == (uintptr_t) & TCD0) { + tc_tcd0_ccd_callback = callback; + } else +#endif + +#ifdef TCE0 + if ((uintptr_t) tc == (uintptr_t) & TCE0) { + tc_tce0_ccd_callback = callback; + } else +#endif + +#ifdef TCF0 + if ((uintptr_t) tc == (uintptr_t) & TCF0) { + tc_tcf0_ccd_callback = callback; + } else +#endif + {} +} diff --git a/DSTAT1/src/asf/xmega/drivers/tc/tc.h b/DSTAT1/src/asf/xmega/drivers/tc/tc.h new file mode 100644 index 0000000000000000000000000000000000000000..73cf96ce615d5653fdbfc30b0573cf61e02a859b --- /dev/null +++ b/DSTAT1/src/asf/xmega/drivers/tc/tc.h @@ -0,0 +1,1610 @@ +/** + * \file + * + * \brief AVR XMEGA Timer Counter (TC) driver + * + * Copyright (c) 2010-2011 Atmel Corporation. All rights reserved. + * + * \asf_license_start + * + * 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. The name of Atmel may not be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * 4. This software may only be redistributed and used in connection with an + * Atmel microcontroller product. + * + * THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE + * EXPRESSLY AND SPECIFICALLY DISCLAIMED. IN NO EVENT SHALL ATMEL 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. + * + * \asf_license_stop + * + */ +#ifndef TC_H +#define TC_H + +#include +#include +#include "status_codes.h" +#include "pmic.h" +#include +#include + + +#ifdef __cplusplus +extern "C" { +#endif + + + +/** + * \defgroup tc_group Timer Counter (TC) + * + * See \ref xmega_tc_quickstart + * + * This is a driver for the AVR XMEGA Timer Counter (TC). It provides functions + * for enabling, disabling and configuring the TC modules. + * + * \section dependencies Dependencies + * This driver depends on the following modules: + * - \ref sysclk_group for peripheral clock control. + * - \ref sleepmgr_group for setting allowed sleep mode. + * - \ref interrupt_group for ISR definition and disabling interrupts during + * critical code sections. + * @{ + */ + + + +/** + * \brief Interrupt event callback function type + * + * The interrupt handler can be configured to do a function callback, + * the callback function must match the tc_callback_t type. + * + */ +typedef void (*tc_callback_t)(void); + +//! Timer Counter Capture Compare Channel index +enum tc_cc_channel_t { + //! Channel A + TC_CCA = 1, + //! Channel B + TC_CCB = 2, + //! Channel C + TC_CCC = 3, + //! Channel D + TC_CCD = 4, +}; + +//! Timer Counter Capture Compare Channel index +enum tc_cc_channel_mask_enable_t { + //! Channel A Enable mask + TC_CCAEN = TC0_CCAEN_bm, + //! Channel B Enable mask + TC_CCBEN = TC0_CCBEN_bm, + //! Channel C Enable mask + TC_CCCEN = TC0_CCCEN_bm, + //! Channel D Enable mask + TC_CCDEN = TC0_CCDEN_bm, +}; + +//! Timer Counter Direction +enum tc_dir_t { + //! Counting up + TC_UP = 0, + //! Down Coutning B + TC_DOWN = 1 +}; +//! Timer Counter Waveform Generator mode +enum tc_wg_mode_t { + //! TC in normal Mode + TC_WG_NORMAL = TC_WGMODE_NORMAL_gc, + //! TC in Frequency Generator mode + TC_WG_FRQ = TC_WGMODE_FRQ_gc, + //! TC in single slope PWM mode + TC_WG_SS = TC_WGMODE_SS_gc, + //! TC in dual slope Top PWM mode + TC_WG_DS_T = TC_WGMODE_DS_T_gc, + //! TC in dual slope Top Bottom PWM mode + TC_WG_DS_TB = TC_WGMODE_DS_TB_gc, + //! TC in dual slope Bottom PWM mode + TC_WG_DS_B = TC_WGMODE_DS_B_gc +}; + +//! TC interrupt levels +enum TC_INT_LEVEL_t { + TC_INT_LVL_OFF = 0x00, + TC_INT_LVL_LO = 0x01, + TC_INT_LVL_MED = 0x02, + TC_INT_LVL_HI = 0x03, +}; + +//! Macro to check if type of passed TC is TC1_t +#define tc_is_tc1(void) ((uint16_t)tc&0x40 ? true : false) +//! Macro to check if type of passed TC is TC0_t +#define tc_is_tc0(void) ((uint16_t)tc&0x40 ? false : true) + +/** + * \brief Enable TC + * + * Enables the TC. + * + * \param tc Pointer to TC module + * + * \note + * unmask TC clock (sysclk), but does not configure the TC clock source. + */ +void tc_enable(volatile void *tc); + +/** + * \brief Disable TC + * + * Disables the TC. + * + * \param tc Pointer to TC module + * + * \note + * mask TC clock (sysclk). + */ +void tc_disable(volatile void *tc); + +/** + * \ingroup tc_group + * \defgroup tc_interrupt_group Timer Counter (TC) interrupt management + * This group provides functions to configure TC module interrupts + * + * + * @{ + */ +/** + * \brief Set TC overflow interrupt callback function + * + * This function allows the caller to set and change the interrupt callback + * function. Without setting a callback function the interrupt handler in the + * driver will only clear the interrupt flags. + * + * \param tc Pointer to the Timer Counter (TC) base address + * \param callback Reference to a callback function + */ +void tc_set_overflow_interrupt_callback(volatile void *tc, + tc_callback_t callback); + +/** + * \brief Set TC error interrupt callback function + * + * This function allows the caller to set and change the interrupt callback + * function. Without setting a callback function the interrupt handler in the + * driver will only clear the interrupt flags. + * + * \param tc Pointer to the Timer Counter (TC) base address + * \param callback Reference to a callback function + */ +void tc_set_error_interrupt_callback(volatile void *tc, tc_callback_t callback); + +/** + * \brief Set TC Capture Compare Channel A interrupt callback function + * + * This function allows the caller to set and change the interrupt callback + * function. Without setting a callback function the interrupt handler in the + * driver will only clear the interrupt flags. + * + * \param tc Pointer to the Timer Counter (TC) base address + * \param callback Reference to a callback function + */ +void tc_set_cca_interrupt_callback(volatile void *tc, tc_callback_t callback); + +/** + * \brief Set TC Capture Compare Channel B interrupt callback function + * + * This function allows the caller to set and change the interrupt callback + * function. Without setting a callback function the interrupt handler in the + * driver will only clear the interrupt flags. + * + * \param tc Pointer to the Timer Counter (TC) base address + * \param callback Reference to a callback function + */ +void tc_set_ccb_interrupt_callback(volatile void *tc, tc_callback_t callback); + +/** + * \brief Set TC Capture Compare Channel C interrupt callback function + * + * This function allows the caller to set and change the interrupt callback + * function. Without setting a callback function the interrupt handler in the + * driver will only clear the interrupt flags. + * + * \param tc Pointer to the Timer Counter (TC) base address + * \param callback Reference to a callback function + */ +void tc_set_ccc_interrupt_callback(volatile void *tc, tc_callback_t callback); + +/** + * \brief Set TC Capture Compare Channel D interrupt callback function + * + * This function allows the caller to set and change the interrupt callback + * function. Without setting a callback function the interrupt handler in the + * driver will only clear the interrupt flags. + * + * \param tc Pointer to the Timer Counter (TC) base address + * \param callback Reference to a callback function + */ +void tc_set_ccd_interrupt_callback(volatile void *tc, tc_callback_t callback); +/** + * \brief Configures TC overflow Interrupt level + * + * \param tc Pointer to TC module. + * \param level Overflow interrupt level + * \note Configures OVFINTLVL in INTCTRLA + */ +static inline void tc_set_overflow_interrupt_level(volatile void *tc, + enum TC_INT_LEVEL_t level) +{ + ((TC0_t *)tc)->INTCTRLA = ((TC0_t *)tc)->INTCTRLA & ~TC0_OVFINTLVL_gm; + ((TC0_t *)tc)->INTCTRLA = + ((TC0_t *)tc)->INTCTRLA | (level << TC0_OVFINTLVL_gp); +} + +/** + * \brief Configures TC error Interrupt level + * + * \param tc Pointer to TC module. + * \param level Error interrupt level + * \note Configures ERRINTLVL in INTCTRLA + */ +static inline void tc_set_error_interrupt_level(volatile void *tc, + enum TC_INT_LEVEL_t level) +{ + ((TC0_t *)tc)->INTCTRLA = ((TC0_t *)tc)->INTCTRLA & ~TC0_ERRINTLVL_gm; + ((TC0_t *)tc)->INTCTRLA = + ((TC0_t *)tc)->INTCTRLA | (level << TC0_ERRINTLVL_gp); +} + +/** + * \brief Configures TC Capture Compare A Interrupt level + * + * \param tc Pointer to TC module. + * \param level CCA interrupt level + * \note Configures CCAINTLVL in INTCTRLB + */ +static inline void tc_set_cca_interrupt_level(volatile void *tc, + enum TC_INT_LEVEL_t level) +{ + ((TC0_t *)tc)->INTCTRLB = ((TC0_t *)tc)->INTCTRLB & ~TC0_CCAINTLVL_gm; + ((TC0_t *)tc)->INTCTRLB = + ((TC0_t *)tc)->INTCTRLB | (level << TC0_CCAINTLVL_gp); +} + +/** + * \brief Configures TC Capture Compare B Interrupt level + * + * \param tc Pointer to TC module. + * \param level CCB interrupt level + * \note Configures CCBINTLVL in INTCTRLB + */ +static inline void tc_set_ccb_interrupt_level(volatile void *tc, + enum TC_INT_LEVEL_t level) +{ + ((TC0_t *)tc)->INTCTRLB = ((TC0_t *)tc)->INTCTRLB & ~TC0_CCBINTLVL_gm; + ((TC0_t *)tc)->INTCTRLB = + ((TC0_t *)tc)->INTCTRLB | (level << TC0_CCBINTLVL_gp); +} + +/** + * \brief Configures TC Capture Compare C Interrupt level + * + * \param tc Pointer to TC module. + * \param level CCC interrupt level + * \note Configures CCCINTLVL in INTCTRLB + */ +static inline void tc_set_ccc_interrupt_level(volatile void *tc, + enum TC_INT_LEVEL_t level) +{ + ((TC0_t *)tc)->INTCTRLB = ((TC0_t *)tc)->INTCTRLB & ~TC0_CCCINTLVL_gm; + ((TC0_t *)tc)->INTCTRLB = + ((TC0_t *)tc)->INTCTRLB | (level << TC0_CCCINTLVL_gp); +} + + /** + * \brief Configures TC Capture Compare D Interrupt level + * + * \param tc Pointer to TC module. + * \param level CCD interrupt level + * \note Configures CCDINTLVL in INTCTRLB + */ +static inline void tc_set_ccd_interrupt_level(volatile void *tc, + enum TC_INT_LEVEL_t level) +{ + ((TC0_t *)tc)->INTCTRLB = ((TC0_t *)tc)->INTCTRLB & ~TC0_CCDINTLVL_gm; + ((TC0_t *)tc)->INTCTRLB = + ((TC0_t *)tc)->INTCTRLB | (level << TC0_CCDINTLVL_gp); +} + +//@} + +/** + * \brief Configure Timer Clock Source + * + * \param tc Pointer to TC module. + * \param TC_CLKSEL_enum Clock source selection + * \note Configuring the clock starts alos the timer + */ +static inline void tc_write_clock_source(volatile void *tc, + TC_CLKSEL_t TC_CLKSEL_enum) +{ + ((TC0_t *)tc)->CTRLA = + (((TC0_t *)tc)->CTRLA & ~TC0_CLKSEL_gm) | + TC_CLKSEL_enum; +} + +/** + * \brief Read Timer Clock Source + * + * \param tc Pointer to TC module. + * \return TC_CLKSEL_enum Clock source selection + */ +static inline TC_CLKSEL_t tc_read_clock_source(volatile void *tc) +{ + return (TC_CLKSEL_t)(((TC0_t *)tc)->CTRLA & TC0_CLKSEL_gm); +} + +/** + * \brief Select clock for a specified TC and resolution. + * + * This function configures the clock selection, as prescaled CLKper, for a + * specified TC that gives a resolution at least as high as the one specified. + * The resolution of a TC is synonymous with its clock frequency. + * + * \note It is also possible to clock TCs with event channels. This is not + * handled by this implementation. + * + * \param tc ID of TC to get clock selection for. + * \param resolution Desired resolution for the TC in Hz. + */ +static inline void tc_set_resolution(void *tc, uint32_t resolution) +{ + uint32_t tc_clk_rate = sysclk_get_per_hz(); + + if (resolution <= (tc_clk_rate / 1024)) { + tc_write_clock_source(tc, TC_CLKSEL_DIV1024_gc); + } else if (resolution <= (tc_clk_rate / 256)) { + tc_write_clock_source(tc, TC_CLKSEL_DIV256_gc); + } else if (resolution <= (tc_clk_rate / 64)) { + tc_write_clock_source(tc, TC_CLKSEL_DIV64_gc); + } else if (resolution <= (tc_clk_rate / 8)) { + tc_write_clock_source(tc, TC_CLKSEL_DIV8_gc); + } else if (resolution <= (tc_clk_rate / 4)) { + tc_write_clock_source(tc, TC_CLKSEL_DIV4_gc); + } else if (resolution <= (tc_clk_rate / 2)) { + tc_write_clock_source(tc, TC_CLKSEL_DIV2_gc); + } else { + tc_write_clock_source(tc, TC_CLKSEL_DIV1_gc); + } +} + +/** + * \brief Get real resolution for a specified TC. + * + * This function returns the resolution which the specified clock selection + * of TC will result in. The resolution of a TC is synonymous with its clock + * frequency. + * + * \note This function does not handle event channel clock selections. + * + * \param tc Pointer of TC module to get resolution for. + * + * \return The resolution of \a tc. + */ +static inline uint32_t tc_get_resolution(void *tc) +{ + uint32_t tc_clk_rate = sysclk_get_per_hz(); + switch (tc_read_clock_source(tc)) { + case TC_CLKSEL_OFF_gc: + tc_clk_rate = 0; + break; + + case TC_CLKSEL_DIV1024_gc: + tc_clk_rate /= 1024; + break; + + case TC_CLKSEL_DIV256_gc: + tc_clk_rate /= 256; + break; + + case TC_CLKSEL_DIV64_gc: + tc_clk_rate /= 64; + break; + + case TC_CLKSEL_DIV8_gc: + tc_clk_rate /= 8; + break; + + case TC_CLKSEL_DIV4_gc: + tc_clk_rate /= 4; + break; + + case TC_CLKSEL_DIV2_gc: + tc_clk_rate /= 2; + break; + + case TC_CLKSEL_DIV1_gc: + break; + + default: + tc_clk_rate = 0; + break; + } + return (tc_clk_rate); +} + +/** + * \brief Configure Timer Direction + * + * \param tc Pointer to TC module. + * \param dir Timer direction : + */ +static inline void tc_set_direction(volatile void *tc, enum tc_dir_t dir) +{ + if (dir == TC_UP) { + ((TC0_t *)tc)->CTRLFCLR |= ~TC0_DIR_bm; + } else { + ((TC0_t *)tc)->CTRLFSET |= TC0_DIR_bm; + } +} + +/** + * \brief Write the Counter value of the Timer + * + * \param tc Pointer to TC module. + * \param cnt_value Counter value : + */ +static inline void tc_write_count(volatile void *tc, uint16_t cnt_value) +{ + ((TC0_t *)tc)->CNT = cnt_value; +} + +/** + * \brief Reads the Counter value of the Timer + * + * \param tc Pointer to TC module. + * \note Output the Counter value CNT + */ +static inline uint16_t tc_read_count(volatile void *tc) +{ + return (((TC0_t *)tc)->CNT); +} + +/** + * \brief Writes the Period value of the Timer + * + * \param tc Pointer to TC module. + * \param per_value Period value : PER + */ +static inline void tc_write_period(volatile void *tc, uint16_t per_value) +{ + ((TC0_t *)tc)->PER = per_value; +} + +/** + * \brief Reads the Period value of the Timer + * + * \param tc Pointer to TC module. + * \return Period value : PER + */ +static inline uint16_t tc_read_period(volatile void *tc) +{ + return (((TC0_t *)tc)->PER); +} + +/** + * \brief Writes the Period Buffer value of the Timer + * + * \param tc Pointer to TC module. + * \param per_buf Period Buffer value : PERH/PERL + */ +static inline void tc_write_period_buffer(volatile void *tc, uint16_t per_buf) +{ + ((TC0_t *)tc)->PERBUF = per_buf; +} + +/** + * \brief Reads the Period Buffer value of the Timer + * + * \param tc Pointer to TC module. + * \return Period Buffer value : PERH/PERL + */ +static inline uint16_t tc_read_period_buffer(volatile void *tc) +{ + return (((TC0_t *)tc)->PERBUF); +} + +/** + * \brief Tests if the Period Buffer is valid + * + * \param tc Pointer to TC module. + * \return period Buffer is valid or not:PERBV + */ +static inline bool tc_period_buffer_is_valid(volatile void *tc) +{ + return (((TC0_t *)tc)->CTRLGCLR & TC0_PERBV_bm); +} + +/** + * \brief Enables delay (used for 32bit timer mode) + * + * \param tc Pointer to TC module. + * \note enables Delay mode + */ +static inline void tc_enable_delay(volatile void *tc) +{ + ((TC0_t *)tc)->CTRLD = (((TC0_t *)tc)->CTRLD & + ~TC0_EVDLY_bm) | (1 << TC0_EVDLY_bp); +} + +/** + * \brief Disables delay + * + * \param tc Pointer to TC module. + * \note disables Delay mode + */ +static inline void tc_disable_delay(volatile void *tc) +{ + ((TC0_t *)tc)->CTRLD = ((TC0_t *)tc)->CTRLD & ~TC0_EVDLY_bm; +} + +/** + * \brief Tests if the Overflow flag is set + * + * \param tc Pointer to TC module. + * \return overflow has occured or not : OVFIF + */ +static inline bool tc_is_overflow(volatile void *tc) +{ + return (((TC0_t *)tc)->INTFLAGS & TC0_OVFIF_bm); +} + +/** + * \brief Clears the Overflow flag + * + * \param tc Pointer to TC module. + * \note OVFIF is cleared + */ +static inline void tc_clear_overflow(volatile void *tc) +{ + ((TC0_t *)tc)->INTFLAGS |= TC0_OVFIF_bm; +} + +/** + * \brief Tests if the Error flag is set + * + * \param tc Pointer to TC module. + * \return Error has occured or not : ERRIF + */ +static inline bool tc_read_error(volatile void *tc) +{ + return (((TC0_t *)tc)->INTFLAGS & TC0_ERRIF_bm); +} + +/** + * \brief Clears the Error flag + * + * \param tc Pointer to TC module. + * \note ERRIF is cleared + */ +static inline void tc_clear_error(volatile void *tc) +{ + ((TC0_t *)tc)->INTFLAGS |= TC0_ERRIF_bm; +} + +/** + * \brief Restart the Timer + * + * \param tc Pointer to TC module. + * \note CMD[3] in CTRLFSET is set to 1 and CMD[2] in CTRLFCLR is set + */ +static inline void tc_restart(volatile void *tc) +{ + ((TC0_t *)tc)->CTRLFSET = TC_CMD_RESTART_gc; +} + +/** + * \brief Reset the Timer + * + * \param tc Pointer to TC module. + * \note CMD[3:2] in CTRLFSET are set to 1 + */ +static inline void tc_reset(volatile void *tc) +{ + ((TC0_t *)tc)->CTRLFSET = TC_CMD_RESET_gc; +} + +/** + * \brief Update the Timer + * + * \param tc Pointer to TC module. + * \note CMD[2] in CTRLFSET is set to 1 and CMD[3] in CTRLFCLR is set + */ +static inline void tc_update(volatile void *tc) +{ + ((TC0_t *)tc)->CTRLFSET = TC_CMD_UPDATE_gc; +} + +/** + * \brief Configures the Timer in Byte mode + * + * \param tc Pointer to TC module. + * \note Configures BYTEM in CTRLE + */ +static inline void tc_set_8bits_mode(volatile void *tc) +{ +#ifdef TC0_BYTEM0_bm + ((TC0_t *)tc)->CTRLE |= TC0_BYTEM0_bm; +#else + ((TC0_t *)tc)->CTRLE |= TC0_BYTEM_bm; +#endif +} + +/** + * \brief Locks the Update of the Buffered registers + * + * \param tc Pointer to TC module. + * + * */ +static inline void tc_lock_update_buffers(volatile void *tc) +{ + ((TC0_t *)tc)->CTRLFSET |= TC0_LUPD_bm; +} + +/** + * \brief Unlocks the Update of the Buffered registers + * + * \param tc Pointer to TC module. + * \note Configures LUPD in CTRLFCLR + */ +static inline void tc_unlock_update_buffers(volatile void *tc) +{ + ((TC0_t *)tc)->CTRLFCLR |= TC0_LUPD_bm; +} + +/** + * \brief Enables Compare/Capture channel + * + * \param tc Pointer to TC module. + * \param enablemask CC channel + */ +static inline void tc_enable_cc_channels(volatile void *tc, + enum tc_cc_channel_mask_enable_t enablemask) +{ + if (tc_is_tc0(void *tc)) { + ((TC0_t *)tc)->CTRLB |= enablemask; + } else if (tc_is_tc1(void *tc)) { + ((TC1_t *)tc)->CTRLB |= + enablemask & (TC1_CCAEN_bm | TC1_CCBEN_bm); + } +} + +/** + * \brief Disables Compare/Capture channel + * + * \param tc Pointer to TC module. + * \param disablemask CC channel + */ +static inline void tc_disable_cc_channels(volatile void *tc, + enum tc_cc_channel_mask_enable_t disablemask) +{ + if (tc_is_tc0(void *tc)) { + ((TC0_t *)tc)->CTRLB &= ~disablemask; + } else if (tc_is_tc1(void *tc)) { + ((TC1_t *)tc)->CTRLB &= + ~(disablemask & TC0_CCAEN_bm & TC0_CCBEN_bm); + } +} + +/** + * \brief Enables Input capture mode + * + * \param tc Pointer to TC module. + * \param eventsource Source for the capture + * \param eventaction Event action capture type + */ +static inline void tc_set_input_capture(volatile void *tc, + TC_EVSEL_t eventsource, TC_EVACT_t eventaction) +{ + ((TC0_t *)tc)->CTRLD &= ~(TC0_EVSEL_gm | TC0_EVACT_gm); + ((TC0_t *)tc)->CTRLD |= (eventsource | eventaction); +} + +/** + * \brief Reads the Capture value + * + * \param tc Pointer to TC module. + * \param channel_index Channel x + * \return Read value of CCx + */ +static inline uint16_t tc_read_cc(volatile void *tc, + enum tc_cc_channel_t channel_index) +{ + if (tc_is_tc0(void *tc)) { + switch (channel_index) { + case TC_CCA: + return (((TC0_t *)tc)->CCA); + case TC_CCB: + return (((TC0_t *)tc)->CCB); + case TC_CCC: + return (((TC0_t *)tc)->CCC); + case TC_CCD: + return (((TC0_t *)tc)->CCD); + } + } else if (tc_is_tc1(void *tc)) { + switch (channel_index) { + case TC_CCA: + return (((TC1_t *)tc)->CCA); + case TC_CCB: + return (((TC1_t *)tc)->CCB); + default: + return (0); + } + } + return (0); +} + +/** + * \brief Writes the CC value + * + * \param tc Pointer to TC module. + * \param channel_index CC Channel + * \param value Counter value + */ +static inline void tc_write_cc(volatile void *tc, + enum tc_cc_channel_t channel_index, uint16_t value) +{ + if (tc_is_tc0(void *tc)) { + switch (channel_index) { + case TC_CCA: + ((TC0_t *)tc)->CCA = value; + break; + case TC_CCB: + ((TC0_t *)tc)->CCB = value; + break; + case TC_CCC: + ((TC0_t *)tc)->CCC = value; + break; + case TC_CCD: + ((TC0_t *)tc)->CCD = value; + break; + } + } else if (tc_is_tc1(void *tc)) { + switch (channel_index) { + case TC_CCA: + ((TC1_t *)tc)->CCA = value; + break; + case TC_CCB: + ((TC1_t *)tc)->CCB = value; + break; + default: + return ; + } + } +} + +/** + * \brief Writes the Capture/Compare Buffer value + * + * \param tc Pointer to TC module. + * \param channel_index CC Channel + * \param buffer_value Counter Buffer value + */ +static inline void tc_write_cc_buffer(volatile void *tc, + enum tc_cc_channel_t channel_index, uint16_t buffer_value) +{ + if (tc_is_tc0(void *tc)) { + switch (channel_index) { + case TC_CCA: + ((TC0_t *)tc)->CCABUF = buffer_value; + break; + case TC_CCB: + ((TC0_t *)tc)->CCBBUF = buffer_value; + break; + case TC_CCC: + ((TC0_t *)tc)->CCCBUF = buffer_value; + break; + case TC_CCD: + ((TC0_t *)tc)->CCDBUF = buffer_value; + break; + } + } else if (tc_is_tc1(void *tc)) { + switch (channel_index) { + case TC_CCA: + ((TC1_t *)tc)->CCABUF = buffer_value; + break; + case TC_CCB: + ((TC1_t *)tc)->CCBBUF = buffer_value; + break; + default: + return; + } + } +} + +/** + * \brief Reads the Capture/Compare Buffer value + * + * \param tc Pointer to TC module. + * \param channel_index CC Channel + * \return CCx Buffer value + */ +static inline uint16_t tc_read_cc_buffer(volatile void *tc, + enum tc_cc_channel_t channel_index) +{ + if (tc_is_tc0(void *tc)) { + switch (channel_index) { + case TC_CCA: + return (((TC0_t *)tc)->CCABUF); + case TC_CCB: + return (((TC0_t *)tc)->CCBBUF); + case TC_CCC: + return (((TC0_t *)tc)->CCCBUF); + case TC_CCD: + return (((TC0_t *)tc)->CCDBUF); + } + } else if (tc_is_tc1(void *tc)) { + switch (channel_index) { + case TC_CCA: + return (((TC1_t *)tc)->CCABUF); + case TC_CCB: + return (((TC1_t *)tc)->CCBBUF); + default: + return (0); + } + } + return (0); +} + +/** + * \brief Reports is Capture/Compare Buffer is valid + * + * \param tc Pointer to TC module. + * \param channel_index CC Channel + * \return CCx Buffer is valid or not + */ +static inline bool tc_cc_buffer_is_valid(volatile void *tc, + enum tc_cc_channel_t channel_index) +{ + if (tc_is_tc0(void *tc)) { + switch (channel_index) { + case TC_CCA: + return ((TC0_t *)tc)->CTRLGCLR & TC0_CCABV_bm; + case TC_CCB: + return ((TC0_t *)tc)->CTRLGCLR & TC0_CCBBV_bm; + case TC_CCC: + return ((TC0_t *)tc)->CTRLGCLR & TC0_CCCBV_bm; + case TC_CCD: + return ((TC0_t *)tc)->CTRLGCLR & TC0_CCDBV_bm; + } + } else if (tc_is_tc1(void *tc)) { + switch (channel_index) { + case TC_CCA: + return (((TC1_t *)tc)->CTRLGCLR & + TC1_CCABV_bm); + case TC_CCB: + return (((TC1_t *)tc)->CTRLGCLR & + TC1_CCBBV_bm); + default: + return (0); + } + } + return (0); +} + +/** + * \brief Reports if Capture/Compare interrupt has occured + * + * \param tc Pointer to TC module. + * \param channel_index CC Channel + * \return CCx Interrupt or not + */ +static inline bool tc_is_cc_interrupt(volatile void *tc, + enum tc_cc_channel_t channel_index) +{ + if (tc_is_tc0(void *tc)) { + switch (channel_index) { + case TC_CCA: + return (((TC0_t *)tc)->INTFLAGS & TC0_CCAIF_bm); + case TC_CCB: + return (((TC0_t *)tc)->INTFLAGS & TC0_CCBIF_bm); + case TC_CCC: + return (((TC0_t *)tc)->INTFLAGS & TC0_CCCIF_bm); + case TC_CCD: + return (((TC0_t *)tc)->INTFLAGS & TC0_CCDIF_bm); + } + } else if (tc_is_tc1(void *tc)) { + switch (channel_index) { + case TC_CCA: + return (((TC1_t *)tc)->INTFLAGS & + TC1_CCAIF_bm); + case TC_CCB: + return (((TC1_t *)tc)->INTFLAGS & + TC1_CCBIF_bm); + default: + return (0); + } + } + return (0); +} + +/** + * \brief Clears Capture/Compare interrupt + * + * \param tc Pointer to TC module. + * \param channel_index CC Channel + */ +static inline void tc_clear_cc_interrupt(volatile void *tc, + enum tc_cc_channel_t channel_index) +{ + if (tc_is_tc0(void *tc)) { + switch (channel_index) { + case TC_CCA: + ((TC0_t *)tc)->INTFLAGS = TC0_CCAIF_bm; + break; + case TC_CCB: + ((TC0_t *)tc)->INTFLAGS = TC0_CCBIF_bm; + break; + case TC_CCC: + ((TC0_t *)tc)->INTFLAGS = TC0_CCCIF_bm; + break; + case TC_CCD: + ((TC0_t *)tc)->INTFLAGS = TC0_CCDIF_bm; + break; + } + } else if (tc_is_tc1(void *tc)) { + switch (channel_index) { + case TC_CCA: + ((TC1_t *)tc)->INTFLAGS = TC1_CCAIF_bm; + break; + case TC_CCB: + ((TC1_t *)tc)->INTFLAGS = TC1_CCBIF_bm; + break; + default: + return; + } + } +} + +/** + * \brief Configures TC in the specified Waveform generator mode + * + * \param tc Pointer to TC module. + * \param wgm : waveform generator + */ +static inline void tc_set_wgm(volatile void *tc, enum tc_wg_mode_t wgm) +{ + ((TC0_t *)tc)->CTRLB = (((TC0_t *)tc)->CTRLB & ~TC0_WGMODE_gm) | wgm; +} + +/** + * \ingroup tc_group + * \defgroup tc_awex_group AWeX extension driver + * This group provides low level drivers to configure AWeX extension + * @{ + */ + +/** + * \brief AWeX extension enable + * + * \param awex Pointer to AWeX module (AWEXC or AWEXE) + */ +static inline void tc_awex_enable_cwcm(AWEX_t *awex) +{ + ((AWEX_t *)awex)->CTRL |= AWEX_CWCM_bm; +} + +/** + * \brief AWeX extension disable Common waveform mode + * + * \param awex Pointer to AWeX module (AWEXC or AWEXE) + */ +static inline void tc_awex_disable_cwcm(AWEX_t *awex) +{ + ((AWEX_t *)awex)->CTRL &= ~AWEX_CWCM_bm; +} + +/** + * \brief AWeX extension ensable pattern generator mode + * + * \param awex Pointer to AWeX module (AWEXC or AWEXE) + */ +static inline void tc_awex_enable_pgm(AWEX_t *awex) +{ + ((AWEX_t *)awex)->CTRL |= AWEX_PGM_bm; +} + +/** + * \brief AWeX extension dissable pattern generator mode + * + * \param awex Pointer to AWeX module (AWEXC or AWEXE) + */ +static inline void tc_awex_disable_pgm(AWEX_t *awex) +{ + ((AWEX_t *)awex)->CTRL &= ~AWEX_PGM_bm; +} + +/** + * \brief AWeX extension : enable Deadtime insertion on ccA + * + * \param awex Pointer to AWeX module (AWEXC or AWEXE) + */ +static inline void tc_awex_enable_cca_deadtime(AWEX_t *awex) +{ + ((AWEX_t *)awex)->CTRL |= AWEX_DTICCAEN_bm; +} + +/** + * \brief AWeX extension : disable Deadtime insertion on ccA + * + * \param awex Pointer to AWeX module (AWEXC or AWEXE) + */ +static inline void tc_awex_disable_cca_deadtime(AWEX_t *awex) +{ + ((AWEX_t *)awex)->CTRL &= ~AWEX_DTICCAEN_bm; +} + +/** + * \brief AWeX extension : enable Deadtime insertion on ccB + * + * \param awex Pointer to AWeX module (AWEXC or AWEXE) + */ +static inline void tc_awex_enable_ccb_deadtime(AWEX_t *awex) +{ + ((AWEX_t *)awex)->CTRL |= AWEX_DTICCBEN_bm; +} + +/** + * \brief AWeX extension : disable Deadtime insertion on ccB + * + * \param awex Pointer to AWeX module (AWEXC or AWEXE) + */ +static inline void tc_awex_disable_ccb_deadtime(AWEX_t *awex) +{ + ((AWEX_t *)awex)->CTRL &= ~AWEX_DTICCBEN_bm; +} + +/** + * \brief AWeX extension : enable Deadtime insertion on ccC + * + * \param awex Pointer to AWeX module (AWEXC or AWEXE) + */ +static inline void tc_awex_enable_ccc_deadtime(AWEX_t *awex) +{ + ((AWEX_t *)awex)->CTRL |= AWEX_DTICCCEN_bm; +} + +/** + * \brief AWeX extension : disable Deadtime insertion on ccD + * + * \param awex Pointer to AWeX module (AWEXC or AWEXE) + */ +static inline void tc_awex_disable_ccc_deadtime(AWEX_t *awex) +{ + ((AWEX_t *)awex)->CTRL &= ~AWEX_DTICCCEN_bm; +} + +/** + * \brief AWeX extension : enable Deadtime insertion on ccD + * + * \param awex Pointer to AWeX module (AWEXC or AWEXE) + */ +static inline void tc_awex_enable_ccd_deadtime(AWEX_t *awex) +{ + ((AWEX_t *)awex)->CTRL |= AWEX_DTICCDEN_bm; +} + +/** + * \brief AWeX extension : disable Deadtime insertion on ccD + * + * \param awex Pointer to AWeX module (AWEXC or AWEXE) + */ +static inline void tc_awex_disable_ccd_deadtime(AWEX_t *awex) +{ + ((AWEX_t *)awex)->CTRL &= ~AWEX_DTICCDEN_bm; +} +/** + * \brief AWeX extension : configures high side deadtime + * + * \param awex Pointer to AWeX module (AWEXC or AWEXE) + * \param value : deadtime value + */ +static inline void tc_awex_set_dti_high(AWEX_t *awex, int16_t value) +{ + ((AWEX_t *)awex)->DTHS = value; +} +/** + * \brief AWeX extension : configures low side deadtime + * + * \param awex Pointer to AWeX module (AWEXC or AWEXE) + * \param value : deadtime value + */ +static inline void tc_awex_set_dti_low(AWEX_t *awex, int16_t value) +{ + ((AWEX_t *)awex)->DTLS = value; +} +/** + * \brief AWeX extension : configures symetrical deadtime + * + * \param awex Pointer to AWeX module (AWEXC or AWEXE) + * \param value : deadtime value + */ +static inline void tc_awex_set_dti_both(AWEX_t *awex, int16_t value) +{ + ((AWEX_t *)awex)->DTBOTH = value; +} + +/** + * \brief AWeX extension : configures symetrical deadtime buffer + * + * \param awex Pointer to AWeX module (AWEXC or AWEXE) + * \param value : deadtime buffer value + */ +static inline void tc_awex_set_dti_both_buffer(AWEX_t *awex, + int16_t value) +{ + ((AWEX_t *)awex)->DTBOTHBUF = value; +} + +/** + * \brief AWeX extension : returns the deadtime buffer high nibble + * + * \param awex Pointer to AWeX module (AWEXC or AWEXE) + * \return Dead Time High value + */ +static inline int8_t tc_awex_get_dti_high_buffer(AWEX_t *awex) +{ + return (((AWEX_t *)awex)->DTHSBUF); +} + +/** + * \brief AWeX extension : returns the deadtime buffer low nibble + * + * \param awex Pointer to AWeX module (AWEXC or AWEXE) + * \return Dead Time High value + */ +static inline int8_t tc_awex_get_dti_low_buffer(AWEX_t *awex) +{ + return (((AWEX_t *)awex)->DTLSBUF); +} + +/** + * \brief AWeX extension : returns if DTI high buffer is valid + * + * \param awex Pointer to AWeX module (AWEXC or AWEXE) + * \return Dead Time High Buffer valid or not + */ +static inline bool tc_awex_is_dti_high_buffer_valid(AWEX_t *awex) +{ + return (((AWEX_t *)awex)->STATUS & AWEX_DTHSBUFV_bm); +} + +/** + * \brief AWeX extension : returns if DTI low buffer is valid + * + * \param awex Pointer to AWeX module (AWEXC or AWEXE) + * \return Dead Time Low Buffer is valid or not + */ +static inline bool tc_awex_is_dti_low_buffer_valid(AWEX_t *awex) +{ + return (((AWEX_t *)awex)->STATUS & AWEX_DTLSBUFV_bm); +} + +/** + * \brief AWeX extension : configures the Fault restart in latched mode + * + * \param awex Pointer to AWeX module (AWEXC or AWEXE) + */ +static inline void tc_awex_fdmode_restart_latched(AWEX_t *awex) +{ + ((AWEX_t *)awex)->FDCTRL &= ~AWEX_FDMODE_bm; +} + +/** + * \brief AWeX extension : configures the Fault restart in cycle to cycle mode + * + * \param awex Pointer to AWeX module (AWEXC or AWEXE) + */ +static inline void tc_awex_fdmode_restart_cycle(AWEX_t *awex) +{ + ((AWEX_t *)awex)->FDCTRL |= AWEX_FDMODE_bm; +} + +/** + * \brief AWeX extension : returns if fault is detected + * + * \param awex Pointer to AWeX module (AWEXC or AWEXE) + */ +static inline bool tc_awex_fault_is_detected(AWEX_t *awex) +{ + return (((AWEX_t *)awex)->STATUS & AWEX_FDF_bm); +} + +/** + * \brief AWeX extension : clears the Fault detection + * + * \param awex Pointer to AWeX module (AWEXC or AWEXE) + */ +static inline void tc_awex_clear_fault(AWEX_t *awex) +{ + ((AWEX_t *)awex)->STATUS = AWEX_FDF_bm; +} + +/** + * \brief AWeX extension : configures fault action + * + * \param awex Pointer to AWeX module (AWEXC or AWEXE) + * \param fd_act Fault action + */ +static inline void tc_awex_set_fault_detection_action(AWEX_t * + awex, AWEX_FDACT_t fd_act) +{ + ((AWEX_t *)awex)->FDCTRL = (((AWEX_t *)awex)->FDCTRL & ~AWEX_FDACT_gm) | + (fd_act & AWEX_FDACT_gm); + +} + +/** + * \brief AWeX extension : configures fault detection event + * + * \param awex Pointer to AWeX module (AWEXC or AWEXE) + * \param eventmask Fault detection event + */ +static inline void tc_awex_set_fault_detection_event(AWEX_t *awex, + int8_t eventmask) +{ + ((AWEX_t *)awex)->FDEMASK = eventmask; +} + +/** + * \brief AWeX extension : configures the port overdrive + * + * \param awex Pointer to AWeX module (AWEXC or AWEXE) + * \param value Output everride configuration + */ +static inline void tc_awex_set_output_override(AWEX_t * awex, + int8_t value) +{ + ((AWEX_t *)awex)->OUTOVEN = value; +} + +/** + * \brief AWeX extension : enable fault detection on debug break detection + * + * \param awex Pointer to AWeX module (AWEXC or AWEXE) + */ +static inline void tc_awex_enable_fault_debug_break(AWEX_t *awex) +{ + ((AWEX_t *)awex)->FDCTRL &= ~AWEX_FDDBD_bm; +} + +/** + * \brief AWeX extension : disable fault detection on debug break detection + * + * \param awex Pointer to AWeX module (AWEXC or AWEXE) + */ +static inline void tc_awex_disable_fault_debug_break(AWEX_t *awex) +{ + ((AWEX_t *)awex)->FDCTRL |= AWEX_FDDBD_bm; +} +//@} +/** + * \ingroup tc_group + * \defgroup tc_hires_group Hi-Res extension driver + * This group provides low level drivers to configure Hi-Res extension + * @{ + */ + +/** + * \brief Hi-Res Extension : configures the Hi-Res + * + * \param hires Pointer to AWeX module (AWEXC or AWEXE) + * \param hi_res_mode HIRES configuration + */ +static inline void tc_hires_set_mode(HIRES_t * hires, HIRES_HREN_t hi_res_mode) +{ + ((HIRES_t *)hires)->CTRLA = hi_res_mode; +} +//@} + +/** @} */ + + +#ifdef __cplusplus +} +#endif + +/** + * \page xmega_tc_quickstart Quick Start Guide for the XMEGA TC Driver + * + * This is the quick start guide for the \ref tc_group , with step-by-step + * instructions on how to configure and use the driver for a specific use case. + * The code examples can be copied into e.g the main application loop or any + * other function that will need to control the timer/counters. + * + * + * \section xmega_tc_qs_use_cases Use cases + * - \ref xmega_tc_qs_ovf + * - \ref xmega_tc_qs_cc + * - \ref xmega_tc_qs_pwm + * + * + * \section xmega_tc_qs_ovf Timer/counter overflow (interrupt based) + * + * This use case will prepare a timer to trigger a interrupt when the timer + * overflows. The interrupt is handled by a cutomizable call back function. + * + * We will setup the timer in this mode: + * - Normal WGM mode (incrementing timer) + * - Use the system clock as clock source + * - No prescaling (DIV = 1) + * - Overflow interrupt after 1000 counts. This will be done by setting the top + * value to 1000. + * + * + * \section xmega_tc_qs_ovf_setup Setup steps + * + * \subsection xmega_tc_qs_ovf_usage_prereq Prequisites + * + * For the setup code of this use case to work, the following must + * be added to the project: + * - \ref interrupt_group + * - \ref clk_group + * + * \subsection xmega_tc_qs_ovf_setup_code Example code + * + * Add a callback function that will be executed when the overflow interrupt + * trigger. + * \code + * static void my_callback(void) + * { + * ...Add your code here. This code will be executed when the overflow occur... + * } + * \endcode + * Add to, e.g., the main loop in the application C-file: + * \code + * pmic_init(); + * sysclk_init(); + * tc_enable(&TCC0); + * tc_set_overflow_interrupt_callback(&TCC0, my_callback); + * tc_set_wgm(&TCC0, TC_WG_NORMAL); + * tc_write_period(&TCC0, 1000); + * tc_set_overflow_interrupt_level(&TCC0, TC_INT_LVL_LO); + * cpu_irq_enable(); + * tc_write_clock_source(&TCC0, TC_CLKSEL_DIV1_gc); + * \endcode + * + * \subsection xmega_tc_qs_ovf_setup_code_workflow Workflow + * + * -# Enable the interrupt controller: + * - \code pmic_init(); \endcode + * -# Enable the clock system: + * - \code sysclk_init(); \endcode + * -# Enable timer/counter TCC0 + * - \code tc_enable(&TCC0); \endcode + * - \note This will enable the clock system for the module + * -# Set the callback function for overflow interrupt + * - \code tc_set_overflow_interrupt_callback(&TCC0, my_callback); \endcode + * - \warning This function requires that the my_callback function is defined + * -# Set the desired waveform mode + * - \code tc_set_wgm(&TCC0, TC_WG_NORMAL); \endcode + * - \note In this case, we use normal mode where the timer increments it + count value until the TOP value is reached. The timer then reset + its count value to 0. + * -# Set the period + * - \code tc_write_period(&TCC0, 1000); \endcode + * - \note This will specify the TOP value of the counter. The timer will + * overflow and reset when this value is reached. + * -# Set the overflow interrupt level + * - \code tc_set_overflow_interrupt_level(&TCC0, TC_INT_LVL_LO); \endcode + * -# Enable interrupts: + * - \code cpu_irq_enable(); \endcode + * -# Set the clock source + * - \code tc_write_clock_source(&TCC0, TC_CLKSEL_DIV1_gc); \endcode + * - \warning When the clock source is set, the timer will start counting + * + * \section xmega_tc_qs_ovf_usage Usage steps + * + * - None. The timer will run in the background, and the code written in the + * call back function will execute each time the timer overflows. + * + * + * \section xmega_tc_qs_cc Timer/counter compare match (interrupt based) + * + * This use case will prepare a timer to trigger two independent interrupts + * when it reaches two different compare values. The period of the timer + * is customizable and the two compare matches will be handled by two separate + * interrupts implemented in call back functions. + * + * We will setup the timer in this mode: + * - Normal WGM mode - incrementing timer + * - Use the system clock as clock source + * - No prescaling (DIV = 1) + * - Period of timer 10000 counts + * - Compare match A interrupt trigger after 100 counts + * - Compare match B interrupt trigger after 1000 counts + * - If compare A and compare B match occur simulatneously, compare B + * should have higher priority + * + * + * \section xmega_tc_qs_cc_setup Setup steps + * + * \subsection xmega_tc_qs_cc_usage_prereq Prequisites + * For the setup code of this use case to work, the following must + * be added to the project: + * - \ref interrupt_group + * - \ref clk_group + * + * \subsection xmega_tc_qs_cc_setup_code Example code + * + * Add two callback functions that will be executed when compare match A and + * compare match B occurs + * \code + * static void my_cca_callback(void) + * { + * ...Add your code here. This code will be executed when a compare match + * occur on channel A... + * } + * static void my_ccb_callback(void) + * { + * ...Add your code here. This code will be executed when a compare match + * occur on channel B... + * } + * \endcode + * Add to, e.g., the main loop in the application C-file: + * \code + * pmic_init(); + * sysclk_init(); + * cpu_irq_enable(); + * tc_enable(&TCC0); + * tc_set_cca_interrupt_callback(&TCC0, my_cca_callback); + * tc_set_ccb_interrupt_callback(&TCC0, my_ccb_callback); + * tc_set_wgm(&TCC0, TC_WG_NORMAL); + * tc_write_period(&TCC0, 10000); + * tc_write_cc(&TCC0, TC_CCA, 100); + * tc_write_cc(&TCC0, TC_CCB, 1000); + * tc_enable_cc_channels(&TCC0,(TC_CCAEN | TC_CCBEN)); + * tc_set_cca_interrupt_level(&TCC0, TC_INT_LVL_LO); + * tc_set_ccb_interrupt_level(&TCC0, TC_INT_LVL_MED); + * tc_write_clock_source(&TCC0, TC_CLKSEL_DIV1_gc); + * \endcode + * + * \subsection xmega_tc_qs_cc_setup_code_workflow Workflow + * + * -# Enable the interrupt controller: + * - \code pmic_init(); \endcode + * -# Enable the clock system: + * - \code sysclk_init(); \endcode + * -# Enable interrupts: + * - \code cpu_irq_enable(); \endcode + * -# Enable timer/counter TCC0 + * - \code tc_enable(&TCC0); \endcode + * - \note This will enable the clock system for the module + * -# Set call back function for CCA interrupt + * - \code tc_set_cca_interrupt_callback(&TCC0, my_cca_callback); \endcode + * - \warning This function requires that the call back function is defined + * -# Set call back function for CCB interrupt + * - \code tc_set_ccb_interrupt_callback(&TCC0, my_ccb_callback); \endcode + * - \warning This function requires that the call back function is defined + * -# Set the desired waveform mode + * - \code tc_set_wgm(&TCC0, TC_WG_NORMAL); \endcode + * - \note In this case, we use normal mode where the timer increments it + count value until the TOP value is reached. The timer then reset + its count value to 0. + * -# Set the period + * - \code tc_write_period(&TCC0, 10000); \endcode + * - \note This will specify the TOP value of the counter. The timer will + * overflow and reset when this value is reached. + * -# Set compare match value on CCA + * - \code tc_write_cc(&TCC0, TC_CCA, 100); \endcode + * -# Set compare match value on CCB + * - \code tc_write_cc(&TCC0, TC_CCB, 1000); \endcode + * -# Enable compare channel A and compare channel B + * -\code tc_enable_cc_channels(&TCC0, (TC_CCAEN | TC_CCBEN)); \endcode + * -# Set interrupt level on channel A (low priority, see \ref TC_INT_LEVEL_t) + * - \code tc_set_cca_interrupt_level(&TCC0, TC_INT_LVL_LO); \endcode + * -# Set interrupt level on channel B (medium priority \ref TC_INT_LEVEL_t) + * - \code tc_set_ccb_interrupt_level(&TCC0, TC_INT_LVL_MED); \endcode + * -# Set the clock source + * - \code tc_write_clock_source(&TCC0, TC_CLKSEL_DIV1_gc); \endcode + * - \warning When the clock source is set, the timer will start counting + * + * \section xmega_tc_qs_cc_usage Usage steps + * + * - None. The timer will run in the background, and the code written in the + * call back functions will execute each time a compare match occur. + * + * + * \section xmega_tc_qs_pwm Timer/counter PWM + * + * This use case will setup a timer in PWM mode. For more details you can + * also look at the XMEGA PWM service. + * + * We will setup the timer in this mode: + * - Normal WGM mode - incrementing timer + * - Use the 2MHz oscillator as clock source (default) + * - 1Hz PWM frequency (2MHz clock, 1024x prescale, TOP value 1950) + * - 10% duty cycle (1:10 ratio between PER and CC register) + * - Output the PWM signal to a I/O port + * + * \section xmega_tc_qs_pwm_setup Setup steps + * + * \subsection xmega_tc_qs_pwm_usage_prereq Prequisites + * For the setup code of this use case to work, the following must + * be added to the project: + * - \ref clk_group + * + * \subsection xmega_tc_qs_pwm_setup_code Example code + * + * Add to, e.g., the main loop in the application C-file: + * \code + * board_init(); + * sysclk_init(); + * tc_enable(&TCE0); + * tc_set_wgm(&TCE0, TC_WG_SS); + * tc_write_period(&TCE0, 1950); + * tc_write_cc(&TCE0, TC_CCA, 195); + * tc_enable_cc_channels(&TCE0,TC_CCAEN); + * tc_write_clock_source(&TCE0, TC_CLKSEL_DIV1024_gc); + * \endcode + * + * \subsection xmega_tc_qs_pwm_setup_code_workflow Workflow + * + * -# Ensure that PWM I/O pin is configured as output + * - \code board_init(); \endcode + * \note The board_init(); function configures the I/O pins. If this function + * is not executed, the I/O pin must be configured as output manually + * -# Enable the clock system: + * - \code sysclk_init(); \endcode + * -# Enable timer/counter TCE0 + * - \code tc_enable(&TCE0); \endcode + * - \note This will enable the clock system for the module + * -# Set the desired waveform mode + * - \code tc_set_wgm(&TCE0, TC_WG_NORMAL); \endcode + * - \note In this case, we use normal mode where the timer increments it + * count value until the TOP value is reached. The timer then reset + * its count value to 0. + * -# Set the period + * - \code tc_write_period(&TCE0, 1950); \endcode + * - \note This will specify the TOP value of the counter. The timer will + * overflow and reset when this value is reached. + * -# Set compare match value on CCA + * - \code tc_write_cc(&TCC0, TC_CCA, 195); \endcode + * - \note The PWM duty cycle will be the ratio between PER and CCA, which + * is set by the tc_write_period() and tc_write_cc() functions. Use + * tc_write_cc() to change duty cycle run time (e.g to dim a LED). + * When CCA = 0, the duty cycle will be 0%. When CCA = PER (top value) + * the duty cycle will be 100%. + * -# Enable compare channel A + * -\code tc_enable_cc_channels(&TCE0,TC_CCAEN); \endcode + * -# Set the clock source + * - \code tc_write_clock_source(&TCE0, TC_CLKSEL_DIV1024_gc); \endcode + * - \warning When the clock source is set, the timer will start counting + * + * \section xmega_tc_qs_pwm_usage Usage steps + * - Use tc_write_cc() to change the duty cycle of the PWM signal + * - Use tc_write_period() to change the PWM frequency + */ + +#endif /* TC_H */ diff --git a/DSTAT1/src/asf/xmega/drivers/usb/usb_device.c b/DSTAT1/src/asf/xmega/drivers/usb/usb_device.c new file mode 100644 index 0000000000000000000000000000000000000000..0f96e56814e8e6245fe21299b57396dcdb3daa48 --- /dev/null +++ b/DSTAT1/src/asf/xmega/drivers/usb/usb_device.c @@ -0,0 +1,1448 @@ +/** + * \file + * + * \brief USB Device driver + * Compliance with common driver UDD + * + * Copyright (c) 2011 Atmel Corporation. All rights reserved. + * + * \asf_license_start + * + * 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. The name of Atmel may not be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * 4. This software may only be redistributed and used in connection with an + * Atmel microcontroller product. + * + * THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE + * EXPRESSLY AND SPECIFICALLY DISCLAIMED. IN NO EVENT SHALL ATMEL 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. + * + * \asf_license_stop + * + */ + +#include "conf_usb.h" + +// Read Modify Write opcode is implemented after IAR AVR 5.51 +#ifdef __ICCAVR__ +# if (__VER__ <= 551 || XMEGA_A1U) +# undef USB_WORKAROUND_DO_NOT_USE_RMW +# define USB_WORKAROUND_DO_NOT_USE_RMW +# endif +#endif + +#include "sysclk.h" +#include "udd.h" +#include "usb_device.h" +#include + +#ifndef UDD_NO_SLEEP_MGR +#include "sleepmgr.h" +#endif + +#ifndef UDD_USB_INT_LEVEL +// By default USB interrupt have low priority +# define UDD_USB_INT_LEVEL USB_INTLVL_LO_gc +#endif + + + +#ifdef USB_DEVICE_HS_SUPPORT +#error This product does not support high speed mode, please remove define USB_DEVICE_HS_SUPPORT in conf_usb.h +#endif + +//////////////////////////////////////////////////// +// USBB Device low-level driver (UDD) +//////////////////////////////////////////////////// +/** + * \ingroup usb_device_group + * \defgroup udd_group USB Device Driver (UDD) + * + * \section USBB_CONF USBB Custom configuration + * The following USBB driver configuration must be included in the conf_usb.h + * file of the application. + * + * UDD_USB_INT_LEVEL
+ * Option to change the interrupt priority (USB_INTLVL_x_gc) + * by default USB_INTLVL_LO_gc (recommended). + * + * \section Callbacks management + * The USB driver is fully managed by interrupt and does not request periodique + * task. Thereby, the USB events use callbacks to transfer the information. + * The callbacks are declared in static during compilation or in variable during + * code execution. + * + * Static declarations defined in conf_usb.h: + * - UDC_VBUS_EVENT(bool b_present)
+ * To signal Vbus level change + * - UDC_SUSPEND_EVENT()
+ * Called when USB bus enter in suspend mode + * - UDC_RESUME_EVENT()
+ * Called when USB bus is wakeup + * - UDC_SOF_EVENT()
+ * Called for each received SOF, Note: Each 1ms in HS/FS mode only. + * + * Dynamic callbacks, called "endpoint job" , are registered + * in udd_ep_job_t structure via the following functions: + * - udd_ep_run()
+ * To call it when a transfer is finish + * - udd_ep_wait_stall_clear()
+ * To call it when a endpoint halt is disabled + * + * \section Power mode management + * The Sleep modes authorized : + * - in USB IDLE state, the USB needs of USB clock and authorizes up to IDLE mode + * - in USB SUSPEND state, the USB no needs USB clock but requests a minimum + * clock restart timing. Thus, it authorizes up to POWER_DOWN or STANDBY mode. + * + * The USB_SLEEP_MODE_USB_IDLE equals SLEEPMGR_IDLE. + * + * The USB_SLEEP_MODE_USB_SUSPEND depends on USB clock startup timing: + * | Clock Startup | Sleep mode authorized | + * | >10ms | SLEEPMGR_STDBY | + * | <=10ms | SLEEPMGR_PDOWN | + * + * @{ + */ + + +// Check USB Device configuration +#ifndef USB_DEVICE_EP_CTRL_SIZE +# error USB_DEVICE_EP_CTRL_SIZE not defined +#endif +#ifndef USB_DEVICE_MAX_EP +# error USB_DEVICE_MAX_EP not defined +#endif +#if (USB_DEVICE_MAX_EP!=0) +// Errata: FIFO Multipacket generates a TC interrupt for each USB packets +// For silicon version impacted by this errata, the TC FIFO is set at maximum +// Note: Remove it when all silicons are fixed +# define USB_DEVICE_MAX_EP_TEMP 15 +#else +# define USB_DEVICE_MAX_EP_TEMP 0 +#endif + +/** + * \name Power management routine. + */ +//@{ + + +#ifndef UDD_NO_SLEEP_MGR + +//! Definition of sleep levels +#if ((defined USB_DEVICE_HS_SUPPORT) && (USBCLK_STARTUP_TIMEOUT>3000)) \ + || ((!defined USB_DEVICE_HS_SUPPORT) && (USBCLK_STARTUP_TIMEOUT>10000)) +# define USBC_SLEEP_MODE_USB_SUSPEND SLEEPMGR_IDLE +#else +# define USBC_SLEEP_MODE_USB_SUSPEND SLEEPMGR_PDOWN +#endif +#define USBC_SLEEP_MODE_USB_IDLE SLEEPMGR_IDLE + +//! State of USB line +static bool udd_b_idle; + + +/*! \brief Authorize or not the CPU powerdown mode + * + * \param b_enable true to authorize powerdown mode + */ +static void udd_sleep_mode(bool b_idle) +{ + if (!b_idle && udd_b_idle) { + sleepmgr_unlock_mode(USBC_SLEEP_MODE_USB_IDLE); + } + if (b_idle && !udd_b_idle) { + sleepmgr_lock_mode(USBC_SLEEP_MODE_USB_IDLE); + } + udd_b_idle = b_idle; +} +#else + +static void udd_sleep_mode(bool b_idle) { +} +#endif // UDD_NO_SLEEP_MGR + +//@} + +/** + * \brief USB SRAM data about fifo, endpoint descriptor table and frame number + * + * The content of the USB SRAM can be: + * - modified by USB hardware by interface to signal endpoint status. + * Thereby, it is read by software. + * - modified by USB software to control endpoint. + * Thereby, it is read by hardware. + * This data section is volatile and the specific opcode read/modify/write must be used. + * + * @{ + */ +struct udd_sram_data { +#if XMEGA_A1U +# if (0!=((USB_DEVICE_MAX_EP_TEMP+1)%4)) + uint8_t padding_align[16 - ((USB_DEVICE_MAX_EP_TEMP + 1) * + sizeof(uint32_t)) % 16]; +# endif +#endif + uint32_t fifo[USB_DEVICE_MAX_EP_TEMP + 1]; + USB_EP_t ep_ctrl[2 * (USB_DEVICE_MAX_EP_TEMP + 1)]; + uint16_t frame_number; +}; +#if XMEGA_A1U +COMPILER_ALIGNED(16) +#else +COMPILER_ALIGNED(4) //! Caution seems GCC does not handle 2 alignement properly +#endif +static volatile struct udd_sram_data udd_sram; +#define UDD_EP_t USB_EP_t volatile + +// @} + +/** + * \name initialization of endpoint + */ +//@{ +/** + * \brief Configures and enables an endpoint + * + * \param ep Endpoint number including direction (USB_EP_DIR_IN/USB_EP_DIR_OUT). + * \param bmAttributes Attribut of endpoint declared in descriptor. + * \param MaxEndpointSize Endpoint size maximum + */ +static void udd_ep_init(udd_ep_id_t ep, uint8_t bmAttributes, + uint16_t MaxEndpointSize); + +/** + * \brief Returns a pointer on endpoint control SRAM corresponding at endpoint number + * + * \param ep Endpoint number including direction (USB_EP_DIR_IN/USB_EP_DIR_OUT). + * + * \return endpoint descriptor index + */ +static UDD_EP_t *udd_ep_get_ctrl(udd_ep_id_t ep); +//@} + + +/** + * \name Control endpoint low level management routine. + * + * This function performs control endpoint mangement. + * It handle the SETUP/DATA/HANDSHAKE phases of a control transaction. + */ +//@{ + +//! Global variable to give and record information about setup request management +udd_ctrl_request_t udd_g_ctrlreq; + +//! Bit definitions about endpoint control state machine for udd_ep_control_state +typedef enum { + UDD_EPCTRL_SETUP = 0, //!< Wait a SETUP packet + UDD_EPCTRL_DATA_OUT = 1, //!< Wait a OUT data packet + UDD_EPCTRL_DATA_IN = 2, //!< Wait a IN data packet + UDD_EPCTRL_HANDSHAKE_WAIT_IN_ZLP = 3, //!< Wait a IN ZLP packet + UDD_EPCTRL_HANDSHAKE_WAIT_OUT_ZLP = 4, //!< Wait a OUT ZLP packet + UDD_EPCTRL_STALL_REQ = 5, //!< STALL enabled on IN & OUT packet +} udd_ctrl_ep_state_t; + +//! State of the endpoint control management +static udd_ctrl_ep_state_t udd_ep_control_state; +//! Total number of data received/sent during data packet phase with previous payload buffers +static uint16_t udd_ctrl_prev_payload_nb_trans; +//! Number of data received/sent to/from udd_g_ctrlreq.payload buffer +static uint16_t udd_ctrl_payload_nb_trans; +//! Signal if the data sent during IN DATA need of IN ZLP +static bool udd_ctrl_payload_need_in_zlp; + +/** + * \brief Buffer to store the data received on control endpoint (SETUP/OUT endpoint 0) + * + * Used to avoid a RAM buffer overflow in case of the payload buffer + * is smaller than control endpoint size + */ +static uint8_t udd_ctrl_buffer[USB_DEVICE_EP_CTRL_SIZE]; + +/** + * \brief Reset control endpoint management + * + * Called after a USB line reset or at the end of SETUP request (after ZLP) + */ +static void udd_ctrl_init(void); + +//! \brief Managed reception of SETUP packet on control enpoint +static void udd_ctrl_setup_received(void); + +//! \brief Managed reception of IN packet on control enpoint +static void udd_ctrl_in_sent(void); + +//! \brief Managed reception of OUT packet on control enpoint +static void udd_ctrl_out_received(void); + +//! \brief Managed underflow event of IN packet on control enpoint +//! It is used to detect a DATA phase stopped by the host via a ZLP request. +//! This is mandatory for chapter 8 compliance +static void udd_ctrl_underflow(void); + +//! \brief Managed overflow event of OUT packet on control enpoint +//! It is used to detect a DATA phase stopped by the host via a ZLP request. +//! This is mandatory for chapter 8 compliance +static void udd_ctrl_overflow(void); + +//! \brief Managed stall event of IN/OUT packet on control enpoint +static void udd_ctrl_stall_data(void); + +//! \brief Send a ZLP IN on control endpoint +static void udd_ctrl_send_zlp_in(void); + +//! \brief Send a ZLP OUT on control endpoint +static void udd_ctrl_send_zlp_out(void); + +//! \brief Call callback associated to setup request +static void udd_ctrl_endofrequest(void); + +/** + * \brief Sub interrupt routine to manage error on control endpoint + * + * \return \c 1 if an error about control endpoint is occured, otherwise \c 0. + */ +static bool udd_ctrl_interrupt_error(void); + +/** + * \brief Sub interrupt routine to manage a SETUP transfer complet on control endpoint + * + * \return \c 1 if an SETUP transfer complet about control endpoint is occured, + * otherwise \c 0. + */ +static bool udd_ctrl_interrupt_tc_setup(void); + +//@} + + +/** + * \name Management of bulk/interrupt/isochronous endpoints + * + * The UDD manages the data transfer on endpoints: + * - Start data tranfer on endpoint with USB Device DMA + * - Send a ZLP packet if requested + * - Call callback registered to signal end of transfer + * The transfer abort and stall feature are supported. + */ +//@{ +#if (0!=USB_DEVICE_MAX_EP) + +//! Structure definition about job registered on an endpoint +typedef struct { + //! A job is registered on this endpoint + uint8_t busy:1; + //! A short packet is requested for this job on endpoint IN + uint8_t b_shortpacket:1; + //! The cache buffer is currently used on endpoint OUT + uint8_t b_use_out_cache_buffer:1; + //! Buffer located in internal RAM to send or fill during job + uint8_t *buf; + //! Size of buffer to send or fill + iram_size_t buf_size; + //! Total number of data transfered on enpoint + iram_size_t nb_trans; + union { + //! Callback to call at the end of transfer + udd_callback_trans_t call_trans; + //! Callback to call when the endpoint halt is cleared + udd_callback_halt_cleared_t call_nohalt; + }; +} udd_ep_job_t; + +//! Array to register a job on bulk/interrupt/isochronous endpoint +static udd_ep_job_t udd_ep_job[USB_DEVICE_MAX_EP * 2]; + +/** + * \brief Buffer to store the data received on bulk/interrupt endpoints + * + * Used to avoid a RAM buffer overflow in case of the user buffer + * is smaller than endpoint size + * + * \warning The isochronous endpoint is not protected by this system + * and the user must always use a buffer corresponding at endpoint size + */ +#ifdef USB_DEVICE_LOW_SPEED +static uint8_t udd_ep_out_cache_buffer[USB_DEVICE_MAX_EP][8]; +#else +static uint8_t udd_ep_out_cache_buffer[USB_DEVICE_MAX_EP][64]; +#endif + + +/** + * \brief Checks endpoint number + * + * \param ep endpoint number + */ +bool udd_ep_is_valid(udd_ep_id_t ep); + +/** + * \brief Manages transfer complet on bulk/interrupt/isochronous endpoints + * + * \param ep endpoint number to manage + */ +static void udd_ep_trans_complet(udd_ep_id_t ep); + +/** + * \brief Returns the size of endpoint + * + * \return the size of current selected endpoint + */ +static uint16_t udd_ep_get_size(UDD_EP_t * ep_ctrl); + +/** + * \brief Returns a pointer on endpoint job corresponding at endpoint number + * + * \param ep Endpoint number including direction (USB_EP_DIR_IN/USB_EP_DIR_OUT). + */ +static udd_ep_job_t *udd_ep_get_job(udd_ep_id_t ep); + +#endif // (0!=USB_DEVICE_MAX_EP) +//@} + + +void udd_enable(void) +{ + uint8_t i; + irqflags_t flags; + + // Sanity check Silicon revision +#if part_is_defined(ATxmega128A1U) + // The part ATxmega128A1U Rev. J is not supported, please use new silicon revision. + Assert(!(MCU_REVID < 0x0A)); +#endif + +#ifdef CONFIG_OSC_AUTOCAL +# if CONFIG_OSC_AUTOCAL_REF_OSC == OSC_ID_USBSOF + // RC oscillator calibration via USB Start Of Frame is not available + // in low speed mode. + // Thus, the calibration is disabled + // when USB interface start in low speed mode + DFLLRC32M.CTRL = 0; +# endif +#endif + +#ifdef USB_DEVICE_LOW_SPEED + // The USB hardware need of 6MHz in low speed mode + sysclk_enable_usb(6); + udd_set_low_speed(); +#else + // The USB hardware need of 48MHz in full speed mode + sysclk_enable_usb(48); + udd_set_full_speed(); +# ifdef CONFIG_OSC_AUTOCAL +# if CONFIG_OSC_AUTOCAL_REF_OSC == OSC_ID_USBSOF + // Now the full mode is enabled and the SOF calibration can be enabled + DFLLRC32M.CTRL = DFLL_ENABLE_bm; +# endif +# endif +#endif + + flags = cpu_irq_save(); + + // Reset endpoints table + for (i = 0; i < ((USB_DEVICE_MAX_EP_TEMP + 1) * 2); i++) { + udd_sram.ep_ctrl[i].CTRL = 0; + } +#if (0!=USB_DEVICE_MAX_EP) + // Reset internal variables + for (i = 0; i < (USB_DEVICE_MAX_EP * 2); i++) { + udd_ep_job[i].busy = false; + } +#endif + + //** Enable USB hardware + usb_pad_init(); + udd_set_nb_max_ep(USB_DEVICE_MAX_EP_TEMP); + udd_enable_interface(); + udd_enable_store_frame_number(); + udd_set_ep_table_addr(udd_sram.ep_ctrl); + // Enable TC fifo management + udd_enable_fifo(); + udd_reset_fifo(); + // Enable Interrupt USB Device + udd_enable_interrupt(UDD_USB_INT_LEVEL); + +#ifndef UDD_NO_SLEEP_MGR + // Initialize the sleep mode authorized for the USB suspend mode + udd_b_idle = false; + sleepmgr_lock_mode(USBC_SLEEP_MODE_USB_SUSPEND); +#endif + + cpu_irq_restore(flags); +} + + +void udd_disable(void) +{ + irqflags_t flags; + flags = cpu_irq_save(); + udd_detach_device(); + // Disable interface + USB_INTCTRLA = 0; + USB_INTCTRLB = 0; + sysclk_disable_usb(); + udd_sleep_mode(false); +#ifndef UDD_NO_SLEEP_MGR + sleepmgr_unlock_mode(USBC_SLEEP_MODE_USB_SUSPEND); +#endif + cpu_irq_restore(flags); +} + +bool udd_include_vbus_monitoring(void) +{ + return false; // No Vbus monitoring +} + +void udd_attach(void) +{ + irqflags_t flags; + flags = cpu_irq_save(); + + // At startup the USB bus state is unknown, + // therefore the state is considered IDLE to not miss any USB event + udd_sleep_mode(true); + + udd_ack_suspend_event(); + udd_ack_resume_event(); + udd_attach_device(); + // Enable main USB interrupts + udd_enable_tc_interrupt(); + udd_enable_busevt_interrupt(); + udd_enable_setup_interrupt(); + udd_enable_start_of_frame_interrupt(); + + cpu_irq_restore(flags); +} + +void udd_detach(void) +{ + // Detach device from the bus + udd_detach_device(); +} + +bool udd_is_high_speed(void) +{ + return false; +} + +void udd_set_address(uint8_t address) +{ + udd_set_device_address(address); +} + +uint8_t udd_getaddress(void) +{ + return udd_get_device_address(); +} + +uint16_t udd_get_frame_number(void) +{ + return udd_sram.frame_number; +} + +uint16_t udd_get_micro_frame_number(void) +{ + return 0; +} + +void udd_send_wake_up(void) +{ +#ifndef UDD_NO_SLEEP_MGR + if (!udd_b_idle) +#endif + { + udd_sleep_mode(true); // Enter in IDLE mode + udd_send_remote_wake_up(); + } +} + +void udd_set_setup_payload( uint8_t *payload, uint16_t payload_size ) +{ + udd_g_ctrlreq.payload = payload; + udd_g_ctrlreq.payload_size = payload_size; +} + +#if (0!=USB_DEVICE_MAX_EP) +bool udd_ep_alloc(udd_ep_id_t ep, uint8_t bmAttributes, + uint16_t MaxEndpointSize) +{ + UDD_EP_t *ep_ctrl; + Assert(udd_ep_is_valid(ep)); + + ep_ctrl = udd_ep_get_ctrl(ep); + if (udd_endpoint_is_enable(ep_ctrl)) { + return false; // Already allocated + } + udd_ep_init(ep, bmAttributes, MaxEndpointSize); + + // Do not use multipacket mode with isochronous 1023 bytes endpoint + if (udd_endpoint_get_type(ep_ctrl)==USB_EP_TYPE_ISOCHRONOUS_gc + && (udd_endpoint_get_size_field(ep_ctrl) + ==USB_EP_BUFSIZE_1023_gc)) { + return true; + } + + udd_endpoint_set_multipacket(ep_ctrl); + return true; +} + +void udd_ep_free(udd_ep_id_t ep) +{ + UDD_EP_t *ep_ctrl; + Assert(udd_ep_is_valid(ep)); + + udd_ep_abort(ep); + ep_ctrl = udd_ep_get_ctrl(ep); + udd_endpoint_disable(ep_ctrl); +} + +bool udd_ep_is_halted(udd_ep_id_t ep) +{ + UDD_EP_t *ep_ctrl; + Assert(udd_ep_is_valid(ep)); + + ep_ctrl = udd_ep_get_ctrl(ep); + return (udd_endpoint_is_stall(ep_ctrl)); +} + +bool udd_ep_set_halt(udd_ep_id_t ep) +{ + UDD_EP_t *ep_ctrl; + Assert(udd_ep_is_valid(ep)); + + ep_ctrl = udd_ep_get_ctrl(ep); + udd_endpoint_enable_stall(ep_ctrl); + udd_endpoint_clear_dtgl(ep_ctrl); + + udd_ep_abort(ep); + return true; +} + +bool udd_ep_clear_halt(udd_ep_id_t ep) +{ + udd_ep_job_t *ptr_job; + UDD_EP_t *ep_ctrl; + Assert(udd_ep_is_valid(ep)); + + ep_ctrl = udd_ep_get_ctrl(ep); + udd_endpoint_disable_stall(ep_ctrl); + + // If a job is register on clear halt action + // then execute callback + ptr_job = udd_ep_get_job(ep); + if (ptr_job->busy == true) { + ptr_job->busy = false; + ptr_job->call_nohalt(); + } + return true; +} + +bool udd_ep_run(udd_ep_id_t ep, bool b_shortpacket, uint8_t * buf, + iram_size_t buf_size, udd_callback_trans_t callback) +{ + udd_ep_job_t *ptr_job; + irqflags_t flags; + UDD_EP_t *ep_ctrl; + + Assert(udd_ep_is_valid(ep)); + + // Get control & job about this endpoint + ptr_job = udd_ep_get_job(ep); + ep_ctrl = udd_ep_get_ctrl(ep); + + if (!udd_endpoint_is_enable(ep_ctrl)) { + return false; // Endpoint not allocated + } + if (udd_endpoint_get_type(ep_ctrl)!=USB_EP_TYPE_ISOCHRONOUS_gc + && udd_endpoint_is_stall(ep_ctrl)) { + return false; // Endpoint is halted + } + flags = cpu_irq_save(); + if (ptr_job->busy == true) { + cpu_irq_restore(flags); + return false; // Job already on going + } + ptr_job->busy = true; + cpu_irq_restore(flags); + + + // Update Job information + ptr_job->buf = buf; + ptr_job->buf_size = buf_size; + ptr_job->nb_trans = 0; + ptr_job->call_trans = callback; + // Need to enable shortpacket to send a ZLP (buf_size==0) + ptr_job->b_shortpacket = b_shortpacket || (buf_size==0); + ptr_job->b_use_out_cache_buffer = false; + + // Initialize value to simulate a empty transfer + if (USB_EP_DIR_IN == (ep & USB_EP_DIR_IN)) { + udd_endpoint_in_reset_nb_sent(ep_ctrl); + } + else + { + if ((USB_EP_TYPE_ISOCHRONOUS_gc == udd_endpoint_get_type(ep_ctrl)) + && (0 != (buf_size % udd_ep_get_size(ep_ctrl)))) { + // The user must use a buffer size modulo endpoint size + ptr_job->busy = false; + return false; + } + udd_endpoint_out_reset_nb_received(ep_ctrl); + udd_endpoint_out_set_nbbyte(ep_ctrl, 0); + } + // Request next transfer + udd_ep_trans_complet(ep); + return true; +} + +void udd_ep_abort(udd_ep_id_t ep) +{ + UDD_EP_t *ep_ctrl; + udd_ep_job_t *ptr_job; + Assert(udd_ep_is_valid(ep)); + + ep_ctrl = udd_ep_get_ctrl(ep); + ptr_job = udd_ep_get_job(ep); + + // Stop transfer + udd_endpoint_set_NACK0(ep_ctrl); + if (ptr_job->busy == false) { + return; // No job on going + } + ptr_job->busy = false; + if (NULL != ptr_job->call_trans) { + ptr_job->call_trans(UDD_EP_TRANSFER_ABORT, + (ep & USB_EP_DIR_IN) ? + udd_endpoint_in_nb_sent(ep_ctrl) + : udd_endpoint_out_nb_receiv(ep_ctrl)); + } +} + +bool udd_ep_wait_stall_clear(udd_ep_id_t ep, + udd_callback_halt_cleared_t callback) +{ + udd_ep_job_t *ptr_job; + UDD_EP_t *ep_ctrl; + Assert(udd_ep_is_valid(ep)); + + ep_ctrl = udd_ep_get_ctrl(ep); + ptr_job = udd_ep_get_job(ep); + + if (udd_endpoint_is_stall(ep_ctrl)) { + // Wait clear halt endpoint + if (ptr_job->busy == true) { + return false; // Job already on going + } + ptr_job->busy = true; + ptr_job->call_nohalt = callback; + } else { + // Enpoint not halted then call directly callback + callback(); + } + return true; +} +#endif // (0!=USB_DEVICE_MAX_EP) + +//-------------------------------------------------------- +//--- INTERNAL ROUTINES TO MANAGED GLOBAL EVENTS + +/** + * \internal + * \brief Function called by USB bus event interrupt + * + * USB bus event interrupt includes : + * - USB line events SOF, reset, suspend, resume, wakeup + * - endpoint control errors underflow, overflow, stall + */ +ISR(USB_BUSEVENT_vect) +{ + if (udd_is_start_of_frame_event()) { + udd_ack_start_of_frame_event(); + udc_sof_notify(); +#ifdef UDC_SOF_EVENT + UDC_SOF_EVENT(); +#endif + goto udd_interrupt_bus_event_end; + } + + if (udd_ctrl_interrupt_error()) { + goto udd_interrupt_bus_event_end; + } + if (udd_is_reset_event()) { + udd_ack_reset_event(); +#if (0!=USB_DEVICE_MAX_EP) + // Abort all endpoint jobs on going + uint8_t i; + for (i = 1; i < USB_DEVICE_MAX_EP; i++) { + udd_ep_abort(i); + udd_ep_abort(i | USB_EP_DIR_IN); + } +#endif + udc_reset(); + + // Reset USB address to 0 + udd_set_device_address(0); + // Alloc and configure control endpoint + udd_ep_init(0, USB_EP_TYPE_CONTROL, USB_DEVICE_EP_CTRL_SIZE); + udd_ep_init(0 | USB_EP_DIR_IN, USB_EP_TYPE_CONTROL, + USB_DEVICE_EP_CTRL_SIZE); + udd_control_out_set_buf(&udd_ctrl_buffer); + // Reset endpoint control management + udd_ctrl_init(); + goto udd_interrupt_bus_event_end; + } + + if (udd_is_suspend_event()) { + udd_ack_suspend_event(); + udd_sleep_mode(false); // Enter in SUSPEND mode +#ifdef UDC_SUSPEND_EVENT + UDC_SUSPEND_EVENT(); +#endif + goto udd_interrupt_bus_event_end; + } + + if (udd_is_resume_event()) { + udd_ack_resume_event(); + udd_sleep_mode(true); // Enter in power reduction mode +#ifdef UDC_RESUME_EVENT + UDC_RESUME_EVENT(); +#endif + goto udd_interrupt_bus_event_end; + } + +udd_interrupt_bus_event_end: + return; +} + +/** + * \internal + * \brief Function called by USB transfer complet interrupt + * + * USB transfer complet interrupt includes events about endpoint transfer on all endpoints. + */ +ISR(USB_TRNCOMPL_vect) +{ +#if (0!=USB_DEVICE_MAX_EP) + uint8_t ep_index; + uint8_t i_fifo; + uint16_t ad; + uint16_t *p_ad; + int8_t rp; + UDD_EP_t *ep_ctrl; + udd_ep_id_t ep; +#endif + + // Check reception of SETUP packet on control endpoint + if (udd_ctrl_interrupt_tc_setup()) { + goto udd_interrupt_tc_end; // Interrupt acked by control endpoint managed + } + // Check IN/OUT transfer complet on all endpoints + Assert(udd_is_tc_event()); + udd_ack_tc_event(); + +#if (0!=USB_DEVICE_MAX_EP) + //** Decode TC FIFO + // Compute ep addr + rp = udd_get_fifo_rp(); + i_fifo = 2 * (1 + ~rp); + ad = ((uint16_t) udd_sram.ep_ctrl) - i_fifo; + p_ad = (uint16_t *) ad; + // Compute ep + ep_index = (((uint16_t) * p_ad - ((uint16_t) udd_sram.ep_ctrl)) >> 3); + ep = (ep_index / 2) + ((ep_index & 1) ? USB_EP_DIR_IN : 0); + Assert(USB_DEVICE_MAX_EP >= (ep & USB_EP_ADDR_MASK)); + + // Ack IT TC of endpoint + ep_ctrl = udd_ep_get_ctrl(ep); + if (!udd_endpoint_transfer_complete(ep_ctrl)) { + return; // Error, TC is generated by Multipacket transfer + } + udd_endpoint_ack_transfer_complete(ep_ctrl); + + // Check status on control endpoint + if (ep == 0) { + udd_ctrl_out_received(); + goto udd_interrupt_tc_end; // Interrupt acked by control endpoint managed + } + if (ep == (0 | USB_EP_DIR_IN)) { + udd_ctrl_in_sent(); + goto udd_interrupt_tc_end; // Interrupt acked by control endpoint managed + } + Assert(udd_ep_is_valid(ep)); + // Manage end of transfert on endpoint bulk/interrupt/isochronous + udd_ep_trans_complet(ep); + +#else + + udd_get_fifo_rp(); + if (udd_endpoint_transfer_complete(udd_ep_get_ctrl(0))) { + udd_endpoint_ack_transfer_complete(udd_ep_get_ctrl(0)); + udd_ctrl_out_received(); + }else{ + udd_endpoint_ack_transfer_complete(udd_ep_get_ctrl(0 | USB_EP_DIR_IN)); + udd_ctrl_in_sent(); + } +#endif + +udd_interrupt_tc_end: + return; +} + +//-------------------------------------------------------- +//--- INTERNAL ROUTINES TO INITIALIZE ENDPOINT + +static void udd_ep_init(udd_ep_id_t ep, uint8_t bmAttributes, + uint16_t MaxEndpointSize) +{ + USB_EP_TYPE_t type; + USB_EP_BUFSIZE_t size; + UDD_EP_t *ep_ctrl; + +#if (0!=USB_DEVICE_MAX_EP) + // Translate USB attribut to hardware defines + switch (bmAttributes & USB_EP_TYPE_MASK) { + case USB_EP_TYPE_CONTROL: + type = USB_EP_TYPE_CONTROL_gc; + break; + case USB_EP_TYPE_ISOCHRONOUS: + type = USB_EP_TYPE_ISOCHRONOUS_gc; + break; + case USB_EP_TYPE_BULK: + case USB_EP_TYPE_INTERRUPT: //interrupt behaves as bulk + type = USB_EP_TYPE_BULK_gc; + break; + default: + Assert(false); // Wrong value + break; + } +#else + type = USB_EP_TYPE_CONTROL_gc; +#endif + + // Translate USB endpoint size to hardware defines + switch (MaxEndpointSize) { + default: + Assert(false); // Wrong value + case 8: + size = USB_EP_BUFSIZE_8_gc; + break; + case 16: + size = USB_EP_BUFSIZE_16_gc; + break; + case 32: + size = USB_EP_BUFSIZE_32_gc; + break; + case 64: + size = USB_EP_BUFSIZE_64_gc; + break; +#if (0!=USB_DEVICE_MAX_EP) + case 128: + size = USB_EP_BUFSIZE_128_gc; + break; + case 256: + size = USB_EP_BUFSIZE_256_gc; + break; + case 512: + size = USB_EP_BUFSIZE_512_gc; + break; + case 1023: + size =USB_EP_BUFSIZE_1023_gc; + break; +#endif + } + + // Enable endpoint + ep_ctrl = udd_ep_get_ctrl(ep); + udd_endpoint_disable(ep_ctrl); + udd_endpoint_clear_status(ep_ctrl); + udd_endpoint_set_control(ep_ctrl, (uint8_t) type | (uint8_t) size); +} + +static UDD_EP_t *udd_ep_get_ctrl(udd_ep_id_t ep) +{ + return &udd_sram.ep_ctrl[(2 * (ep & USB_EP_ADDR_MASK) + + ((ep & USB_EP_DIR_IN) ? 1 : 0))]; +} + + +//-------------------------------------------------------- +//--- INTERNAL ROUTINES TO MANAGED THE CONTROL ENDPOINT + +static void udd_ctrl_init(void) +{ + udd_disable_overflow_interrupt(); + udd_disable_underflow_interrupt(); + + // Clear status flag from control endpointS + // Mandatory for ATxmega128A1 Rev. K + udd_control_in_set_NACK0(); + udd_control_in_set_bytecnt(0); + udd_control_in_ack_tc(); + udd_control_ack_in_underflow(); + udd_control_out_ack_tc(); + udd_control_ack_out_overflow(); + + udd_g_ctrlreq.callback = NULL; + udd_g_ctrlreq.over_under_run = NULL; + udd_g_ctrlreq.payload_size = 0; + udd_ep_control_state = UDD_EPCTRL_SETUP; +} + +static void udd_ctrl_setup_received(void) +{ + if (UDD_EPCTRL_SETUP != udd_ep_control_state) { + if ((UDD_EPCTRL_HANDSHAKE_WAIT_IN_ZLP == udd_ep_control_state) + || (UDD_EPCTRL_HANDSHAKE_WAIT_OUT_ZLP == udd_ep_control_state)) { + // Accept that ZLP event can be hidden by setup packet event + // in case of setup packet sending quiclky after a ZLP + udd_ctrl_endofrequest(); + } + // Reinitializes control endpoint management + udd_ctrl_init(); + } + // Fill setup request structure + if (8 != udd_control_out_get_bytecnt()) + return; // Error data number don't correspond to SETUP packet + memcpy((uint8_t *) & udd_g_ctrlreq.req, udd_ctrl_buffer, 8); + + // To detect a protocol error on setup, enable nak interrupt on IN/OUT of control endpoint + udd_enable_overflow_interrupt(); + udd_enable_underflow_interrupt(); + + // Decode setup request + if (udc_process_setup() == false) { + // Setup request unknow then stall it + udd_ctrl_stall_data(); + return; + } + + if (Udd_setup_is_in()) { + // Compute if an IN ZLP must be send after IN data + udd_ctrl_payload_need_in_zlp = + ((udd_g_ctrlreq.payload_size % USB_DEVICE_EP_CTRL_SIZE) == 0); + udd_ctrl_prev_payload_nb_trans = 0; + udd_ctrl_payload_nb_trans = 0; + udd_ep_control_state = UDD_EPCTRL_DATA_IN; + udd_ctrl_in_sent(); // Send first data transfer + } else { + if (0 == udd_g_ctrlreq.req.wLength) { + // No data phase requested + // Send IN ZLP to ACK setup request + udd_ctrl_send_zlp_in(); + return; + } + // OUT data phase requested + udd_ctrl_prev_payload_nb_trans = 0; + udd_ctrl_payload_nb_trans = 0; + udd_ep_control_state = UDD_EPCTRL_DATA_OUT; + // Clear packet to receive first packet + udd_control_out_clear_NACK0(); + } +} + +static void udd_ctrl_in_sent(void) +{ + uint16_t nb_remain; + + if (UDD_EPCTRL_HANDSHAKE_WAIT_IN_ZLP == udd_ep_control_state) { + // ZLP on IN is sent, then valid end of setup request + udd_ctrl_endofrequest(); + // Reinitializes control endpoint management + udd_ctrl_init(); + return; + } + Assert(udd_ep_control_state == UDD_EPCTRL_DATA_IN); + + nb_remain = udd_g_ctrlreq.payload_size - udd_ctrl_payload_nb_trans; + if (0 == nb_remain) { + // All content of current buffer payload are sent + if (!udd_ctrl_payload_need_in_zlp) { + // It is the end of data phase, because the last data packet is a short packet + // then generate an OUT ZLP for handshake phase. + udd_ctrl_send_zlp_out(); + return; + } + if ((udd_g_ctrlreq.req.wLength > (udd_ctrl_prev_payload_nb_trans + + udd_g_ctrlreq.payload_size)) + || (!udd_g_ctrlreq.over_under_run) + || (!udd_g_ctrlreq.over_under_run())) { + // Underrun or data packet complete + // than send zlp on IN (note don't change DataToggle) + udd_ctrl_payload_need_in_zlp = false; + udd_control_in_set_bytecnt(0); + goto udd_ctrl_in_sent_continue; + } + // A new payload buffer is given + // Update number of total data sending by previous payload buffer + udd_ctrl_prev_payload_nb_trans += udd_ctrl_payload_nb_trans; + // Update maangement of current playoad transfer + udd_ctrl_payload_nb_trans = 0; + nb_remain = udd_g_ctrlreq.payload_size; + // Compute if an IN ZLP must be send after IN data + udd_ctrl_payload_need_in_zlp = + ((udd_g_ctrlreq.payload_size % USB_DEVICE_EP_CTRL_SIZE) == 0); + } + // Continue transfer an send next data + if (nb_remain > USB_DEVICE_EP_CTRL_SIZE) { + nb_remain = USB_DEVICE_EP_CTRL_SIZE; + } + udd_control_in_set_bytecnt(nb_remain); + + // Link payload buffer directly on USB hardware + udd_control_in_set_buf(udd_g_ctrlreq.payload + udd_ctrl_payload_nb_trans); + udd_ctrl_payload_nb_trans += nb_remain; + +udd_ctrl_in_sent_continue: + // Valid and sent the data available in control endpoint buffer + udd_control_in_clear_NACK0(); +} + +static void udd_ctrl_out_received(void) +{ + uint16_t nb_data; + + if (UDD_EPCTRL_HANDSHAKE_WAIT_OUT_ZLP == udd_ep_control_state) { + // Valids end of setup request + udd_ctrl_endofrequest(); + // Reinitializes control endpoint management + udd_ctrl_init(); + return; + } + Assert(udd_ep_control_state == UDD_EPCTRL_DATA_OUT); + + // Read data received during OUT phase + nb_data = udd_control_out_get_bytecnt(); + + if (udd_g_ctrlreq.payload_size < (udd_ctrl_payload_nb_trans + nb_data)) { + // Payload buffer too small, ignore data remaining + nb_data = udd_g_ctrlreq.payload_size - udd_ctrl_payload_nb_trans; + } + + memcpy((uint8_t *) (udd_g_ctrlreq.payload + udd_ctrl_payload_nb_trans), + udd_ctrl_buffer, nb_data); + udd_ctrl_payload_nb_trans += nb_data; + + if ((USB_DEVICE_EP_CTRL_SIZE != nb_data) || (udd_g_ctrlreq.req.wLength + <= (udd_ctrl_prev_payload_nb_trans + + udd_ctrl_payload_nb_trans))) { + // End of reception because it is a short packet + // or all data are transfered + + // Before send ZLP, call intermediat calback + // in case of data receiv generate a stall + udd_g_ctrlreq.payload_size = udd_ctrl_payload_nb_trans; + if (NULL != udd_g_ctrlreq.over_under_run) { + if (!udd_g_ctrlreq.over_under_run()) { + // Stall ZLP + udd_ctrl_stall_data(); + return; + } + } + // Send IN ZLP to ACK setup request + udd_ctrl_send_zlp_in(); + return; + } + + if (udd_g_ctrlreq.payload_size == udd_ctrl_payload_nb_trans) { + // Overrun then request a new payload buffer + if (!udd_g_ctrlreq.over_under_run) { + // No callback availabled to request a new payload buffer + udd_ctrl_stall_data(); + return; + } + if (!udd_g_ctrlreq.over_under_run()) { + // No new payload buffer delivered + udd_ctrl_stall_data(); + return; + } + // New payload buffer available + // Update number of total data received + udd_ctrl_prev_payload_nb_trans += udd_ctrl_payload_nb_trans; + // Reinit reception on payload buffer + udd_ctrl_payload_nb_trans = 0; + } + // Free buffer of OUT control endpoint to authorize next reception + udd_control_out_clear_NACK0(); +} + +static void udd_ctrl_underflow(void) +{ + if (udd_control_out_tc()) { + return; // underflow ignored if OUT data is received + } + if (UDD_EPCTRL_DATA_OUT == udd_ep_control_state) { + // Host want to stop OUT transaction + // then stop to wait OUT data phase and wait IN ZLP handshake + udd_ctrl_send_zlp_in(); + } else if (UDD_EPCTRL_HANDSHAKE_WAIT_OUT_ZLP == udd_ep_control_state) { + // A OUT handshake is waiting by device, + // but host want extra IN data then stall extra IN data and following status stage + udd_control_in_enable_stall(); + udd_control_out_enable_stall(); + } +} + +static void udd_ctrl_overflow(void) +{ + if (udd_control_in_tc()) { + return; // overflow ignored if IN data is received + } + if (UDD_EPCTRL_DATA_IN == udd_ep_control_state) { + // Host want to stop IN transaction + // then stop to wait IN data phase and wait OUT ZLP handshake + udd_ctrl_send_zlp_out(); + } else if (UDD_EPCTRL_HANDSHAKE_WAIT_IN_ZLP == udd_ep_control_state) { + // A IN handshake is waiting by device, + // but host want extra OUT data then stall extra OUT data and following status stage + udd_control_in_enable_stall(); + udd_control_out_enable_stall(); + } +} + +static void udd_ctrl_stall_data(void) +{ + // Stall all packets on IN & OUT control endpoint + udd_ep_control_state = UDD_EPCTRL_STALL_REQ; + udd_control_in_enable_stall(); + udd_control_out_enable_stall(); +} + +static void udd_ctrl_send_zlp_in(void) +{ + udd_ep_control_state = UDD_EPCTRL_HANDSHAKE_WAIT_IN_ZLP; + // Valid and sent empty IN packet on control endpoint + udd_control_in_set_bytecnt(0); + udd_control_in_clear_NACK0(); +} + +static void udd_ctrl_send_zlp_out(void) +{ + udd_ep_control_state = UDD_EPCTRL_HANDSHAKE_WAIT_OUT_ZLP; + // Valid reception of OUT packet on control endpoint + udd_control_out_clear_NACK0(); +} + +static void udd_ctrl_endofrequest(void) +{ + // If a callback is registered then call it + if (udd_g_ctrlreq.callback) { + udd_g_ctrlreq.callback(); + } +} + +static bool udd_ctrl_interrupt_error(void) +{ + // Underflow only managed for control endpoint + if (udd_is_underflow_event()) { + udd_ack_underflow_event(); + if (udd_control_in_underflow()) { + udd_ctrl_underflow(); + } + return true; + } + // Overflow only managed for control endpoint + if (udd_is_overflow_event()) { + udd_ack_overflow_event(); + if (udd_control_out_overflow()) { + udd_ctrl_overflow(); + } + return true; + } + return false; +} + +static bool udd_ctrl_interrupt_tc_setup(void) +{ + if (!udd_is_setup_event()) { + return false; + } + udd_ack_setup_event(); + + // Clear eventually previous stall events + udd_control_out_ack_stall(); + udd_control_in_ack_stall(); + udd_ack_stall_event(); + + Assert(udd_control_setup()); // A setup must be received on control endpoint + + // Ack SETUP packet and decode request + udd_control_ack_setup(); + udd_ctrl_setup_received(); + return true; +} + + +//-------------------------------------------------------- +//--- INTERNAL ROUTINES TO MANAGED THE BULK/INTERRUPT/ISOCHRONOUS ENDPOINTS + +#if (0!=USB_DEVICE_MAX_EP) + +static uint16_t udd_ep_get_size(UDD_EP_t * ep_ctrl) +{ + // Translate hardware defines to USB endpoint size + switch (udd_endpoint_get_size_field(ep_ctrl)) { + default: + case USB_EP_BUFSIZE_8_gc: + return 8; + case USB_EP_BUFSIZE_16_gc: + return 16; + case USB_EP_BUFSIZE_32_gc: + return 32; + case USB_EP_BUFSIZE_64_gc: + return 64; + case USB_EP_BUFSIZE_128_gc: + return 128; + case USB_EP_BUFSIZE_256_gc: + return 256; + case USB_EP_BUFSIZE_512_gc: + return 512; + case USB_EP_BUFSIZE_1023_gc: + return 1023; + } +} + +static udd_ep_job_t *udd_ep_get_job(udd_ep_id_t ep) +{ + return &udd_ep_job[(2 * (ep & USB_EP_ADDR_MASK) + + ((ep & USB_EP_DIR_IN) ? 1 : 0)) - 2]; +} + +bool udd_ep_is_valid(udd_ep_id_t ep) +{ + ep &= USB_EP_ADDR_MASK; + if (ep == 0) { + return false; + } + return (USB_DEVICE_MAX_EP >= ep); +} + +static void udd_ep_trans_complet(udd_ep_id_t ep) +{ + UDD_EP_t *ep_ctrl; + udd_ep_job_t *ptr_job; + uint16_t ep_size, nb_trans; + iram_size_t next_trans; + + ptr_job = udd_ep_get_job(ep); + ep_ctrl = udd_ep_get_ctrl(ep); + ep_size = udd_ep_get_size(ep_ctrl); + + if (USB_EP_DIR_IN == (ep & USB_EP_DIR_IN)) { + // Transfer complet on IN + nb_trans = udd_endpoint_in_nb_sent(ep_ctrl); + + // Update number of data transfered + ptr_job->nb_trans += nb_trans; + + // Need to send other data + if (ptr_job->nb_trans != ptr_job->buf_size) { + next_trans = ptr_job->buf_size - ptr_job->nb_trans; + if (UDD_ENDPOINT_MAX_TRANS < next_trans) { + // The USB hardware support a maximum + // transfer size of UDD_ENDPOINT_MAX_TRANS Bytes + next_trans = UDD_ENDPOINT_MAX_TRANS - + (UDD_ENDPOINT_MAX_TRANS % ep_size); + } + // Need ZLP, if requested and last packet is not a short packet + ptr_job->b_shortpacket = ptr_job->b_shortpacket + && (0==(next_trans % ep_size)); + udd_endpoint_in_reset_nb_sent(ep_ctrl); + udd_endpoint_in_set_bytecnt(ep_ctrl, next_trans); + // Link the user buffer directly on USB hardware DMA + udd_endpoint_set_buf(ep_ctrl, &ptr_job->buf[ptr_job->nb_trans]); + udd_endpoint_clear_NACK0(ep_ctrl); + return; + } + + // Need to send a ZLP after all data transfer + if (ptr_job->b_shortpacket) { + ptr_job->b_shortpacket = false; + udd_endpoint_in_reset_nb_sent(ep_ctrl); + udd_endpoint_in_set_bytecnt(ep_ctrl, 0); + udd_endpoint_clear_NACK0(ep_ctrl); + return; + } + } + else + { + // Transfer complet on OUT + nb_trans = udd_endpoint_out_nb_receiv(ep_ctrl); + + // Can be necessary to copy data receiv from cache buffer to user buffer + if (ptr_job->b_use_out_cache_buffer) { + memcpy(&ptr_job->buf[ptr_job->nb_trans] + , udd_ep_out_cache_buffer[ep - 1] + , ptr_job->buf_size % ep_size); + } + + // Update number of data transfered + ptr_job->nb_trans += nb_trans; + if (ptr_job->nb_trans > ptr_job->buf_size) { + ptr_job->nb_trans = ptr_job->buf_size; + } + + // If all previous data requested are received and user buffer not full + // then need to receiv other data + if ((nb_trans == udd_endpoint_out_get_nbbyte_requested(ep_ctrl)) + && (ptr_job->nb_trans != ptr_job->buf_size)) { + next_trans = ptr_job->buf_size - ptr_job->nb_trans; + if (UDD_ENDPOINT_MAX_TRANS < next_trans) { + // The USB hardware support a maximum transfer size + // of UDD_ENDPOINT_MAX_TRANS Bytes + next_trans = UDD_ENDPOINT_MAX_TRANS + - (UDD_ENDPOINT_MAX_TRANS % ep_size); + } else { + next_trans -= next_trans % ep_size; + } + + udd_endpoint_out_reset_nb_received(ep_ctrl); + if (next_trans < ep_size) { + // Use the cache buffer for Bulk or Interrupt size endpoint + ptr_job->b_use_out_cache_buffer = true; + udd_endpoint_set_buf( ep_ctrl, + udd_ep_out_cache_buffer[((ep & USB_EP_ADDR_MASK) - 1)]); + udd_endpoint_out_set_nbbyte(ep_ctrl, ep_size); + } else { + // Link the user buffer directly on USB hardware DMA + udd_endpoint_set_buf(ep_ctrl, &ptr_job->buf[ptr_job->nb_trans]); + udd_endpoint_out_set_nbbyte(ep_ctrl, next_trans); + } + // Start transfer + udd_endpoint_clear_NACK0(ep_ctrl); + return; + } + } + + // Job complet then call callback + if (ptr_job->busy) { + ptr_job->busy = false; + if (NULL != ptr_job->call_trans) { + ptr_job->call_trans(UDD_EP_TRANSFER_OK, + ptr_job->nb_trans); + } + } + return; +} +#endif // (0!=USB_DEVICE_MAX_EP) +//@} diff --git a/DSTAT1/src/asf/xmega/drivers/usb/usb_device.h b/DSTAT1/src/asf/xmega/drivers/usb/usb_device.h new file mode 100644 index 0000000000000000000000000000000000000000..c15241c6b6c59de6c39f50ec44773e5f1128d099 --- /dev/null +++ b/DSTAT1/src/asf/xmega/drivers/usb/usb_device.h @@ -0,0 +1,385 @@ +/** + * \file + * + * \brief USB Driver header file for XMEGA products including USB interface. + * + * Copyright (c) 2011 Atmel Corporation. All rights reserved. + * + * \asf_license_start + * + * 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. The name of Atmel may not be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * 4. This software may only be redistributed and used in connection with an + * Atmel microcontroller product. + * + * THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE + * EXPRESSLY AND SPECIFICALLY DISCLAIMED. IN NO EVENT SHALL ATMEL 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. + * + * \asf_license_stop + * + */ + +#ifndef _USB_DEVICE_H_ +#define _USB_DEVICE_H_ + +#include + +/** + * \ingroup usb_device_group + * \defgroup udd_group USB Device Driver (UDD) + * USBC low-level driver for USB Device mode + * + * + * @{ + */ + +//! @name USB Device main management +//! @{ + +/** + * \brief Initializes the USB DP/DM buffers + * + * This functions initializes the USB buffer using the calibration value + * stored in production raw. + * If the calibration value is not found (0xFF) value, a default typical + * value is applied. + * Alternatively user can force calibration values using USB_PAD_USER_CAL0 + * and USB_PAD_USER_CAL1 + * + */ +static inline void usb_pad_init(void) +{ + uint8_t cal; + +#ifdef USB_PAD_USER_CAL0 + USB_CAL0 = USB_PAD_USER_CAL0; +#else + cal = nvm_read_production_signature_row + (nvm_get_production_signature_row_offset(USBCAL0)); + if (cal != 0xFF) { + USB_CAL0 = cal; + } else { + USB_CAL0 = 0x1F; + } +#endif + +#ifdef USB_PAD_USER_CAL1 + USB_CAL1 = USB_PAD_USER_CAL1; +#else + cal = nvm_read_production_signature_row + (nvm_get_production_signature_row_offset(USBCAL1)); + if (cal != 0xFF) { + USB_CAL1 = cal; + } else { + USB_CAL1 = 0x1F; + } +#endif +} + +#define udd_enable_interface() (USB_CTRLA |= USB_ENABLE_bm) +#define udd_disable_interface() (USB_CTRLA &= ~USB_ENABLE_bm) +#define udd_attach_device() (USB_CTRLB |= USB_ATTACH_bm) +#define udd_detach_device() (USB_CTRLB &= ~USB_ATTACH_bm) +#define udd_gnak_disable() (USB_CTRLB &= ~USB_GNACK_bm) +#define udd_gnak_enable() (USB_CTRLB |= USB_GNACK_bm) +#define udd_gnak_is_enable() (USB_CTRLB & USB_GNACK_bm) +#define udd_set_nb_max_ep(n) (USB_CTRLA |= n) +#define udd_enable_store_frame_number() (USB_CTRLA |= USB_STFRNUM_bm) +#define udd_disable_store_frame_number() (USB_CTRLA &= ~USB_STFRNUM_bm) +#define udd_set_full_speed() (USB_CTRLA |= USB_SPEED_bm) +#define udd_set_low_speed() (USB_CTRLA &= ~USB_SPEED_bm) +#define udd_set_ep_table_addr(n) (USB.EPPTR = (uint16_t)n) +#define udd_get_ep_table_addr() (USB.EPPTR) +#define udd_get_fifo_rp() (USB_FIFORP) +#define udd_reset_fifo() (USB_FIFORP=0xFF) +#define udd_enable_interrupt(level) (USB_INTCTRLA |= level&(USB_INTLVL1_bm|USB_INTLVL0_bm)) + +#define udd_set_device_address(n) (USB_ADDR=n) +#define udd_get_device_address() (USB_ADDR) +#define udd_enable_fifo() (USB_CTRLA |= USB_FIFOEN_bm) +#define udd_disable_fifo() (USB_CTRLA &= ~USB_FIFOEN_bm) + +#define udd_send_remote_wake_up() (USB_CTRLB &= ~USB_RWAKEUP_bm, USB_CTRLB |= USB_RWAKEUP_bm) +#define udd_set_global_nack() (USB_CTRLB |= USB_GNACK_bm) +#define udd_is_crc_event() (USB_INTFLAGSASET & USB_CRCIF_bm ? true : false) +#define udd_ack_crc_event() (USB_INTFLAGSACLR = USB_CRCIF_bm) +#define udd_set_crc_event() (USB_INTFLAGSASET = USB_CRCIF_bm) +#define udd_enable_crc_interrupt() (USB_INTCTRLA |= USB_CRCIE_bm) +#define udd_disable_crc_interrupt() (USB_INTCTRLA &= ~USB_CRCIE_bm) + +#define udd_is_start_of_frame_event() (USB_INTFLAGSASET & USB_SOFIF_bm ? true : false) +#define udd_ack_start_of_frame_event() (USB_INTFLAGSACLR = USB_SOFIF_bm) +#define udd_set_start_of_frame_event() (USB_INTFLAGSASET = USB_SOFIF_bm) +#define udd_enable_start_of_frame_interrupt() (USB_INTCTRLA |= USB_SOFIE_bm) +#define udd_disable_start_of_frame_interrupt() (USB_INTCTRLA &= ~USB_SOFIE_bm) +#define udd_is_enable_start_of_frame_interrupt() (0!=(USB_INTCTRLA|USB_SOFIE_bm)) + +#define udd_is_reset_event() (USB_INTFLAGSASET & USB_RSTIF_bm ? true : false) +#define udd_ack_reset_event() (USB_INTFLAGSACLR = USB_RSTIF_bm) +#define udd_set_reset_event() (USB_INTFLAGSASET = USB_RSTIF_bm) + +#define udd_is_suspend_event() (USB_INTFLAGSASET & USB_SUSPENDIF_bm ? true : false) +#define udd_ack_suspend_event() (USB_INTFLAGSACLR = USB_SUSPENDIF_bm) +#define udd_set_suspend_event() (USB_INTFLAGSASET = USB_SUSPENDIF_bm) + +#define udd_is_resume_event() (USB_INTFLAGSASET & USB_RESUMEIF_bm ? true : false) +#define udd_ack_resume_event() (USB_INTFLAGSACLR = USB_RESUMEIF_bm) +#define udd_set_resume_event() (USB_INTFLAGSASET = USB_RESUMEIF_bm) + +#define udd_enable_busevt_interrupt() (USB_INTCTRLA |= USB_BUSEVIE_bm) +#define udd_disable_busevt_interrupt() (USB_INTCTRLA &= ~USB_BUSEVIE_bm) + +#define udd_is_setup_event() (USB_INTFLAGSBCLR & USB_SETUPIF_bm ? true : false) +#define udd_ack_setup_event() (USB_INTFLAGSBCLR = USB_SETUPIF_bm) +#define udd_set_setup_event() (USB_INTFLAGSBSET = USB_SETUPIF_bm) +#define udd_enable_setup_interrupt() (USB_INTCTRLB |= USB_SETUPIE_bm) +#define udd_disable_setup_interrupt() (USB_INTCTRLB &= ~USB_SETUPIE_bm) + +#define udd_is_tc_event() (USB_INTFLAGSBCLR & USB_TRNIF_bm ? true : false) +#define udd_ack_tc_event() (USB_INTFLAGSBCLR = USB_TRNIF_bm) +#define udd_set_tc_event() (USB_INTFLAGSBSET = USB_TRNIF_bm) +#define udd_enable_tc_interrupt() (USB_INTCTRLB |= USB_TRNIE_bm) +#define udd_disable_tc_interrupt() (USB_INTCTRLB &= ~USB_TRNIE_bm) + +#define udd_is_overflow_event() (USB_INTFLAGSASET & USB_OVFIF_bm ? true : false) +#define udd_ack_overflow_event() (USB_INTFLAGSACLR = USB_OVFIF_bm) +#define udd_set_overflow_event() (USB_INTFLAGSASET = USB_OVFIF_bm) +#define udd_enable_overflow_interrupt() (USB_INTCTRLA |= USB_BUSERRIE_bm) +#define udd_disable_overflow_interrupt() (USB_INTCTRLA &= ~USB_BUSERRIE_bm) +#define udd_is_enable_overflow_interrupt() (USB_INTCTRLA&USB_BUSERRIE_bm ? true : false) + +#define udd_is_underflow_event() (USB_INTFLAGSASET & USB_UNFIF_bm ? true : false) +#define udd_ack_underflow_event() (USB_INTFLAGSACLR = USB_UNFIF_bm) +#define udd_set_underflow_event() (USB_INTFLAGSASET = USB_UNFIF_bm) +#define udd_enable_underflow_interrupt() (USB_INTCTRLA |= USB_BUSERRIE_bm) +#define udd_disable_underflow_interrupt() (USB_INTCTRLA &= ~USB_BUSERRIE_bm) +#define udd_is_enable_underflow_interrupt() (USB_INTCTRLA&USB_BUSERRIE_bm ? true : false) + +#define udd_is_stall_event() (USB_INTFLAGSASET & USB_STALLIF_bm ? true : false) +#define udd_ack_stall_event() (USB_INTFLAGSACLR = USB_STALLIF_bm) +#define udd_set_stall_event() (USB_INTFLAGSASET = USB_STALLIF_bm) +#define udd_enable_stall_interrupt() (USB_INTCTRLA |= USB_STALLIE_bm) +#define udd_disable_stall_interrupt() (USB_INTCTRLA &= ~USB_STALLIE_bm) +#define udd_is_enable_stall_interrupt() (USB_INTCTRLA&USB_STALLIE_bm ? true : false) +//! @} + +//! @name USB Device read/modify/write management +//! @{ +#ifndef USB_WORKAROUND_DO_NOT_USE_RMW +/* + * Read modify write new instructions for Xmega + * inline asm implementation with R16 register. + * This should be removed later on when the new instructions + * will be available whithin the compiler. + * + */ +// Load and Clear +#ifdef __GNUC__ +#define LACR16(addr,msk) \ + __asm__ __volatile__ ( \ + "ldi r16, %1" "\n\t" \ + ".dc.w 0x9306" "\n\t"\ + ::"z" (addr), "M" (msk):"r16") +#else +#define LACR16(addr,msk) __lac((unsigned char)msk,(unsigned char*)addr) +#endif + +// Load and Set +#ifdef __GNUC__ +#define LASR16(addr,msk) \ + __asm__ __volatile__ ( \ + "ldi r16, %1" "\n\t" \ + ".dc.w 0x9305" "\n\t"\ + ::"z" (addr), "M" (msk):"r16") +#else +#define LASR16(addr,msk) __las((unsigned char)msk,(unsigned char*)addr) +#endif + +// Exchange +#ifdef __GNUC__ +#define XCHR16(addr,msk) \ + __asm__ __volatile__ ( \ + "ldi r16, %1" "\n\t" \ + ".dc.w 0x9304" "\n\t"\ + ::"z" (addr), "M" (msk):"r16") +#else +#define XCHR16(addr,msk) __xch(msk,addr) +#endif + +// Load and toggle +#ifdef __GNUC__ +#define LATR16(addr,msk) \ + __asm__ __volatile__ ( \ + "ldi r16, %1" "\n\t" \ + ".dc.w 0x9307" "\n\t"\ + ::"z" (addr), "M" (msk):"r16") +#else +#define LATR16(addr,msk) __lat(msk,addr) +#endif + +#else + +// Load and Clear +#define LACR16(addr,msk) (*addr &= ~msk) +// Load and Set +#define LASR16(addr,msk)(*addr |= msk) + +#endif +//! @} + + +//! @name USB Device endpoints table management +//! @{ + +#define udd_endpoint_set_control(ep_ctrl,val) (ep_ctrl->CTRL=val) +#define udd_endpoint_get_control(ep_ctrl) (ep_ctrl->CTRL) + +#define udd_endpoint_disable(ep_ctrl) udd_endpoint_set_control(ep_ctrl,0) +#define udd_endpoint_is_enable(ep_ctrl) (USB_EP_TYPE_DISABLE_gc!=udd_endpoint_get_type(ep_ctrl)) + + +#define udd_endpoint_enable_stall(ep_ctrl) (ep_ctrl->CTRL |= USB_EP_STALL_bm) +#define udd_endpoint_disable_stall(ep_ctrl) (ep_ctrl->CTRL &= ~USB_EP_STALL_bm) +#define udd_endpoint_is_stall(ep_ctrl) (ep_ctrl->CTRL &USB_EP_STALL_bm ? true : false) +#define udd_endpoint_set_multipacket(ep_ctrl) (ep_ctrl->CTRL |= USB_EP_MULTIPKT_bm) +#define udd_endpoint_TC_int_disable(ep_ctrl) (ep_ctrl->CTRL |= USB_EP_INTDSBL_bm) +#define udd_endpoint_set_pingpong(ep_ctrl) (ep_ctrl->CTRL |= USB_EP_PINGPONG_bm) +#define udd_endpoint_get_size_field(ep_ctrl) (ep_ctrl->CTRL & USB_EP_BUFSIZE_gm) +#define udd_endpoint_get_type(ep_ctrl) (ep_ctrl->CTRL & USB_EP_TYPE_gm) + +#define udd_endpoint_get_status(ep_ctrl) (ep_ctrl->STATUS) +#define udd_endpoint_clear_status(ep_ctrl) (ep_ctrl->STATUS=USB_EP_BUSNACK0_bm|USB_EP_BUSNACK1_bm) + +#define udd_endpoint_setup_received(ep_ctrl) (ep_ctrl->STATUS&USB_EP_SETUP_bm ? true : false) +#define udd_endpoint_ack_setup_received(ep_ctrl) LACR16(&ep_ctrl->STATUS, USB_EP_SETUP_bm) + +#define udd_endpoint_transfer_complete(ep_ctrl) (ep_ctrl->STATUS&USB_EP_TRNCOMPL0_bm ? true : false) +#define udd_endpoint_ack_transfer_complete(ep_ctrl) LACR16(&(ep_ctrl->STATUS), USB_EP_TRNCOMPL0_bm) +#define udd_endpoint_transfer_complete_bank0(ep_ctrl) (ep_ctrl->STATUS&USB_EP_TRNCOMPL0_bm ? true : false) +#define udd_endpoint_ack_transfer_complete_bankO(ep_ctrl) LACR16(&ep_ctrl->STATUS, USB_EP_TRNCOMPL0_bm) +#define udd_endpoint_transfer_complete_bank1(ep_ctrl) (ep_ctrl->STATUS&USB_EP_SETUP_bm ? true : false) +#define udd_endpoint_ack_transfer_complete_bank1(ep_ctrl) LACR16(&ep_ctrl->STATUS, USB_EP_SETUP_bm) + +#define udd_endpoint_get_bank(ep_ctrl) (ep_ctrl->STATUS & USB_EP_BANK_bm ? true : false) +#define udd_endpoint_set_bank(ep_ctrl) LASR16(&ep_ctrl->STATUS, USB_EP_BANK_bm) +#define udd_endpoint_clear_bank(ep_ctrl) LACR16(&ep_ctrl->STATUS, USB_EP_BANK_bm) + +#define udd_endpoint_set_dtgl(ep_ctrl) LASR16(&ep_ctrl->STATUS,USB_EP_TOGGLE_bm) +#define udd_endpoint_clear_dtgl(ep_ctrl) LACR16(&ep_ctrl->STATUS, USB_EP_TOGGLE_bm ) +#define udd_endpoint_get_dtgl(ep_ctrl) ((ep_ctrl->STATUS)&USB_EP_TOGGLE_bm ? true : false) +#define udd_endpoint_toggle_dtgl(ep_ctrl) LATR16(&ep_ctrl->STATUS, USB_EP_TOGGLE_bm) + +#define udd_endpoint_set_NACK0(ep_ctrl) LASR16(&ep_ctrl->STATUS,USB_EP_BUSNACK0_bm) +#define udd_endpoint_set_NACK1(ep_ctrl) LASR16(&ep_ctrl->STATUS,USB_EP_BUSNACK1_bm) +#define udd_endpoint_clear_NACK0(ep_ctrl) LACR16(&ep_ctrl->STATUS, USB_EP_BUSNACK0_bm) +#define udd_endpoint_clear_NACK1(ep_ctrl) LACR16(&ep_ctrl->STATUS, USB_EP_BUSNACK1_bm) +#define udd_endpoint_get_NACK1(ep_ctrl) ((ep_ctrl->STATUS&USB_EP_BUSNACK1_bm) ? true : false) +#define udd_endpoint_get_NACK0(ep_ctrl) ((ep_ctrl->STATUS&USB_EP_BUSNACK0_bm) ? true : false) +#define udd_endpoint_overflow(ep_ctrl) (ep_ctrl->STATUS&USB_EP_OVF_bm ? true : false) +#define udd_endpoint_underflow(ep_ctrl) (ep_ctrl->STATUS&USB_EP_UNF_bm ? true : false) + +#define UDD_ENDPOINT_MAX_TRANS (0x3FF) + +#define udd_endpoint_out_nb_receiv(ep_ctrl) (ep_ctrl->CNT) +#define udd_endpoint_out_reset_nb_received(ep_ctrl) (ep_ctrl->CNT = 0) +#define udd_endpoint_in_set_bytecnt(ep_ctrl,n) (ep_ctrl->CNT = n) +#define udd_endpoint_set_azlp(ep_ctrl) (ep_ctrl->CNT |= 0x8000) +#define udd_endpoint_clear_azlp(ep_ctrl) (ep_ctrl->CNT &= ~0x8000) + +#define udd_endpoint_set_buf(ep_ctrl,buf) (ep_ctrl->DATAPTR = (uint16_t) buf) + +#define udd_endpoint_in_nb_sent(ep_ctrl) (ep_ctrl->AUXDATA) +#define udd_endpoint_in_reset_nb_sent(ep_ctrl) (ep_ctrl->AUXDATA = 0) +#define udd_endpoint_out_set_nbbyte(ep_ctrl,nb) (ep_ctrl->AUXDATA = nb) +#define udd_endpoint_out_get_nbbyte_requested(ep_ctrl) (ep_ctrl->AUXDATA) +#define udd_endpoint_set_aux(ep_ctrl,buf) (ep_ctrl->AUXDATA = (uint16_t) buf) +//! @} + + +//! @name USB Device endpoint control field management +//! @{ + +//! @name USB Device endpoint control setup field management +//! @{ +#define udd_control_setup() (udd_sram.ep_ctrl[0].STATUS&USB_EP_SETUP_bm ? true : false) +#define udd_control_ack_setup() LACR16(&udd_sram.ep_ctrl[0].STATUS,USB_EP_SETUP_bm) +//! @} + +//! @name USB Device endpoint control OUT field management +//! @{ +#define udd_control_out_is_enable_stall() (udd_sram.ep_ctrl[0].CTRL&USB_EP_STALL_bm ? true : false) +#define udd_control_out_enable_stall() LASR16(&udd_sram.ep_ctrl[0].CTRL,USB_EP_STALL_bm) +#define udd_control_out_disable_stall() LACR16(&udd_sram.ep_ctrl[0].CTRL,USB_EP_STALL_bm) +#define udd_control_out_is_stalled() (udd_sram.ep_ctrl[0].STATUS&USB_EP_STALLF_bm ? true : false) +#define udd_control_out_ack_stall() LACR16(&udd_sram.ep_ctrl[0].STATUS,USB_EP_STALLF_bm) +#define udd_control_out_set_NACK0() LASR16(&udd_sram.ep_ctrl[0].STATUS,USB_EP_BUSNACK0_bm) +#define udd_control_out_clear_NACK0() LACR16(&udd_sram.ep_ctrl[0].STATUS,USB_EP_BUSNACK0_bm) + +#define udd_control_out_overflow() (udd_sram.ep_ctrl[0].STATUS&USB_EP_OVF_bm ? true : false) +#define udd_control_ack_out_overflow() LACR16(&udd_sram.ep_ctrl[0].STATUS,USB_EP_OVF_bm) + +#define udd_control_out_tc() (udd_sram.ep_ctrl[0].STATUS&USB_EP_TRNCOMPL0_bm ? true : false) +#define udd_control_out_ack_tc() LACR16(&udd_sram.ep_ctrl[0].STATUS,USB_EP_TRNCOMPL0_bm) +#define udd_control_out_set_tc() LASR16(&udd_sram.ep_ctrl[0].STATUS,USB_EP_TRNCOMPL0_bm) + +#define udd_control_out_dt_get() (udd_sram.ep_ctrl[0].STATUS&USB_EP_TOGGLE_bm ? true : false) +#define udd_control_out_dt_set() LASR16(&udd_sram.ep_ctrl[0].STATUS,USB_EP_TOGGLE_bm ) +#define udd_control_out_dt_clear() LACR16(&udd_sram.ep_ctrl[0].STATUS,USB_EP_TOGGLE_bm ) +#define udd_control_out_dt_toggle() LATR16(&udd_sram.ep_ctrl[0].STATUS,USB_EP_TOGGLE_bm) + +#define udd_control_out_set_buf(buf) (udd_sram.ep_ctrl[0].DATAPTR = (uint16_t) buf) + +#define udd_control_out_get_bytecnt() (udd_sram.ep_ctrl[0].CNT) +//! @} + +//! @name USB Device endpoint control IN field management +//! @{ +#define udd_control_in_is_enable_stall() (udd_sram.ep_ctrl[1].CTRL&USB_EP_STALL_bm ? true : false) +#define udd_control_in_enable_stall() LASR16(&udd_sram.ep_ctrl[1].CTRL,USB_EP_STALL_bm) +#define udd_control_in_disable_stall() LACR16(&udd_sram.ep_ctrl[1].CTRL,USB_EP_STALL_bm) +#define udd_control_in_is_stalled() (udd_sram.ep_ctrl[1].STATUS&USB_EP_STALLF_bm ? true : false) +#define udd_control_in_ack_stall() LACR16(&udd_sram.ep_ctrl[1].STATUS,USB_EP_STALLF_bm) +#define udd_control_in_set_NACK0() LASR16(&udd_sram.ep_ctrl[1].STATUS,USB_EP_BUSNACK0_bm) +#define udd_control_in_clear_NACK0() LACR16(&udd_sram.ep_ctrl[1].STATUS,USB_EP_BUSNACK0_bm) + +#define udd_control_in_underflow() (udd_sram.ep_ctrl[1].STATUS&USB_EP_UNF_bm ? true : false) +#define udd_control_ack_in_underflow() LACR16(&udd_sram.ep_ctrl[1].STATUS,USB_EP_UNF_bm) + +#define udd_control_in_tc() (udd_sram.ep_ctrl[1].STATUS&USB_EP_TRNCOMPL0_bm ? true : false) +#define udd_control_in_ack_tc() LACR16(&udd_sram.ep_ctrl[1].STATUS,USB_EP_TRNCOMPL0_bm) +#define udd_control_in_set_tc() LASR16(&udd_sram.ep_ctrl[1].STATUS,USB_EP_TRNCOMPL0_bm) + +#define udd_control_in_dt_get() (udd_sram.ep_ctrl[1].STATUS&USB_EP_TOGGLE_bm ? true : false) +#define udd_control_in_dt_set() LASR16(&udd_sram.ep_ctrl[1].STATUS,USB_EP_TOGGLE_bm ) +#define udd_control_in_dt_clear() LACR16(&udd_sram.ep_ctrl[1].STATUS,USB_EP_TOGGLE_bm ) +#define udd_control_in_dt_toggle() LATR16(&udd_sram.ep_ctrl[1].STATUS,USB_EP_TOGGLE_bm) + +#define udd_control_in_set_buf(buf) (udd_sram.ep_ctrl[1].DATAPTR = (uint16_t) buf) + +#define udd_control_in_set_bytecnt(n) (udd_sram.ep_ctrl[1].CNT = n) +//! @} +//! @} + +//! @} + +#endif // _USB_DEVICE_H_ diff --git a/DSTAT1/src/asf/xmega/utils/assembler.h b/DSTAT1/src/asf/xmega/utils/assembler.h new file mode 100644 index 0000000000000000000000000000000000000000..31165a486523b87e3d65e4bedbb124cfb8d2e3f4 --- /dev/null +++ b/DSTAT1/src/asf/xmega/utils/assembler.h @@ -0,0 +1,154 @@ +/** + * \file + * + * \brief Assembler abstraction layer and utilities + * + * Copyright (c) 2009 Atmel Corporation. All rights reserved. + * + * \asf_license_start + * + * 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. The name of Atmel may not be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * 4. This software may only be redistributed and used in connection with an + * Atmel microcontroller product. + * + * THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE + * EXPRESSLY AND SPECIFICALLY DISCLAIMED. IN NO EVENT SHALL ATMEL 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. + * + * \asf_license_stop + * + */ +#ifndef ASSEMBLER_H_INCLUDED +#define ASSEMBLER_H_INCLUDED + +#if !defined(__ASSEMBLER__) && !defined(__IAR_SYSTEMS_ASM__) \ + && !defined(__DOXYGEN__) +# error This file may only be included from assembly files +#endif + +#if defined(__ASSEMBLER__) +# include "assembler/gas.h" +# include +#elif defined(__IAR_SYSTEMS_ASM__) +# include "assembler/iar.h" +# include +#endif + +/** + * \ingroup group_xmega_utils + * \defgroup assembler_group Assembler Support + * + * This group provides a good handful of macros intended to smooth out + * the differences between various assemblers, similar to what compiler.h does + * for compilers, except that assemblers tend to be much less standardized than + * compilers. + * + * @{ + */ + +//! \name Control Statements +//@{ +/** + * \def REPEAT(count) + * \brief Repeat the following statements \a count times + */ +/** + * \def END_REPEAT() + * \brief Mark the end of the statements to be repeated + */ +/** + * \def SET_LOC(offset) + * \brief Set the location counter to \a offset + */ +/** + * \def END_FILE() + * \brief Mark the end of the file + */ +//@} + +//! \name Data Objects +//@{ +/** + * \def FILL_BYTES(count) + * \brief Allocate space for \a count bytes + */ +//@} + +//! \name Symbol Definition +//@{ +/** + * \def L(name) + * \brief Turn \a name into a local symbol, if possible + */ +/** + * \def EXTERN_SYMBOL(name) + * \brief Declare \a name as an external symbol referenced by this file + */ +/** + * \def FUNCTION(name) + * \brief Define a file-local function called \a name + */ +/** + * \def PUBLIC_FUNCTION(name) + * \brief Define a globally visible function called \a name + */ +/** + * \def WEAK_FUNCTION(name) + * \brief Define a weak function called \a name + * + * Weak functions are only referenced if no strong definitions are found + */ +/** + * \def WEAK_FUNCTION_ALIAS(name, strong_name) + * \brief Define \a name as a weak alias for the function \a strong_name + * \sa WEAK_FUNCTION + */ +/** + * \def END_FUNC(name) + * \brief Mark the end of the function called \a name + */ +//@} + +//! \name Section Definition +//@{ +/** + * \def TEXT_SECTION(name) + * \brief Start a new section containing executable code + */ +/** + * \def RODATA_SECTION(name) + * \brief Start a new section containing read-only data + */ +/** + * \def DATA_SECTION(name) + * \brief Start a new section containing writeable initialized data + */ +/** + * \def BSS_SECTION(name) + * \brief Start a new section containing writeable zero-initialized data + */ +//@} + +//! @} + +#endif /* ASSEMBLER_H_INCLUDED */ diff --git a/DSTAT1/src/asf/xmega/utils/assembler/gas.h b/DSTAT1/src/asf/xmega/utils/assembler/gas.h new file mode 100644 index 0000000000000000000000000000000000000000..fa0505098518f15cdaab281c5bbe0541ac277b29 --- /dev/null +++ b/DSTAT1/src/asf/xmega/utils/assembler/gas.h @@ -0,0 +1,119 @@ +/** + * \file + * + * \brief Assembler abstraction layer: GNU Assembler specifics + * + * Copyright (c) 2009 Atmel Corporation. All rights reserved. + * + * \asf_license_start + * + * 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. The name of Atmel may not be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * 4. This software may only be redistributed and used in connection with an + * Atmel microcontroller product. + * + * THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE + * EXPRESSLY AND SPECIFICALLY DISCLAIMED. IN NO EVENT SHALL ATMEL 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. + * + * \asf_license_stop + * + */ +#ifndef ASSEMBLER_GAS_H_INCLUDED +#define ASSEMBLER_GAS_H_INCLUDED + +#ifndef __DOXYGEN__ + + /* IAR doesn't accept dots in macro names */ + .macro ld_addr, reg, sym + lda.w \reg, \sym + .endm + + /* Define a function \a name that is either globally visible or only + * file-local. + */ + .macro gas_begin_func name, is_public + .if \is_public + .global \name + .endif + .section .text.\name, "ax", @progbits + .type \name, @function + \name : + .endm + + /* Define a function \a name that is either globally visible or only + * file-local in a given segment. + */ + .macro gas_begin_func_segm name, is_public, segment + .if \is_public + .global \name + .endif + .section .\segment, "ax", @progbits + .type \name, @function + \name : + .endm + + /* Define \a name as a weak alias for the function \a strong_name */ + .macro gas_weak_function_alias name, strong_name + .global \name + .weak \name + .type \name, @function + .set \name, \strong_name + .endm + + /* Define a weak function called \a name */ + .macro gas_weak_function name + .weak \name + gas_begin_func \name 1 + .endm + +#define REPEAT(count) .rept count +#define END_REPEAT() .endr +#define FILL_BYTES(count) .fill count +#define SET_LOC(offset) .org offset +#define L(name) .L##name +#define EXTERN_SYMBOL(name) + +#define TEXT_SECTION(name) \ + .section name, "ax", @progbits +#define RODATA_SECTION(name) \ + .section name, "a", @progbits +#define DATA_SECTION(name) \ + .section name, "aw", @progbits +#define BSS_SECTION(name) \ + .section name, "aw", @nobits + +#define FUNCTION(name) gas_begin_func name 0 +#define PUBLIC_FUNCTION(name) gas_begin_func name 1 +#define PUBLIC_FUNCTION_SEGMENT(name, segment) \ + gas_begin_func_segm name 1 segment +#define WEAK_FUNCTION(name) gas_weak_function name +#define WEAK_FUNCTION_ALIAS(name, strong_name) \ + gas_weak_function_alias name strong_name +#define END_FUNC(name) \ + .size name, . - name + +#define END_FILE() + +#endif /* __DOXYGEN__ */ + +#endif /* ASSEMBLER_GAS_H_INCLUDED */ diff --git a/DSTAT1/src/asf/xmega/utils/bit_handling/clz_ctz.h b/DSTAT1/src/asf/xmega/utils/bit_handling/clz_ctz.h new file mode 100644 index 0000000000000000000000000000000000000000..90c5bfdb968e99586ff8c6e8706d291b7378abac --- /dev/null +++ b/DSTAT1/src/asf/xmega/utils/bit_handling/clz_ctz.h @@ -0,0 +1,210 @@ +/** + * \file + * + * \brief CLZ/CTZ C implemetation. + * + * Copyright (c) 2009 Atmel Corporation. All rights reserved. + * + * \asf_license_start + * + * 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. The name of Atmel may not be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * 4. This software may only be redistributed and used in connection with an + * Atmel microcontroller product. + * + * THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE + * EXPRESSLY AND SPECIFICALLY DISCLAIMED. IN NO EVENT SHALL ATMEL 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. + * + * \asf_license_stop + * + */ +#ifndef CLZ_CTH_H +#define CLZ_CTH_H + +/** + * \brief Count leading zeros in unsigned integer + * + * This macro takes unsigned integers of any size, and evaluates to a call to + * the clz-function for its size. These functions count the number of zeros, + * starting with the MSB, before a one occurs in the integer. + * + * \param x Unsigned integer to count the leading zeros in. + * + * \return The number of leading zeros in \a x. + */ +#define clz(x) compiler_demux_size(sizeof(x), clz, (x)) + +/** + * \internal + * \brief Count leading zeros in unsigned, 8-bit integer + * + * \param x Unsigned byte to count the leading zeros in. + * + * \return The number of leading zeros in \a x. + */ +__always_inline static uint8_t clz8(uint8_t x) +{ + uint8_t bit = 0; + + if (x & 0xf0) { + x >>= 4; + } else { + bit += 4; + } + + if (x & 0x0c) { + x >>= 2; + } else { + bit += 2; + } + + if (!(x & 0x02)) { + bit++; + } + + return bit; + +} + +/** + * \internal + * \brief Count leading zeros in unsigned, 16-bit integer + * + * \param x Unsigned word to count the leading zeros in. + * + * \return The number of leading zeros in \a x. + */ +__always_inline static uint8_t clz16(uint16_t x) +{ + uint8_t bit = 0; + + if (x & 0xff00) { + x >>= 8; + } else { + bit += 8; + } + + return bit + clz8(x); +} + +/** + * \internal + * \brief Count leading zeros in unsigned, 32-bit integer + * + * \param x Unsigned double word to count the leading zeros in. + * + * \return The number of leading zeros in \a x. + */ +__always_inline static uint8_t clz32(uint32_t x) +{ + uint8_t bit = 0; + + if (x & 0xffff0000) { + x >>= 16; + } else { + bit += 16; + } + + return bit + clz16(x); +} + +/** + * \brief Count trailing zeros in unsigned integer + * + * This macro takes unsigned integers of any size, and evaluates to a call to + * the ctz-function for its size. These functions count the number of zeros, + * starting with the LSB, before a one occurs in the integer. + * + * \param x Unsigned integer to count the trailing zeros in. + * + * \return The number of trailing zeros in \a x. + */ +#define ctz(x) compiler_demux_size(sizeof(x), ctz, (x)) + +/** + * \internal + * \brief Count trailing zeros in unsigned, 8-bit integer + * + * \param x Unsigned byte to count the trailing zeros in. + * + * \return The number of leading zeros in \a x. + */ +__always_inline static uint8_t ctz8(uint8_t x) +{ + uint8_t bit = 0; + + if (!(x & 0x0f)) { + bit += 4; + x >>= 4; + } + if (!(x & 0x03)) { + bit += 2; + x >>= 2; + } + if (!(x & 0x01)) + bit++; + + return bit; +} + +/** + * \internal + * \brief Count trailing zeros in unsigned, 16-bit integer + * + * \param x Unsigned word to count the trailing zeros in. + * + * \return The number of trailing zeros in \a x. + */ +__always_inline static uint8_t ctz16(uint16_t x) +{ + uint8_t bit = 0; + + if (!(x & 0x00ff)) { + bit += 8; + x >>= 8; + } + + return bit + ctz8(x); +} + +/** + * \internal + * \brief Count trailing zeros in unsigned, 32-bit integer + * + * \param x Unsigned double word to count the trailing zeros in. + * + * \return The number of trailing zeros in \a x. + */ +__always_inline static uint8_t ctz32(uint32_t x) +{ + uint8_t bit = 0; + + if (!(x & 0x0000ffff)) { + bit += 16; + x >>= 16; + } + + return bit + ctz16(x); +} + +#endif /* CLZ_CTZ_H */ diff --git a/DSTAT1/src/asf/xmega/utils/compiler.h b/DSTAT1/src/asf/xmega/utils/compiler.h new file mode 100644 index 0000000000000000000000000000000000000000..c2dbb00483b5405ec347e48b81d4c78c17397a9e --- /dev/null +++ b/DSTAT1/src/asf/xmega/utils/compiler.h @@ -0,0 +1,1023 @@ +/** + * \file + * + * \brief Commonly used includes, types and macros. + * + * Copyright (c) 2010-2011 Atmel Corporation. All rights reserved. + * + * \asf_license_start + * + * 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. The name of Atmel may not be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * 4. This software may only be redistributed and used in connection with an + * Atmel microcontroller product. + * + * THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE + * EXPRESSLY AND SPECIFICALLY DISCLAIMED. IN NO EVENT SHALL ATMEL 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. + * + * \asf_license_stop + * + */ +#ifndef UTILS_COMPILER_H +#define UTILS_COMPILER_H + +/** + * \defgroup group_xmega_utils XMEGA compiler driver + * + * Compiler abstraction layer and code utilities for 8-bit AVR. + * This module provides various abstraction layers and utilities to make code compatible between different compilers. + * + * \{ + */ + +#if defined(__GNUC__) +# include +# include +#elif defined(__ICCAVR__) +# include +# include +#else +# error Unsupported compiler. +#endif + +#include +#include +#include +#include + +#ifdef __ICCAVR__ +/*! \name Compiler Keywords + * + * Port of some keywords from GCC to IAR Embedded Workbench. + */ +//! @{ +#define __asm__ asm +#define __inline__ inline +#define __volatile__ +//! @} +#endif + +/** + * \def barrier + * \brief Memory barrier + */ +#ifdef __GNUC__ +# define barrier() asm volatile("" ::: "memory") +#else +# define barrier() asm ("") +#endif + +/** + * \brief Emit the compiler pragma \a arg. + * + * \param arg The pragma directive as it would appear after \e \#pragma + * (i.e. not stringified). + */ +#define COMPILER_PRAGMA(arg) _Pragma(#arg) + +/* + * AVR arch does not care about alignment anyway. + */ +#define COMPILER_PACK_RESET(alignment) +#define COMPILER_PACK_SET(alignment) + +/** + * \brief Set aligned boundary. + */ +#if (defined __GNUC__) +#define COMPILER_ALIGNED(a) __attribute__((__aligned__(a))) +#elif (defined __ICCAVR__) +#define COMPILER_ALIGNED(a) COMPILER_PRAGMA(data_alignment = a) +#endif + +/** + * \brief Set word-aligned boundary. + */ +#if (defined __GNUC__) +#define COMPILER_WORD_ALIGNED __attribute__((__aligned__(2))) +#elif (defined __ICCAVR__) +#define COMPILER_WORD_ALIGNED COMPILER_PRAGMA(data_alignment = 2) +#endif + +/** + * \name Tag functions as deprecated + * + * Tagging a function as deprecated will produce a warning when and only + * when the function is called. + * + * Usage is to add the __DEPRECATED__ symbol before the function definition. + * E.g.: + * __DEPRECATED__ uint8_t some_deprecated_function (void) + * { + * ... + * } + * + * \note Only supported by GCC 3.1 and above, no IAR support + * @{ + */ +#if ((defined __GNUC__) && (__GNUC__ > 3 || (__GNUC__ == 3 && __GNUC_MINOR__ >=1))) +#define __DEPRECATED__ __attribute__((__deprecated__)) +#else +#define __DEPRECATED__ +#endif +//! @} + +/*! \name Usual Types + */ +//! @{ +typedef unsigned char Bool; //!< Boolean. +#ifndef __cplusplus +#if !defined(__bool_true_false_are_defined) +typedef unsigned char bool; //!< Boolean. +#endif +#endif +typedef signed char S8 ; //!< 8-bit signed integer. +typedef unsigned char U8 ; //!< 8-bit unsigned integer. +typedef signed short int S16; //!< 16-bit signed integer. +typedef unsigned short int U16; //!< 16-bit unsigned integer. +typedef unsigned short int le16_t; +typedef unsigned short int be16_t; +typedef signed long int S32; //!< 32-bit signed integer. +typedef unsigned long int U32; //!< 32-bit unsigned integer. +typedef uint32_t le32_t; +typedef uint32_t be32_t; +typedef signed long long int S64; //!< 64-bit signed integer. +typedef unsigned long long int U64; //!< 64-bit unsigned integer. +typedef float F32; //!< 32-bit floating-point number. +typedef double F64; //!< 64-bit floating-point number. +typedef uint16_t iram_size_t; +//! @} + + +/*! \name Status Types + */ +//! @{ +typedef Bool Status_bool_t; //!< Boolean status. +typedef U8 Status_t; //!< 8-bit-coded status. +//! @} + + +/*! \name Aliasing Aggregate Types + */ +//! @{ + +//! 16-bit union. +typedef union +{ + S16 s16 ; + U16 u16 ; + S8 s8 [2]; + U8 u8 [2]; +} Union16; + +//! 32-bit union. +typedef union +{ + S32 s32 ; + U32 u32 ; + S16 s16[2]; + U16 u16[2]; + S8 s8 [4]; + U8 u8 [4]; +} Union32; + +//! 64-bit union. +typedef union +{ + S64 s64 ; + U64 u64 ; + S32 s32[2]; + U32 u32[2]; + S16 s16[4]; + U16 u16[4]; + S8 s8 [8]; + U8 u8 [8]; +} Union64; + +//! Union of pointers to 64-, 32-, 16- and 8-bit unsigned integers. +typedef union +{ + S64 *s64ptr; + U64 *u64ptr; + S32 *s32ptr; + U32 *u32ptr; + S16 *s16ptr; + U16 *u16ptr; + S8 *s8ptr ; + U8 *u8ptr ; +} UnionPtr; + +//! Union of pointers to volatile 64-, 32-, 16- and 8-bit unsigned integers. +typedef union +{ + volatile S64 *s64ptr; + volatile U64 *u64ptr; + volatile S32 *s32ptr; + volatile U32 *u32ptr; + volatile S16 *s16ptr; + volatile U16 *u16ptr; + volatile S8 *s8ptr ; + volatile U8 *u8ptr ; +} UnionVPtr; + +//! Union of pointers to constant 64-, 32-, 16- and 8-bit unsigned integers. +typedef union +{ + const S64 *s64ptr; + const U64 *u64ptr; + const S32 *s32ptr; + const U32 *u32ptr; + const S16 *s16ptr; + const U16 *u16ptr; + const S8 *s8ptr ; + const U8 *u8ptr ; +} UnionCPtr; + +//! Union of pointers to constant volatile 64-, 32-, 16- and 8-bit unsigned integers. +typedef union +{ + const volatile S64 *s64ptr; + const volatile U64 *u64ptr; + const volatile S32 *s32ptr; + const volatile U32 *u32ptr; + const volatile S16 *s16ptr; + const volatile U16 *u16ptr; + const volatile S8 *s8ptr ; + const volatile U8 *u8ptr ; +} UnionCVPtr; + +//! Structure of pointers to 64-, 32-, 16- and 8-bit unsigned integers. +typedef struct +{ + S64 *s64ptr; + U64 *u64ptr; + S32 *s32ptr; + U32 *u32ptr; + S16 *s16ptr; + U16 *u16ptr; + S8 *s8ptr ; + U8 *u8ptr ; +} StructPtr; + +//! Structure of pointers to volatile 64-, 32-, 16- and 8-bit unsigned integers. +typedef struct +{ + volatile S64 *s64ptr; + volatile U64 *u64ptr; + volatile S32 *s32ptr; + volatile U32 *u32ptr; + volatile S16 *s16ptr; + volatile U16 *u16ptr; + volatile S8 *s8ptr ; + volatile U8 *u8ptr ; +} StructVPtr; + +//! Structure of pointers to constant 64-, 32-, 16- and 8-bit unsigned integers. +typedef struct +{ + const S64 *s64ptr; + const U64 *u64ptr; + const S32 *s32ptr; + const U32 *u32ptr; + const S16 *s16ptr; + const U16 *u16ptr; + const S8 *s8ptr ; + const U8 *u8ptr ; +} StructCPtr; + +//! Structure of pointers to constant volatile 64-, 32-, 16- and 8-bit unsigned integers. +typedef struct +{ + const volatile S64 *s64ptr; + const volatile U64 *u64ptr; + const volatile S32 *s32ptr; + const volatile U32 *u32ptr; + const volatile S16 *s16ptr; + const volatile U16 *u16ptr; + const volatile S8 *s8ptr ; + const volatile U8 *u8ptr ; +} StructCVPtr; + +//! @} + + +//_____ M A C R O S ________________________________________________________ + +/*! \name Usual Constants + */ +//! @{ +#define DISABLE 0 +#define ENABLE 1 +#ifndef __cplusplus +#if !defined(__bool_true_false_are_defined) +#define false 0 +#define true 1 +#endif +#endif +#define PASS 0 +#define FAIL 1 +#define LOW 0 +#define HIGH 1 +//! @} + + +//! \name Compile time error handling +//@{ + +/** + * \internal + * \def ERROR_FUNC(name, msg) + * \brief Fail compilation if function call isn't eliminated + * + * If the compiler fails to optimize away all calls to the function \a + * name, terminate compilation and display \a msg to the user. + * + * \note Not all compilers support this, so this is best-effort only. + * Sometimes, there may be a linker error instead, and when optimization + * is disabled, this mechanism will be completely disabled. + */ +#ifndef ERROR_FUNC +# define ERROR_FUNC(name, msg) \ + extern int name(void) +#endif + +//@} + +//! \name Function call demultiplexing +//@{ + +//! Error function for failed demultiplexing. +ERROR_FUNC(compiler_demux_bad_size, "Invalid parameter size"); + +/** + * \internal + * \brief Demultiplex function call based on size of datatype + * + * Evaluates to a function call to a function name with suffix 8, 16 or 32 + * depending on the size of the datatype. Any number of parameters can be + * passed to the function. + * + * Usage: + * \code + * void foo8(uint8_t a, void *b); + * void foo16(uint16_t a, void *b); + * void foo32(uint32_t a, void *b); + * + * #define foo(x, y) compiler_demux_size(sizeof(x), foo, x, y) + * \endcode + * + * \param size Size of the datatype. + * \param func Base function name. + * \param ... List of parameters to pass to the function. + */ +#define compiler_demux_size(size, func, ...) \ + (((size) == 1) ? func##8(__VA_ARGS__) : \ + ((size) == 2) ? func##16(__VA_ARGS__) : \ + ((size) == 4) ? func##32(__VA_ARGS__) : \ + compiler_demux_bad_size()) + +//@} + +/** + * \def __always_inline + * \brief The function should always be inlined. + * + * This annotation instructs the compiler to ignore its inlining + * heuristics and inline the function no matter how big it thinks it + * becomes. + */ +#if (defined __GNUC__) + #define __always_inline inline __attribute__((__always_inline__)) +#elif (defined __ICCAVR__) + #define __always_inline _Pragma("inline=forced") +#endif + +//! \name Optimization Control +//@{ + +/** + * \def __always_optimize + * \brief The function should always be optimized. + * + * This annotation instructs the compiler to ignore global optimization + * settings and always compile the function with a high level of + * optimization. + */ +#if (defined __GNUC__) + #define __always_optimize __attribute__((optimize(3))) +#elif (defined __ICCAVR__) + #define __always_optimize _Pragma("optimize=high") +#endif + +/** + * \def likely(exp) + * \brief The expression \a exp is likely to be true + */ +#ifndef likely +# define likely(exp) (exp) +#endif + +/** + * \def unlikely(exp) + * \brief The expression \a exp is unlikely to be true + */ +#ifndef unlikely +# define unlikely(exp) (exp) +#endif + +/** + * \def is_constant(exp) + * \brief Determine if an expression evaluates to a constant value. + * + * \param exp Any expression + * + * \return true if \a exp is constant, false otherwise. + */ +#ifdef __GNUC__ +# define is_constant(exp) __builtin_constant_p(exp) +#else +# define is_constant(exp) (0) +#endif + +//! @} + +/*! \name Bit-Field Handling + */ +#include "bit_handling/clz_ctz.h" +//! @{ + +/*! \brief Reads the bits of a value specified by a given bit-mask. + * + * \param value Value to read bits from. + * \param mask Bit-mask indicating bits to read. + * + * \return Read bits. + */ +#define Rd_bits( value, mask) ((value)&(mask)) + +/*! \brief Writes the bits of a C lvalue specified by a given bit-mask. + * + * \param lvalue C lvalue to write bits to. + * \param mask Bit-mask indicating bits to write. + * \param bits Bits to write. + * + * \return Resulting value with written bits. + */ +#define Wr_bits(lvalue, mask, bits) ((lvalue) = ((lvalue) & ~(mask)) |\ + ((bits ) & (mask))) + +/*! \brief Tests the bits of a value specified by a given bit-mask. + * + * \param value Value of which to test bits. + * \param mask Bit-mask indicating bits to test. + * + * \return \c 1 if at least one of the tested bits is set, else \c 0. + */ +#define Tst_bits( value, mask) (Rd_bits(value, mask) != 0) + +/*! \brief Clears the bits of a C lvalue specified by a given bit-mask. + * + * \param lvalue C lvalue of which to clear bits. + * \param mask Bit-mask indicating bits to clear. + * + * \return Resulting value with cleared bits. + */ +#define Clr_bits(lvalue, mask) ((lvalue) &= ~(mask)) + +/*! \brief Sets the bits of a C lvalue specified by a given bit-mask. + * + * \param lvalue C lvalue of which to set bits. + * \param mask Bit-mask indicating bits to set. + * + * \return Resulting value with set bits. + */ +#define Set_bits(lvalue, mask) ((lvalue) |= (mask)) + +/*! \brief Toggles the bits of a C lvalue specified by a given bit-mask. + * + * \param lvalue C lvalue of which to toggle bits. + * \param mask Bit-mask indicating bits to toggle. + * + * \return Resulting value with toggled bits. + */ +#define Tgl_bits(lvalue, mask) ((lvalue) ^= (mask)) + +/*! \brief Reads the bit-field of a value specified by a given bit-mask. + * + * \param value Value to read a bit-field from. + * \param mask Bit-mask indicating the bit-field to read. + * + * \return Read bit-field. + */ +#define Rd_bitfield( value,mask) (Rd_bits( value, (uint32_t)mask) >> ctz(mask)) + +/*! \brief Writes the bit-field of a C lvalue specified by a given bit-mask. + * + * \param lvalue C lvalue to write a bit-field to. + * \param mask Bit-mask indicating the bit-field to write. + * \param bitfield Bit-field to write. + * + * \return Resulting value with written bit-field. + */ +#define Wr_bitfield(lvalue, mask, bitfield) (Wr_bits(lvalue, mask, (uint32_t)(bitfield) << ctz(mask))) + +//! @} + + +/*! \brief This macro is used to test fatal errors. + * + * The macro tests if the expression is false. If it is, a fatal error is + * detected and the application hangs up. If TEST_SUITE_DEFINE_ASSERT_MACRO + * is defined, a unit test version of the macro is used, to allow execution + * of further tests after a false expression. + * + * \param expr Expression to evaluate and supposed to be nonzero. + */ +#if defined(_ASSERT_ENABLE_) +# if defined(TEST_SUITE_DEFINE_ASSERT_MACRO) + // Assert() is defined in unit_test/suite.h +# include "unit_test/suite.h" +# else +# define Assert(expr) \ + {\ + if (!(expr)) while (true);\ + } +# endif +#else +# define Assert(expr) ((void) 0) +#endif + +/*! \name Bit Reversing + */ +//! @{ + +/*! \brief Reverses the bits of \a u8. + * + * \param u8 U8 of which to reverse the bits. + * + * \return Value resulting from \a u8 with reversed bits. + */ +#define bit_reverse8(u8) ((U8)(bit_reverse32((U8)(u8)) >> 24)) + +/*! \brief Reverses the bits of \a u16. + * + * \param u16 U16 of which to reverse the bits. + * + * \return Value resulting from \a u16 with reversed bits. + */ +#define bit_reverse16(u16) ((U16)(bit_reverse32((U16)(u16)) >> 16)) + +/*! \brief Reverses the bits of \a u32. + * + * \param u32 U32 of which to reverse the bits. + * + * \return Value resulting from \a u32 with reversed bits. + */ +#if (defined __GNUC__) + #define bit_reverse32(u32) \ + (\ + {\ + unsigned int __value = (U32)(u32);\ + __asm__ ("brev\t%0" : "+r" (__value) : : "cc");\ + (U32)__value;\ + }\ + ) +#elif (defined __ICCAVR__) + #define bit_reverse32(u32) ((U32)__bit_reverse((U32)(u32))) +#endif + +/*! \brief Reverses the bits of \a u64. + * + * \param u64 U64 of which to reverse the bits. + * + * \return Value resulting from \a u64 with reversed bits. + */ +#define bit_reverse64(u64) ((U64)(((U64)bit_reverse32((U64)(u64) >> 32)) |\ + ((U64)bit_reverse32((U64)(u64)) << 32))) + +//! @} + +//! \name Logarithmic functions +//! @{ + +/** + * \internal + * Undefined function. Will cause a link failure if ilog2() is called + * with an invalid constant value. + */ +int_fast8_t ilog2_undefined(void); + +/** + * \brief Calculate the base-2 logarithm of a number rounded down to + * the nearest integer. + * + * \param x A 32-bit value + * \return The base-2 logarithm of \a x, or -1 if \a x is 0. + */ +static inline int_fast8_t ilog2(uint32_t x) +{ + if (is_constant(x)) + return ((x) & (1ULL << 31) ? 31 : + (x) & (1ULL << 30) ? 30 : + (x) & (1ULL << 29) ? 29 : + (x) & (1ULL << 28) ? 28 : + (x) & (1ULL << 27) ? 27 : + (x) & (1ULL << 26) ? 26 : + (x) & (1ULL << 25) ? 25 : + (x) & (1ULL << 24) ? 24 : + (x) & (1ULL << 23) ? 23 : + (x) & (1ULL << 22) ? 22 : + (x) & (1ULL << 21) ? 21 : + (x) & (1ULL << 20) ? 20 : + (x) & (1ULL << 19) ? 19 : + (x) & (1ULL << 18) ? 18 : + (x) & (1ULL << 17) ? 17 : + (x) & (1ULL << 16) ? 16 : + (x) & (1ULL << 15) ? 15 : + (x) & (1ULL << 14) ? 14 : + (x) & (1ULL << 13) ? 13 : + (x) & (1ULL << 12) ? 12 : + (x) & (1ULL << 11) ? 11 : + (x) & (1ULL << 10) ? 10 : + (x) & (1ULL << 9) ? 9 : + (x) & (1ULL << 8) ? 8 : + (x) & (1ULL << 7) ? 7 : + (x) & (1ULL << 6) ? 6 : + (x) & (1ULL << 5) ? 5 : + (x) & (1ULL << 4) ? 4 : + (x) & (1ULL << 3) ? 3 : + (x) & (1ULL << 2) ? 2 : + (x) & (1ULL << 1) ? 1 : + (x) & (1ULL << 0) ? 0 : + ilog2_undefined()); + + return 31 - clz(x); +} + +//! @} + +/*! \name Alignment + */ +//! @{ + +/*! \brief Tests alignment of the number \a val with the \a n boundary. + * + * \param val Input value. + * \param n Boundary. + * + * \return \c 1 if the number \a val is aligned with the \a n boundary, else \c 0. + */ +#define Test_align(val, n ) (!Tst_bits( val, (n) - 1 ) ) + +/*! \brief Gets alignment of the number \a val with respect to the \a n boundary. + * + * \param val Input value. + * \param n Boundary. + * + * \return Alignment of the number \a val with respect to the \a n boundary. + */ +#define Get_align( val, n ) ( Rd_bits( val, (n) - 1 ) ) + +/*! \brief Sets alignment of the lvalue number \a lval to \a alg with respect to the \a n boundary. + * + * \param lval Input/output lvalue. + * \param n Boundary. + * \param alg Alignment. + * + * \return New value of \a lval resulting from its alignment set to \a alg with respect to the \a n boundary. + */ +#define Set_align(lval, n, alg) ( Wr_bits(lval, (n) - 1, alg) ) + +/*! \brief Aligns the number \a val with the upper \a n boundary. + * + * \param val Input value. + * \param n Boundary. + * + * \return Value resulting from the number \a val aligned with the upper \a n boundary. + */ +#define Align_up( val, n ) (((val) + ((n) - 1)) & ~((n) - 1)) + +/*! \brief Aligns the number \a val with the lower \a n boundary. + * + * \param val Input value. + * \param n Boundary. + * + * \return Value resulting from the number \a val aligned with the lower \a n boundary. + */ +#define Align_down(val, n ) ( (val) & ~((n) - 1)) + +//! @} + + +/*! \name Mathematics + * + * Compiler optimization for non-constant expressions, only for abs under WinAVR + */ +//! @{ + +/*! \brief Takes the absolute value of \a a. + * + * \param a Input value. + * + * \return Absolute value of \a a. + * + * \note More optimized if only used with values known at compile time. + */ +#define Abs(a) (((a) < 0 ) ? -(a) : (a)) +#ifndef abs +#define abs(a) Abs(a) +#endif + +/*! \brief Takes the minimal value of \a a and \a b. + * + * \param a Input value. + * \param b Input value. + * + * \return Minimal value of \a a and \a b. + * + * \note More optimized if only used with values known at compile time. + */ +#define Min(a, b) (((a) < (b)) ? (a) : (b)) +#define min(a, b) Min(a, b) + +/*! \brief Takes the maximal value of \a a and \a b. + * + * \param a Input value. + * \param b Input value. + * + * \return Maximal value of \a a and \a b. + * + * \note More optimized if only used with values known at compile time. + */ +#define Max(a, b) (((a) > (b)) ? (a) : (b)) +#define max(a, b) Max(a, b) + +//! @} + + +/*! \brief Calls the routine at address \a addr. + * + * It generates a long call opcode. + * + * For example, `Long_call(0x80000000)' generates a software reset on a UC3 if + * it is invoked from the CPU supervisor mode. + * + * \param addr Address of the routine to call. + * + * \note It may be used as a long jump opcode in some special cases. + */ +#define Long_call(addr) ((*(void (*)(void))(addr))()) + +/*! \name System Register Access + */ +//! @{ + +/*! \brief Gets the value of the \a sysreg system register. + * + * \param sysreg Address of the system register of which to get the value. + * + * \return Value of the \a sysreg system register. + */ +#if (defined __GNUC__) + #define Get_system_register(sysreg) __builtin_mfsr(sysreg) +#elif (defined __ICCAVR__) + #define Get_system_register(sysreg) __get_system_register(sysreg) +#endif + +/*! \brief Sets the value of the \a sysreg system register to \a value. + * + * \param sysreg Address of the system register of which to set the value. + * \param value Value to set the \a sysreg system register to. + */ +#if (defined __GNUC__) + #define Set_system_register(sysreg, value) __builtin_mtsr(sysreg, value) +#elif (defined __ICCAVR__) + #define Set_system_register(sysreg, value) __set_system_register(sysreg, value) +#endif + +//! @} + +/*! \name Debug Register Access + */ +//! @{ + +/*! \brief Gets the value of the \a dbgreg debug register. + * + * \param dbgreg Address of the debug register of which to get the value. + * + * \return Value of the \a dbgreg debug register. + */ +#if (defined __GNUC__) + #define Get_debug_register(dbgreg) __builtin_mfdr(dbgreg) +#elif (defined __ICCAVR__) + #define Get_debug_register(dbgreg) __get_debug_register(dbgreg) +#endif + +/*! \brief Sets the value of the \a dbgreg debug register to \a value. + * + * \param dbgreg Address of the debug register of which to set the value. + * \param value Value to set the \a dbgreg debug register to. + */ +#if (defined __GNUC__) + #define Set_debug_register(dbgreg, value) __builtin_mtdr(dbgreg, value) +#elif (defined __ICCAVR__) + #define Set_debug_register(dbgreg, value) __set_debug_register(dbgreg, value) +#endif + +//! @} + + +/*! \name MCU Endianism Handling + * xmega is a MCU little endianism. + */ +//! @{ +#define MSB(u16) (((uint8_t* )&u16)[1]) +#define LSB(u16) (((uint8_t* )&u16)[0]) + +#define MSW(u32) (((uint16_t*)&u32)[1]) +#define LSW(u32) (((uint16_t*)&u32)[0]) +#define MSB0W(u32) (((uint8_t*)&(u32))[3]) //!< Most significant byte of 1st rank of \a u32. +#define MSB1W(u32) (((uint8_t*)&(u32))[2]) //!< Most significant byte of 2nd rank of \a u32. +#define MSB2W(u32) (((uint8_t*)&(u32))[1]) //!< Most significant byte of 3rd rank of \a u32. +#define MSB3W(u32) (((uint8_t*)&(u32))[0]) //!< Most significant byte of 4th rank of \a u32. +#define LSB3W(u32) MSB0W(u32) //!< Least significant byte of 4th rank of \a u32. +#define LSB2W(u32) MSB1W(u32) //!< Least significant byte of 3rd rank of \a u32. +#define LSB1W(u32) MSB2W(u32) //!< Least significant byte of 2nd rank of \a u32. +#define LSB0W(u32) MSB3W(u32) //!< Least significant byte of 1st rank of \a u32. + +#define MSB0(u32) (((uint8_t*)&u32)[3]) +#define MSB1(u32) (((uint8_t*)&u32)[2]) +#define MSB2(u32) (((uint8_t*)&u32)[1]) +#define MSB3(u32) (((uint8_t*)&u32)[0]) +#define LSB0(u32) MSB3(u32) +#define LSB1(u32) MSB2(u32) +#define LSB2(u32) MSB1(u32) +#define LSB3(u32) MSB0(u32) + +#define LE16(x) (x) +#define le16_to_cpu(x) (x) +#define cpu_to_le16(x) (x) +#define LE16_TO_CPU(x) (x) +#define CPU_TO_LE16(x) (x) + +#define BE16(x) Swap16(x) +#define be16_to_cpu(x) swap16(x) +#define cpu_to_be16(x) swap16(x) +#define BE16_TO_CPU(x) Swap16(x) +#define CPU_TO_BE16(x) Swap16(x) + +#define LE32(x) (x) +#define le32_to_cpu(x) (x) +#define cpu_to_le32(x) (x) +#define LE32_TO_CPU(x) (x) +#define CPU_TO_LE32(x) (x) + +#define BE32(x) Swap32(x) +#define be32_to_cpu(x) swap32(x) +#define cpu_to_be32(x) swap32(x) +#define BE32_TO_CPU(x) Swap32(x) +#define CPU_TO_BE32(x) Swap32(x) + + + +//! @} + + +/*! \name Endianism Conversion + * + * The same considerations as for clz and ctz apply here but AVR32-GCC's + * __builtin_bswap_16 and __builtin_bswap_32 do not behave like macros when + * applied to constant expressions, so two sets of macros are defined here: + * - Swap16, Swap32 and Swap64 to apply to constant expressions (values known + * at compile time); + * - swap16, swap32 and swap64 to apply to non-constant expressions (values + * unknown at compile time). + */ +//! @{ + +/*! \brief Toggles the endianism of \a u16 (by swapping its bytes). + * + * \param u16 U16 of which to toggle the endianism. + * + * \return Value resulting from \a u16 with toggled endianism. + * + * \note More optimized if only used with values known at compile time. + */ +#define Swap16(u16) ((U16)(((U16)(u16) >> 8) |\ + ((U16)(u16) << 8))) + +/*! \brief Toggles the endianism of \a u32 (by swapping its bytes). + * + * \param u32 U32 of which to toggle the endianism. + * + * \return Value resulting from \a u32 with toggled endianism. + * + * \note More optimized if only used with values known at compile time. + */ +#define Swap32(u32) ((U32)(((U32)Swap16((U32)(u32) >> 16)) |\ + ((U32)Swap16((U32)(u32)) << 16))) + +/*! \brief Toggles the endianism of \a u64 (by swapping its bytes). + * + * \param u64 U64 of which to toggle the endianism. + * + * \return Value resulting from \a u64 with toggled endianism. + * + * \note More optimized if only used with values known at compile time. + */ +#define Swap64(u64) ((U64)(((U64)Swap32((U64)(u64) >> 32)) |\ + ((U64)Swap32((U64)(u64)) << 32))) + +/*! \brief Toggles the endianism of \a u16 (by swapping its bytes). + * + * \param u16 U16 of which to toggle the endianism. + * + * \return Value resulting from \a u16 with toggled endianism. + * + * \note More optimized if only used with values unknown at compile time. + */ +#define swap16(u16) Swap16(u16) + +/*! \brief Toggles the endianism of \a u32 (by swapping its bytes). + * + * \param u32 U32 of which to toggle the endianism. + * + * \return Value resulting from \a u32 with toggled endianism. + * + * \note More optimized if only used with values unknown at compile time. + */ +#define swap32(u32) Swap32(u32) + +/*! \brief Toggles the endianism of \a u64 (by swapping its bytes). + * + * \param u64 U64 of which to toggle the endianism. + * + * \return Value resulting from \a u64 with toggled endianism. + * + * \note More optimized if only used with values unknown at compile time. + */ +#define swap64(u64) ((U64)(((U64)swap32((U64)(u64) >> 32)) |\ + ((U64)swap32((U64)(u64)) << 32))) + +//! @} + + +/*! \name Target Abstraction + */ +//! @{ + +#define _GLOBEXT_ extern //!< extern storage-class specifier. +#define _CONST_TYPE_ const //!< const type qualifier. +#define _MEM_TYPE_SLOW_ //!< Slow memory type. +#define _MEM_TYPE_MEDFAST_ //!< Fairly fast memory type. +#define _MEM_TYPE_FAST_ //!< Fast memory type. + +typedef U8 Byte; //!< 8-bit unsigned integer. + +#define memcmp_ram2ram memcmp //!< Target-specific memcmp of RAM to RAM. +#define memcmp_code2ram memcmp //!< Target-specific memcmp of RAM to NVRAM. +#define memcpy_ram2ram memcpy //!< Target-specific memcpy from RAM to RAM. +#define memcpy_code2ram memcpy //!< Target-specific memcpy from NVRAM to RAM. + +//! @} + +/** + * \brief Calculate \f$ \left\lceil \frac{a}{b} \right\rceil \f$ using + * integer arithmetic. + * + * \param a An integer + * \param b Another integer + * + * \return (\a a / \a b) rounded up to the nearest integer. + */ +#define div_ceil(a, b) (((a) + (b) - 1) / (b)) + +#include "preprocessor.h" +#include "progmem.h" +#include "interrupt.h" + +/** + * \} + */ + +#endif // UTILS_COMPILER_H diff --git a/DSTAT1/src/asf/xmega/utils/parts.h b/DSTAT1/src/asf/xmega/utils/parts.h new file mode 100644 index 0000000000000000000000000000000000000000..90220fb861bc3b1cbda7953f92bb19b6ce6befe5 --- /dev/null +++ b/DSTAT1/src/asf/xmega/utils/parts.h @@ -0,0 +1,175 @@ +/** + * \file + * + * \brief XMEGA device family definitions + * + * Copyright (c) 2010-2011 Atmel Corporation. All rights reserved. + * + * \asf_license_start + * + * 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. The name of Atmel may not be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * 4. This software may only be redistributed and used in connection with an + * Atmel microcontroller product. + * + * THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE + * EXPRESSLY AND SPECIFICALLY DISCLAIMED. IN NO EVENT SHALL ATMEL 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. + * + * \asf_license_stop + * + */ + +#ifndef XMEGA_PARTS_H +#define XMEGA_PARTS_H + +/** + * \defgroup group_xmega_utils_parts Parts + * + * \ingroup group_xmega_utils + * + * \{ + */ + +//! Convenience macro for checking GCC and IAR part definitions +#define part_is_defined(part) \ + (defined(__ ## part ## __) || defined(__AVR_ ## part ## __)) + +// A1 Family +#define XMEGA_A1 ( \ + part_is_defined(ATxmega64A1) || \ + part_is_defined(ATxmega128A1) \ + ) + +// A3 Family +#define XMEGA_A3 ( \ + part_is_defined(ATxmega64A3) || \ + part_is_defined(ATxmega128A3) || \ + part_is_defined(ATxmega192A3) || \ + part_is_defined(ATxmega256A3) \ + ) + +// A3B Family +#define XMEGA_A3B ( \ + part_is_defined(ATxmega256A3B) \ + ) + +// A4 Family +#define XMEGA_A4 ( \ + part_is_defined(ATxmega16A4) || \ + part_is_defined(ATxmega32A4) \ + ) + +// Entire A Family +#define XMEGA_A (XMEGA_A1 || XMEGA_A3 || XMEGA_A3B || XMEGA_A4) + +// A1U Family +#define XMEGA_A1U ( \ + part_is_defined(ATxmega64A1U) || \ + part_is_defined(ATxmega128A1U) \ + ) + +// A3U Family +#define XMEGA_A3U ( \ + part_is_defined(ATxmega64A3U) || \ + part_is_defined(ATxmega128A3U) || \ + part_is_defined(ATxmega192A3U) || \ + part_is_defined(ATxmega256A3U) \ + ) + +// A3BU Family +#define XMEGA_A3BU ( \ + part_is_defined(ATxmega256A3BU) \ + ) + +// A4U Family +#define XMEGA_A4U ( \ + part_is_defined(ATxmega16A4U) || \ + part_is_defined(ATxmega32A4U) || \ + part_is_defined(ATxmega64A4U) || \ + part_is_defined(ATxmega128A4U) \ + ) + +// Entire AU Family +#define XMEGA_AU (XMEGA_A1U || XMEGA_A3U || XMEGA_A3BU || XMEGA_A4U) + +// B1 Family +#define XMEGA_B1 ( \ + part_is_defined(ATxmega64B1) || \ + part_is_defined(ATxmega128B1) \ + ) + +// B3 Family +#define XMEGA_B3 ( \ + part_is_defined(ATxmega64B3) || \ + part_is_defined(ATxmega128B3) \ + ) + +// Entire B Family +#define XMEGA_B (XMEGA_B1 || XMEGA_B3) + +// C3 Family +#define XMEGA_C3 ( \ + part_is_defined(ATxmega384C3) || \ + part_is_defined(ATxmega256C3) \ + ) + + +// C4 Family +#define XMEGA_C4 ( \ + part_is_defined(ATxmega32C4) || \ + part_is_defined(ATxmega16C4) \ + ) + + +// Entire C Family +#define XMEGA_C (XMEGA_C3 || XMEGA_C4) + + +// D3 Family +#define XMEGA_D3 ( \ + part_is_defined(ATxmega64D3) || \ + part_is_defined(ATxmega128D3) || \ + part_is_defined(ATxmega192D3) || \ + part_is_defined(ATxmega256D3) || \ + part_is_defined(ATxmega384D3) \ + ) + +// D4 Family +#define XMEGA_D4 ( \ + part_is_defined(ATxmega16D4) || \ + part_is_defined(ATxmega32D4) || \ + part_is_defined(ATxmega64D4) || \ + part_is_defined(ATxmega128D4) \ + ) + +// Entire D Family +#define XMEGA_D (XMEGA_D3 || XMEGA_D4) + +// Entire XMEGA Family +#define XMEGA (XMEGA_A || XMEGA_AU || XMEGA_B || XMEGA_C || XMEGA_D) + +/** + * \} + */ + +#endif /* XMEGA_PARTS_H */ diff --git a/DSTAT1/src/asf/xmega/utils/preprocessor/mrepeat.h b/DSTAT1/src/asf/xmega/utils/preprocessor/mrepeat.h new file mode 100644 index 0000000000000000000000000000000000000000..ece2d561dd6f611d9b4436608c8ae3a5c841c2e4 --- /dev/null +++ b/DSTAT1/src/asf/xmega/utils/preprocessor/mrepeat.h @@ -0,0 +1,333 @@ +/** + * \file + * + * \brief Preprocessor macro repeating utils. + * + * Copyright (c) 2009 Atmel Corporation. All rights reserved. + * + * \asf_license_start + * + * 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. The name of Atmel may not be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * 4. This software may only be redistributed and used in connection with an + * Atmel microcontroller product. + * + * THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE + * EXPRESSLY AND SPECIFICALLY DISCLAIMED. IN NO EVENT SHALL ATMEL 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. + * + * \asf_license_stop + * + */ +#ifndef _MREPEAT_H_ +#define _MREPEAT_H_ + +/** + * \defgroup group_xmega_utils_mrepeat Macro Repeat + * + * \ingroup group_xmega_utils + * + * \{ + */ + +#include "preprocessor.h" + + +//! Maximal number of repetitions supported by MREPEAT. +#define MREPEAT_LIMIT 256 + +/*! \brief Macro repeat. + * + * This macro represents a horizontal repetition construct. + * + * \param count The number of repetitious calls to macro. Valid values range from 0 to MREPEAT_LIMIT. + * \param macro A binary operation of the form macro(n, data). This macro is expanded by MREPEAT with + * the current repetition number and the auxiliary data argument. + * \param data Auxiliary data passed to macro. + * + * \return macro(0, data) macro(1, data) ... macro(count - 1, data) + */ +#define MREPEAT(count, macro, data) TPASTE2(MREPEAT, count)(macro, data) + +#define MREPEAT0( macro, data) +#define MREPEAT1( macro, data) MREPEAT0( macro, data) macro( 0, data) +#define MREPEAT2( macro, data) MREPEAT1( macro, data) macro( 1, data) +#define MREPEAT3( macro, data) MREPEAT2( macro, data) macro( 2, data) +#define MREPEAT4( macro, data) MREPEAT3( macro, data) macro( 3, data) +#define MREPEAT5( macro, data) MREPEAT4( macro, data) macro( 4, data) +#define MREPEAT6( macro, data) MREPEAT5( macro, data) macro( 5, data) +#define MREPEAT7( macro, data) MREPEAT6( macro, data) macro( 6, data) +#define MREPEAT8( macro, data) MREPEAT7( macro, data) macro( 7, data) +#define MREPEAT9( macro, data) MREPEAT8( macro, data) macro( 8, data) +#define MREPEAT10( macro, data) MREPEAT9( macro, data) macro( 9, data) +#define MREPEAT11( macro, data) MREPEAT10( macro, data) macro( 10, data) +#define MREPEAT12( macro, data) MREPEAT11( macro, data) macro( 11, data) +#define MREPEAT13( macro, data) MREPEAT12( macro, data) macro( 12, data) +#define MREPEAT14( macro, data) MREPEAT13( macro, data) macro( 13, data) +#define MREPEAT15( macro, data) MREPEAT14( macro, data) macro( 14, data) +#define MREPEAT16( macro, data) MREPEAT15( macro, data) macro( 15, data) +#define MREPEAT17( macro, data) MREPEAT16( macro, data) macro( 16, data) +#define MREPEAT18( macro, data) MREPEAT17( macro, data) macro( 17, data) +#define MREPEAT19( macro, data) MREPEAT18( macro, data) macro( 18, data) +#define MREPEAT20( macro, data) MREPEAT19( macro, data) macro( 19, data) +#define MREPEAT21( macro, data) MREPEAT20( macro, data) macro( 20, data) +#define MREPEAT22( macro, data) MREPEAT21( macro, data) macro( 21, data) +#define MREPEAT23( macro, data) MREPEAT22( macro, data) macro( 22, data) +#define MREPEAT24( macro, data) MREPEAT23( macro, data) macro( 23, data) +#define MREPEAT25( macro, data) MREPEAT24( macro, data) macro( 24, data) +#define MREPEAT26( macro, data) MREPEAT25( macro, data) macro( 25, data) +#define MREPEAT27( macro, data) MREPEAT26( macro, data) macro( 26, data) +#define MREPEAT28( macro, data) MREPEAT27( macro, data) macro( 27, data) +#define MREPEAT29( macro, data) MREPEAT28( macro, data) macro( 28, data) +#define MREPEAT30( macro, data) MREPEAT29( macro, data) macro( 29, data) +#define MREPEAT31( macro, data) MREPEAT30( macro, data) macro( 30, data) +#define MREPEAT32( macro, data) MREPEAT31( macro, data) macro( 31, data) +#define MREPEAT33( macro, data) MREPEAT32( macro, data) macro( 32, data) +#define MREPEAT34( macro, data) MREPEAT33( macro, data) macro( 33, data) +#define MREPEAT35( macro, data) MREPEAT34( macro, data) macro( 34, data) +#define MREPEAT36( macro, data) MREPEAT35( macro, data) macro( 35, data) +#define MREPEAT37( macro, data) MREPEAT36( macro, data) macro( 36, data) +#define MREPEAT38( macro, data) MREPEAT37( macro, data) macro( 37, data) +#define MREPEAT39( macro, data) MREPEAT38( macro, data) macro( 38, data) +#define MREPEAT40( macro, data) MREPEAT39( macro, data) macro( 39, data) +#define MREPEAT41( macro, data) MREPEAT40( macro, data) macro( 40, data) +#define MREPEAT42( macro, data) MREPEAT41( macro, data) macro( 41, data) +#define MREPEAT43( macro, data) MREPEAT42( macro, data) macro( 42, data) +#define MREPEAT44( macro, data) MREPEAT43( macro, data) macro( 43, data) +#define MREPEAT45( macro, data) MREPEAT44( macro, data) macro( 44, data) +#define MREPEAT46( macro, data) MREPEAT45( macro, data) macro( 45, data) +#define MREPEAT47( macro, data) MREPEAT46( macro, data) macro( 46, data) +#define MREPEAT48( macro, data) MREPEAT47( macro, data) macro( 47, data) +#define MREPEAT49( macro, data) MREPEAT48( macro, data) macro( 48, data) +#define MREPEAT50( macro, data) MREPEAT49( macro, data) macro( 49, data) +#define MREPEAT51( macro, data) MREPEAT50( macro, data) macro( 50, data) +#define MREPEAT52( macro, data) MREPEAT51( macro, data) macro( 51, data) +#define MREPEAT53( macro, data) MREPEAT52( macro, data) macro( 52, data) +#define MREPEAT54( macro, data) MREPEAT53( macro, data) macro( 53, data) +#define MREPEAT55( macro, data) MREPEAT54( macro, data) macro( 54, data) +#define MREPEAT56( macro, data) MREPEAT55( macro, data) macro( 55, data) +#define MREPEAT57( macro, data) MREPEAT56( macro, data) macro( 56, data) +#define MREPEAT58( macro, data) MREPEAT57( macro, data) macro( 57, data) +#define MREPEAT59( macro, data) MREPEAT58( macro, data) macro( 58, data) +#define MREPEAT60( macro, data) MREPEAT59( macro, data) macro( 59, data) +#define MREPEAT61( macro, data) MREPEAT60( macro, data) macro( 60, data) +#define MREPEAT62( macro, data) MREPEAT61( macro, data) macro( 61, data) +#define MREPEAT63( macro, data) MREPEAT62( macro, data) macro( 62, data) +#define MREPEAT64( macro, data) MREPEAT63( macro, data) macro( 63, data) +#define MREPEAT65( macro, data) MREPEAT64( macro, data) macro( 64, data) +#define MREPEAT66( macro, data) MREPEAT65( macro, data) macro( 65, data) +#define MREPEAT67( macro, data) MREPEAT66( macro, data) macro( 66, data) +#define MREPEAT68( macro, data) MREPEAT67( macro, data) macro( 67, data) +#define MREPEAT69( macro, data) MREPEAT68( macro, data) macro( 68, data) +#define MREPEAT70( macro, data) MREPEAT69( macro, data) macro( 69, data) +#define MREPEAT71( macro, data) MREPEAT70( macro, data) macro( 70, data) +#define MREPEAT72( macro, data) MREPEAT71( macro, data) macro( 71, data) +#define MREPEAT73( macro, data) MREPEAT72( macro, data) macro( 72, data) +#define MREPEAT74( macro, data) MREPEAT73( macro, data) macro( 73, data) +#define MREPEAT75( macro, data) MREPEAT74( macro, data) macro( 74, data) +#define MREPEAT76( macro, data) MREPEAT75( macro, data) macro( 75, data) +#define MREPEAT77( macro, data) MREPEAT76( macro, data) macro( 76, data) +#define MREPEAT78( macro, data) MREPEAT77( macro, data) macro( 77, data) +#define MREPEAT79( macro, data) MREPEAT78( macro, data) macro( 78, data) +#define MREPEAT80( macro, data) MREPEAT79( macro, data) macro( 79, data) +#define MREPEAT81( macro, data) MREPEAT80( macro, data) macro( 80, data) +#define MREPEAT82( macro, data) MREPEAT81( macro, data) macro( 81, data) +#define MREPEAT83( macro, data) MREPEAT82( macro, data) macro( 82, data) +#define MREPEAT84( macro, data) MREPEAT83( macro, data) macro( 83, data) +#define MREPEAT85( macro, data) MREPEAT84( macro, data) macro( 84, data) +#define MREPEAT86( macro, data) MREPEAT85( macro, data) macro( 85, data) +#define MREPEAT87( macro, data) MREPEAT86( macro, data) macro( 86, data) +#define MREPEAT88( macro, data) MREPEAT87( macro, data) macro( 87, data) +#define MREPEAT89( macro, data) MREPEAT88( macro, data) macro( 88, data) +#define MREPEAT90( macro, data) MREPEAT89( macro, data) macro( 89, data) +#define MREPEAT91( macro, data) MREPEAT90( macro, data) macro( 90, data) +#define MREPEAT92( macro, data) MREPEAT91( macro, data) macro( 91, data) +#define MREPEAT93( macro, data) MREPEAT92( macro, data) macro( 92, data) +#define MREPEAT94( macro, data) MREPEAT93( macro, data) macro( 93, data) +#define MREPEAT95( macro, data) MREPEAT94( macro, data) macro( 94, data) +#define MREPEAT96( macro, data) MREPEAT95( macro, data) macro( 95, data) +#define MREPEAT97( macro, data) MREPEAT96( macro, data) macro( 96, data) +#define MREPEAT98( macro, data) MREPEAT97( macro, data) macro( 97, data) +#define MREPEAT99( macro, data) MREPEAT98( macro, data) macro( 98, data) +#define MREPEAT100(macro, data) MREPEAT99( macro, data) macro( 99, data) +#define MREPEAT101(macro, data) MREPEAT100(macro, data) macro(100, data) +#define MREPEAT102(macro, data) MREPEAT101(macro, data) macro(101, data) +#define MREPEAT103(macro, data) MREPEAT102(macro, data) macro(102, data) +#define MREPEAT104(macro, data) MREPEAT103(macro, data) macro(103, data) +#define MREPEAT105(macro, data) MREPEAT104(macro, data) macro(104, data) +#define MREPEAT106(macro, data) MREPEAT105(macro, data) macro(105, data) +#define MREPEAT107(macro, data) MREPEAT106(macro, data) macro(106, data) +#define MREPEAT108(macro, data) MREPEAT107(macro, data) macro(107, data) +#define MREPEAT109(macro, data) MREPEAT108(macro, data) macro(108, data) +#define MREPEAT110(macro, data) MREPEAT109(macro, data) macro(109, data) +#define MREPEAT111(macro, data) MREPEAT110(macro, data) macro(110, data) +#define MREPEAT112(macro, data) MREPEAT111(macro, data) macro(111, data) +#define MREPEAT113(macro, data) MREPEAT112(macro, data) macro(112, data) +#define MREPEAT114(macro, data) MREPEAT113(macro, data) macro(113, data) +#define MREPEAT115(macro, data) MREPEAT114(macro, data) macro(114, data) +#define MREPEAT116(macro, data) MREPEAT115(macro, data) macro(115, data) +#define MREPEAT117(macro, data) MREPEAT116(macro, data) macro(116, data) +#define MREPEAT118(macro, data) MREPEAT117(macro, data) macro(117, data) +#define MREPEAT119(macro, data) MREPEAT118(macro, data) macro(118, data) +#define MREPEAT120(macro, data) MREPEAT119(macro, data) macro(119, data) +#define MREPEAT121(macro, data) MREPEAT120(macro, data) macro(120, data) +#define MREPEAT122(macro, data) MREPEAT121(macro, data) macro(121, data) +#define MREPEAT123(macro, data) MREPEAT122(macro, data) macro(122, data) +#define MREPEAT124(macro, data) MREPEAT123(macro, data) macro(123, data) +#define MREPEAT125(macro, data) MREPEAT124(macro, data) macro(124, data) +#define MREPEAT126(macro, data) MREPEAT125(macro, data) macro(125, data) +#define MREPEAT127(macro, data) MREPEAT126(macro, data) macro(126, data) +#define MREPEAT128(macro, data) MREPEAT127(macro, data) macro(127, data) +#define MREPEAT129(macro, data) MREPEAT128(macro, data) macro(128, data) +#define MREPEAT130(macro, data) MREPEAT129(macro, data) macro(129, data) +#define MREPEAT131(macro, data) MREPEAT130(macro, data) macro(130, data) +#define MREPEAT132(macro, data) MREPEAT131(macro, data) macro(131, data) +#define MREPEAT133(macro, data) MREPEAT132(macro, data) macro(132, data) +#define MREPEAT134(macro, data) MREPEAT133(macro, data) macro(133, data) +#define MREPEAT135(macro, data) MREPEAT134(macro, data) macro(134, data) +#define MREPEAT136(macro, data) MREPEAT135(macro, data) macro(135, data) +#define MREPEAT137(macro, data) MREPEAT136(macro, data) macro(136, data) +#define MREPEAT138(macro, data) MREPEAT137(macro, data) macro(137, data) +#define MREPEAT139(macro, data) MREPEAT138(macro, data) macro(138, data) +#define MREPEAT140(macro, data) MREPEAT139(macro, data) macro(139, data) +#define MREPEAT141(macro, data) MREPEAT140(macro, data) macro(140, data) +#define MREPEAT142(macro, data) MREPEAT141(macro, data) macro(141, data) +#define MREPEAT143(macro, data) MREPEAT142(macro, data) macro(142, data) +#define MREPEAT144(macro, data) MREPEAT143(macro, data) macro(143, data) +#define MREPEAT145(macro, data) MREPEAT144(macro, data) macro(144, data) +#define MREPEAT146(macro, data) MREPEAT145(macro, data) macro(145, data) +#define MREPEAT147(macro, data) MREPEAT146(macro, data) macro(146, data) +#define MREPEAT148(macro, data) MREPEAT147(macro, data) macro(147, data) +#define MREPEAT149(macro, data) MREPEAT148(macro, data) macro(148, data) +#define MREPEAT150(macro, data) MREPEAT149(macro, data) macro(149, data) +#define MREPEAT151(macro, data) MREPEAT150(macro, data) macro(150, data) +#define MREPEAT152(macro, data) MREPEAT151(macro, data) macro(151, data) +#define MREPEAT153(macro, data) MREPEAT152(macro, data) macro(152, data) +#define MREPEAT154(macro, data) MREPEAT153(macro, data) macro(153, data) +#define MREPEAT155(macro, data) MREPEAT154(macro, data) macro(154, data) +#define MREPEAT156(macro, data) MREPEAT155(macro, data) macro(155, data) +#define MREPEAT157(macro, data) MREPEAT156(macro, data) macro(156, data) +#define MREPEAT158(macro, data) MREPEAT157(macro, data) macro(157, data) +#define MREPEAT159(macro, data) MREPEAT158(macro, data) macro(158, data) +#define MREPEAT160(macro, data) MREPEAT159(macro, data) macro(159, data) +#define MREPEAT161(macro, data) MREPEAT160(macro, data) macro(160, data) +#define MREPEAT162(macro, data) MREPEAT161(macro, data) macro(161, data) +#define MREPEAT163(macro, data) MREPEAT162(macro, data) macro(162, data) +#define MREPEAT164(macro, data) MREPEAT163(macro, data) macro(163, data) +#define MREPEAT165(macro, data) MREPEAT164(macro, data) macro(164, data) +#define MREPEAT166(macro, data) MREPEAT165(macro, data) macro(165, data) +#define MREPEAT167(macro, data) MREPEAT166(macro, data) macro(166, data) +#define MREPEAT168(macro, data) MREPEAT167(macro, data) macro(167, data) +#define MREPEAT169(macro, data) MREPEAT168(macro, data) macro(168, data) +#define MREPEAT170(macro, data) MREPEAT169(macro, data) macro(169, data) +#define MREPEAT171(macro, data) MREPEAT170(macro, data) macro(170, data) +#define MREPEAT172(macro, data) MREPEAT171(macro, data) macro(171, data) +#define MREPEAT173(macro, data) MREPEAT172(macro, data) macro(172, data) +#define MREPEAT174(macro, data) MREPEAT173(macro, data) macro(173, data) +#define MREPEAT175(macro, data) MREPEAT174(macro, data) macro(174, data) +#define MREPEAT176(macro, data) MREPEAT175(macro, data) macro(175, data) +#define MREPEAT177(macro, data) MREPEAT176(macro, data) macro(176, data) +#define MREPEAT178(macro, data) MREPEAT177(macro, data) macro(177, data) +#define MREPEAT179(macro, data) MREPEAT178(macro, data) macro(178, data) +#define MREPEAT180(macro, data) MREPEAT179(macro, data) macro(179, data) +#define MREPEAT181(macro, data) MREPEAT180(macro, data) macro(180, data) +#define MREPEAT182(macro, data) MREPEAT181(macro, data) macro(181, data) +#define MREPEAT183(macro, data) MREPEAT182(macro, data) macro(182, data) +#define MREPEAT184(macro, data) MREPEAT183(macro, data) macro(183, data) +#define MREPEAT185(macro, data) MREPEAT184(macro, data) macro(184, data) +#define MREPEAT186(macro, data) MREPEAT185(macro, data) macro(185, data) +#define MREPEAT187(macro, data) MREPEAT186(macro, data) macro(186, data) +#define MREPEAT188(macro, data) MREPEAT187(macro, data) macro(187, data) +#define MREPEAT189(macro, data) MREPEAT188(macro, data) macro(188, data) +#define MREPEAT190(macro, data) MREPEAT189(macro, data) macro(189, data) +#define MREPEAT191(macro, data) MREPEAT190(macro, data) macro(190, data) +#define MREPEAT192(macro, data) MREPEAT191(macro, data) macro(191, data) +#define MREPEAT193(macro, data) MREPEAT192(macro, data) macro(192, data) +#define MREPEAT194(macro, data) MREPEAT193(macro, data) macro(193, data) +#define MREPEAT195(macro, data) MREPEAT194(macro, data) macro(194, data) +#define MREPEAT196(macro, data) MREPEAT195(macro, data) macro(195, data) +#define MREPEAT197(macro, data) MREPEAT196(macro, data) macro(196, data) +#define MREPEAT198(macro, data) MREPEAT197(macro, data) macro(197, data) +#define MREPEAT199(macro, data) MREPEAT198(macro, data) macro(198, data) +#define MREPEAT200(macro, data) MREPEAT199(macro, data) macro(199, data) +#define MREPEAT201(macro, data) MREPEAT200(macro, data) macro(200, data) +#define MREPEAT202(macro, data) MREPEAT201(macro, data) macro(201, data) +#define MREPEAT203(macro, data) MREPEAT202(macro, data) macro(202, data) +#define MREPEAT204(macro, data) MREPEAT203(macro, data) macro(203, data) +#define MREPEAT205(macro, data) MREPEAT204(macro, data) macro(204, data) +#define MREPEAT206(macro, data) MREPEAT205(macro, data) macro(205, data) +#define MREPEAT207(macro, data) MREPEAT206(macro, data) macro(206, data) +#define MREPEAT208(macro, data) MREPEAT207(macro, data) macro(207, data) +#define MREPEAT209(macro, data) MREPEAT208(macro, data) macro(208, data) +#define MREPEAT210(macro, data) MREPEAT209(macro, data) macro(209, data) +#define MREPEAT211(macro, data) MREPEAT210(macro, data) macro(210, data) +#define MREPEAT212(macro, data) MREPEAT211(macro, data) macro(211, data) +#define MREPEAT213(macro, data) MREPEAT212(macro, data) macro(212, data) +#define MREPEAT214(macro, data) MREPEAT213(macro, data) macro(213, data) +#define MREPEAT215(macro, data) MREPEAT214(macro, data) macro(214, data) +#define MREPEAT216(macro, data) MREPEAT215(macro, data) macro(215, data) +#define MREPEAT217(macro, data) MREPEAT216(macro, data) macro(216, data) +#define MREPEAT218(macro, data) MREPEAT217(macro, data) macro(217, data) +#define MREPEAT219(macro, data) MREPEAT218(macro, data) macro(218, data) +#define MREPEAT220(macro, data) MREPEAT219(macro, data) macro(219, data) +#define MREPEAT221(macro, data) MREPEAT220(macro, data) macro(220, data) +#define MREPEAT222(macro, data) MREPEAT221(macro, data) macro(221, data) +#define MREPEAT223(macro, data) MREPEAT222(macro, data) macro(222, data) +#define MREPEAT224(macro, data) MREPEAT223(macro, data) macro(223, data) +#define MREPEAT225(macro, data) MREPEAT224(macro, data) macro(224, data) +#define MREPEAT226(macro, data) MREPEAT225(macro, data) macro(225, data) +#define MREPEAT227(macro, data) MREPEAT226(macro, data) macro(226, data) +#define MREPEAT228(macro, data) MREPEAT227(macro, data) macro(227, data) +#define MREPEAT229(macro, data) MREPEAT228(macro, data) macro(228, data) +#define MREPEAT230(macro, data) MREPEAT229(macro, data) macro(229, data) +#define MREPEAT231(macro, data) MREPEAT230(macro, data) macro(230, data) +#define MREPEAT232(macro, data) MREPEAT231(macro, data) macro(231, data) +#define MREPEAT233(macro, data) MREPEAT232(macro, data) macro(232, data) +#define MREPEAT234(macro, data) MREPEAT233(macro, data) macro(233, data) +#define MREPEAT235(macro, data) MREPEAT234(macro, data) macro(234, data) +#define MREPEAT236(macro, data) MREPEAT235(macro, data) macro(235, data) +#define MREPEAT237(macro, data) MREPEAT236(macro, data) macro(236, data) +#define MREPEAT238(macro, data) MREPEAT237(macro, data) macro(237, data) +#define MREPEAT239(macro, data) MREPEAT238(macro, data) macro(238, data) +#define MREPEAT240(macro, data) MREPEAT239(macro, data) macro(239, data) +#define MREPEAT241(macro, data) MREPEAT240(macro, data) macro(240, data) +#define MREPEAT242(macro, data) MREPEAT241(macro, data) macro(241, data) +#define MREPEAT243(macro, data) MREPEAT242(macro, data) macro(242, data) +#define MREPEAT244(macro, data) MREPEAT243(macro, data) macro(243, data) +#define MREPEAT245(macro, data) MREPEAT244(macro, data) macro(244, data) +#define MREPEAT246(macro, data) MREPEAT245(macro, data) macro(245, data) +#define MREPEAT247(macro, data) MREPEAT246(macro, data) macro(246, data) +#define MREPEAT248(macro, data) MREPEAT247(macro, data) macro(247, data) +#define MREPEAT249(macro, data) MREPEAT248(macro, data) macro(248, data) +#define MREPEAT250(macro, data) MREPEAT249(macro, data) macro(249, data) +#define MREPEAT251(macro, data) MREPEAT250(macro, data) macro(250, data) +#define MREPEAT252(macro, data) MREPEAT251(macro, data) macro(251, data) +#define MREPEAT253(macro, data) MREPEAT252(macro, data) macro(252, data) +#define MREPEAT254(macro, data) MREPEAT253(macro, data) macro(253, data) +#define MREPEAT255(macro, data) MREPEAT254(macro, data) macro(254, data) +#define MREPEAT256(macro, data) MREPEAT255(macro, data) macro(255, data) + +/** + * \} + */ + +#endif // _MREPEAT_H_ diff --git a/DSTAT1/src/asf/xmega/utils/preprocessor/preprocessor.h b/DSTAT1/src/asf/xmega/utils/preprocessor/preprocessor.h new file mode 100644 index 0000000000000000000000000000000000000000..5bb934096b9578725ba1b49f9f967dde2f401e0e --- /dev/null +++ b/DSTAT1/src/asf/xmega/utils/preprocessor/preprocessor.h @@ -0,0 +1,49 @@ +/** + * \file + * + * \brief Preprocessor utils. + * + * Copyright (c) 2009 Atmel Corporation. All rights reserved. + * + * \asf_license_start + * + * 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. The name of Atmel may not be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * 4. This software may only be redistributed and used in connection with an + * Atmel microcontroller product. + * + * THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE + * EXPRESSLY AND SPECIFICALLY DISCLAIMED. IN NO EVENT SHALL ATMEL 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. + * + * \asf_license_stop + * + */ +#ifndef _PREPROCESSOR_H_ +#define _PREPROCESSOR_H_ + +#include "tpaste.h" +#include "stringz.h" +#include "mrepeat.h" + + +#endif // _PREPROCESSOR_H_ diff --git a/DSTAT1/src/asf/xmega/utils/preprocessor/stringz.h b/DSTAT1/src/asf/xmega/utils/preprocessor/stringz.h new file mode 100644 index 0000000000000000000000000000000000000000..824dfddece922fec5a38b10e108649ef15085372 --- /dev/null +++ b/DSTAT1/src/asf/xmega/utils/preprocessor/stringz.h @@ -0,0 +1,79 @@ +/** + * \file + * + * \brief Preprocessor stringizing utils. + * + * Copyright (c) 2009 Atmel Corporation. All rights reserved. + * + * \asf_license_start + * + * 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. The name of Atmel may not be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * 4. This software may only be redistributed and used in connection with an + * Atmel microcontroller product. + * + * THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE + * EXPRESSLY AND SPECIFICALLY DISCLAIMED. IN NO EVENT SHALL ATMEL 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. + * + * \asf_license_stop + * + */ +#ifndef _STRINGZ_H_ +#define _STRINGZ_H_ + +/** + * \defgroup group_xmega_utils_stringz Stringize + * + * \ingroup group_xmega_utils + * + * \{ + */ + +/*! \brief Stringize. + * + * Stringize a preprocessing token, this token being allowed to be \#defined. + * + * May be used only within macros with the token passed as an argument if the token is \#defined. + * + * For example, writing STRINGZ(PIN) within a macro \#defined by PIN_NAME(PIN) + * and invoked as PIN_NAME(PIN0) with PIN0 \#defined as A0 is equivalent to + * writing "A0". + */ +#define STRINGZ(x) #x + +/*! \brief Absolute stringize. + * + * Stringize a preprocessing token, this token being allowed to be \#defined. + * + * No restriction of use if the token is \#defined. + * + * For example, writing ASTRINGZ(PIN0) anywhere with PIN0 \#defined as A0 is + * equivalent to writing "A0". + */ +#define ASTRINGZ(x) STRINGZ(x) + +/** + * \} + */ + +#endif // _STRINGZ_H_ diff --git a/DSTAT1/src/asf/xmega/utils/preprocessor/tpaste.h b/DSTAT1/src/asf/xmega/utils/preprocessor/tpaste.h new file mode 100644 index 0000000000000000000000000000000000000000..d7a4e36a876cae643ad6eadfc596f1b6e3065228 --- /dev/null +++ b/DSTAT1/src/asf/xmega/utils/preprocessor/tpaste.h @@ -0,0 +1,99 @@ +/** + * \file + * + * \brief Preprocessor token pasting utils. + * + * Copyright (c) 2009 Atmel Corporation. All rights reserved. + * + * \asf_license_start + * + * 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. The name of Atmel may not be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * 4. This software may only be redistributed and used in connection with an + * Atmel microcontroller product. + * + * THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE + * EXPRESSLY AND SPECIFICALLY DISCLAIMED. IN NO EVENT SHALL ATMEL 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. + * + * \asf_license_stop + * + */ +#ifndef _TPASTE_H_ +#define _TPASTE_H_ + +/** + * \defgroup group_xmega_utils_tpaste Token Paste + * + * \ingroup group_xmega_utils + * + * \{ + */ + +/*! \name Token Paste + * + * Paste N preprocessing tokens together, these tokens being allowed to be \#defined. + * + * May be used only within macros with the tokens passed as arguments if the tokens are \#defined. + * + * For example, writing TPASTE2(U, WIDTH) within a macro \#defined by + * UTYPE(WIDTH) and invoked as UTYPE(UL_WIDTH) with UL_WIDTH \#defined as 32 is + * equivalent to writing U32. + */ +//! @{ +#define TPASTE2( a, b) a##b +#define TPASTE3( a, b, c) a##b##c +#define TPASTE4( a, b, c, d) a##b##c##d +#define TPASTE5( a, b, c, d, e) a##b##c##d##e +#define TPASTE6( a, b, c, d, e, f) a##b##c##d##e##f +#define TPASTE7( a, b, c, d, e, f, g) a##b##c##d##e##f##g +#define TPASTE8( a, b, c, d, e, f, g, h) a##b##c##d##e##f##g##h +#define TPASTE9( a, b, c, d, e, f, g, h, i) a##b##c##d##e##f##g##h##i +#define TPASTE10(a, b, c, d, e, f, g, h, i, j) a##b##c##d##e##f##g##h##i##j +//! @} + +/*! \name Absolute Token Paste + * + * Paste N preprocessing tokens together, these tokens being allowed to be \#defined. + * + * No restriction of use if the tokens are \#defined. + * + * For example, writing ATPASTE2(U, UL_WIDTH) anywhere with UL_WIDTH \#defined + * as 32 is equivalent to writing U32. + */ +//! @{ +#define ATPASTE2( a, b) TPASTE2( a, b) +#define ATPASTE3( a, b, c) TPASTE3( a, b, c) +#define ATPASTE4( a, b, c, d) TPASTE4( a, b, c, d) +#define ATPASTE5( a, b, c, d, e) TPASTE5( a, b, c, d, e) +#define ATPASTE6( a, b, c, d, e, f) TPASTE6( a, b, c, d, e, f) +#define ATPASTE7( a, b, c, d, e, f, g) TPASTE7( a, b, c, d, e, f, g) +#define ATPASTE8( a, b, c, d, e, f, g, h) TPASTE8( a, b, c, d, e, f, g, h) +#define ATPASTE9( a, b, c, d, e, f, g, h, i) TPASTE9( a, b, c, d, e, f, g, h, i) +#define ATPASTE10(a, b, c, d, e, f, g, h, i, j) TPASTE10(a, b, c, d, e, f, g, h, i, j) +//! @} + +/** + * \} + */ + +#endif // _TPASTE_H_ diff --git a/DSTAT1/src/asf/xmega/utils/progmem.h b/DSTAT1/src/asf/xmega/utils/progmem.h new file mode 100644 index 0000000000000000000000000000000000000000..d8656cd00b85dfd14ac021b8ed1212168919dc0c --- /dev/null +++ b/DSTAT1/src/asf/xmega/utils/progmem.h @@ -0,0 +1,97 @@ +/** + * \file + * + * \brief Program memory access + * + * Copyright (c) 2010 Atmel Corporation. All rights reserved. + * + * \asf_license_start + * + * 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. The name of Atmel may not be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * 4. This software may only be redistributed and used in connection with an + * Atmel microcontroller product. + * + * THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE + * EXPRESSLY AND SPECIFICALLY DISCLAIMED. IN NO EVENT SHALL ATMEL 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. + * + * \asf_license_stop + * + */ + +#ifndef UTILS_PROGMEM_H +#define UTILS_PROGMEM_H + +/** + * \defgroup group_xmega_utils_progmem Program memory + * + * \ingroup group_xmega_utils + * + * \{ + */ + +/*! \name Program memory + * + * Macros for locating and accessing data in program memory. + * + * @{ + */ +#if defined(__GNUC__) || defined(__DOXYGEN__) +# include +# define PROGMEM_LOCATION(type, name, loc) \ + type name __attribute__((section (#loc))) +# define PROGMEM_DECLARE(type, name) const type name __attribute__((__progmem__)) +# define PROGMEM_STRING(x) PSTR(x) +# define PROGMEM_STRING_T PGM_P +# define PROGMEM_T +# define PROGMEM_PTR_T * +# define PROGMEM_BYTE_ARRAY_T uint8_t* +# define PROGMEM_WORD_ARRAY_T uint16_t* +# define PROGMEM_READ_BYTE(x) pgm_read_byte(x) +# define PROGMEM_READ_WORD(x) pgm_read_word(x) + +#elif defined(__ICCAVR__) +# include +# ifndef __HAS_ELPM__ +# define _MEMATTR_ASF __flash +# else /* __HAS_ELPM__ */ +# define _MEMATTR_ASF __hugeflash +# endif /* __HAS_ELPM__ */ +# define PROGMEM_LOCATION(type, name, loc) const _MEMATTR_ASF type name @ loc +# define PROGMEM_DECLARE(type, name) _MEMATTR_ASF type name +# define PROGMEM_STRING(x) ((_MEMATTR_ASF const char *)(x)) +# define PROGMEM_STRING_T char const _MEMATTR_ASF * +# define PROGMEM_T const _MEMATTR_ASF +# define PROGMEM_PTR_T const _MEMATTR_ASF * +# define PROGMEM_BYTE_ARRAY_T uint8_t const _MEMATTR_ASF * +# define PROGMEM_WORD_ARRAY_T uint16_t const _MEMATTR_ASF * +# define PROGMEM_READ_BYTE(x) *(x) +# define PROGMEM_READ_WORD(x) *(x) +#endif +//! @} + +/** + * \} + */ + +#endif /* UTILS_PROGMEM_H */ diff --git a/DSTAT1/src/asf/xmega/utils/status_codes.h b/DSTAT1/src/asf/xmega/utils/status_codes.h new file mode 100644 index 0000000000000000000000000000000000000000..68873e505d6280aff70ac8663088d5e9f88d3b2a --- /dev/null +++ b/DSTAT1/src/asf/xmega/utils/status_codes.h @@ -0,0 +1,96 @@ +/** + * \file + * + * \brief Status code definitions. + * + * This file defines various status codes returned by functions, + * indicating success or failure as well as what kind of failure. + * + * Copyright (c) 2009 Atmel Corporation. All rights reserved. + * + * \asf_license_start + * + * 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. The name of Atmel may not be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * 4. This software may only be redistributed and used in connection with an + * Atmel microcontroller product. + * + * THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE + * EXPRESSLY AND SPECIFICALLY DISCLAIMED. IN NO EVENT SHALL ATMEL 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. + * + * \asf_license_stop + * + */ +#ifndef STATUS_CODES_H_INCLUDED +#define STATUS_CODES_H_INCLUDED + +/** + * \defgroup group_xmega_utils_status_codes Status Codes + * + * \ingroup group_xmega_utils + * + * \{ + */ + +/** + * Status code that may be returned by shell commands and protocol + * implementations. + * + * \note Any change to these status codes and the corresponding + * message strings is strictly forbidden. New codes can be added, + * however, but make sure that any message string tables are updated + * at the same time. + */ +enum status_code { + STATUS_OK = 0, //!< Success + ERR_IO_ERROR = -1, //!< I/O error + ERR_FLUSHED = -2, //!< Request flushed from queue + ERR_TIMEOUT = -3, //!< Operation timed out + ERR_BAD_DATA = -4, //!< Data integrity check failed + ERR_PROTOCOL = -5, //!< Protocol error + ERR_UNSUPPORTED_DEV = -6, //!< Unsupported device + ERR_NO_MEMORY = -7, //!< Insufficient memory + ERR_INVALID_ARG = -8, //!< Invalid argument + ERR_BAD_ADDRESS = -9, //!< Bad address + ERR_BUSY = -10, //!< Resource is busy + ERR_BAD_FORMAT = -11, //!< Data format not recognized + + /** + * \brief Operation in progress + * + * This status code is for driver-internal use when an operation + * is currently being performed. + * + * \note Drivers should never return this status code to any + * callers. It is strictly for internal use. + */ + OPERATION_IN_PROGRESS = -128, +}; + +typedef enum status_code status_code_t; + +/** + * \} + */ + +#endif /* STATUS_CODES_H_INCLUDED */ diff --git a/DSTAT1/src/config/conf_board.h b/DSTAT1/src/config/conf_board.h new file mode 100644 index 0000000000000000000000000000000000000000..dc022fad8a6bad7f8af2cb0c1625155b9a28de45 --- /dev/null +++ b/DSTAT1/src/config/conf_board.h @@ -0,0 +1,28 @@ +/** + * \file + * + * \brief User board configuration template + * + */ + +#ifndef CONF_BOARD_H +#define CONF_BOARD_H + +// External oscillator settings. +// Uncomment and set correct values if external oscillator is used. + +// External oscillator frequency +#define BOARD_XOSC_HZ 3570000 + +// External oscillator type. +//!< External clock signal +//#define BOARD_XOSC_TYPE XOSC_TYPE_EXTERNAL +//!< 32.768 kHz resonator on TOSC +//#define BOARD_XOSC_TYPE XOSC_TYPE_32KHZ +//!< 0.4 to 16 MHz resonator on XTALS +#define BOARD_XOSC_TYPE XOSC_TYPE_XTAL + +// External oscillator startup time +#define BOARD_XOSC_STARTUP_US 5000 + +#endif // CONF_BOARD_H diff --git a/DSTAT1/src/config/conf_clock.h b/DSTAT1/src/config/conf_clock.h new file mode 100644 index 0000000000000000000000000000000000000000..82610939d28c4d0cd95115b7f154637ba7ad25a6 --- /dev/null +++ b/DSTAT1/src/config/conf_clock.h @@ -0,0 +1,93 @@ +/** + * \file + * + * \brief Chip-specific system clock manager configuration + * + * Copyright (c) 2011 Atmel Corporation. All rights reserved. + * + * \asf_license_start + * + * 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. The name of Atmel may not be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * 4. This software may only be redistributed and used in connection with an + * Atmel microcontroller product. + * + * THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE + * EXPRESSLY AND SPECIFICALLY DISCLAIMED. IN NO EVENT SHALL ATMEL 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. + * + * \asf_license_stop + * + */ +#ifndef CONF_CLOCK_H_INCLUDED +#define CONF_CLOCK_H_INCLUDED + +//#define CONFIG_SYSCLK_SOURCE SYSCLK_SRC_RC2MHZ +//#define CONFIG_SYSCLK_SOURCE SYSCLK_SRC_RC32MHZ +//#define CONFIG_SYSCLK_SOURCE SYSCLK_SRC_RC32KHZ +//#define CONFIG_SYSCLK_SOURCE SYSCLK_SRC_XOSC +//#define CONFIG_SYSCLK_SOURCE SYSCLK_SRC_PLL + +/* Fbus = Fsys / (2 ^ BUS_div) */ +//#define CONFIG_SYSCLK_PSADIV SYSCLK_PSADIV_1 +//#define CONFIG_SYSCLK_PSBCDIV SYSCLK_PSBCDIV_1_1 + +//#define CONFIG_PLL0_SOURCE PLL_SRC_XOSC +//#define CONFIG_PLL0_SOURCE PLL_SRC_RC2MHZ +//#define CONFIG_PLL0_SOURCE PLL_SRC_RC32MHZ +#define CONFIG_PLL0_SOURCE PLL_SRC_XOSC + +/* Fpll = (Fclk * PLL_mul) / PLL_div */ +#define CONFIG_PLL0_MUL 7 +#define CONFIG_PLL0_DIV 1 + +/* External oscillator frequency range */ +//! 0.4 to 2 MHz frequency range +//#define CONFIG_XOSC_RANGE XOSC_RANGE_04TO2 +// 2 to 9 MHz frequency range +#define CONFIG_XOSC_RANGE XOSC_RANGE_2TO9 +//! 9 to 12 MHz frequency range +//define CONFIG_XOSC_RANGE XOSC_RANGE_9TO12 +//! 12 to 16 MHz frequency range +//define CONFIG_XOSC_RANGE XOSC_RANGE_12TO16 + +// *************************************************************** +// ** CONFIGURATION WITH USB ** +// *************************************************************** +//! The following clock configuraiton can be used for USB operation +//! It allows to operate USB using On-Chip RC oscillator at 48MHz +//! The RC oscillator is calibrated via USB Start Of Frame +//! Clk USB = 48MHz (used by USB) +//! Clk sys = 48MHz +//! Clk cpu/per = 24MHz +#define CONFIG_USBCLK_SOURCE USBCLK_SRC_RCOSC +#define CONFIG_OSC_RC32_CAL 48000000UL +#define CONFIG_OSC_AUTOCAL OSC_ID_RC32MHZ +#define CONFIG_OSC_AUTOCAL_REF_OSC OSC_ID_USBSOF +#define CONFIG_SYSCLK_SOURCE SYSCLK_SRC_RC32MHZ +#define CONFIG_SYSCLK_PSADIV SYSCLK_PSADIV_1 +#define CONFIG_SYSCLK_PSBCDIV SYSCLK_PSBCDIV_1_1 + +// ********** END OF USB CLOCK CONFIGURATION ********************** + + +#endif /* CONF_CLOCK_H_INCLUDED */ diff --git a/DSTAT1/src/config/conf_rtc.h b/DSTAT1/src/config/conf_rtc.h new file mode 100644 index 0000000000000000000000000000000000000000..ee43e88bc5183ae4aa01be6bde4a52a046cedd17 --- /dev/null +++ b/DSTAT1/src/config/conf_rtc.h @@ -0,0 +1,49 @@ +/** + * \file + * + * \brief RTC configuration + * + * Copyright (c) 2010 Atmel Corporation. All rights reserved. + * + * \asf_license_start + * + * 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. The name of Atmel may not be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * 4. This software may only be redistributed and used in connection with an + * Atmel microcontroller product. + * + * THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE + * EXPRESSLY AND SPECIFICALLY DISCLAIMED. IN NO EVENT SHALL ATMEL 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. + * + * \asf_license_stop + * + */ +#ifndef CONF_RTC_H +#define CONF_RTC_H + +#define CONFIG_RTC_PRESCALER RTC_PRESCALER_DIV1024_gc +#define CONFIG_RTC_CLOCK_SOURCE CLK_RTCSRC_RCOSC_gc +#define CONFIG_RTC_COMPARE_INT_LEVEL RTC_COMPINTLVL_OFF_gc +#define CONFIG_RTC_OVERFLOW_INT_LEVEL RTC_OVFINTLVL_OFF_gc + +#endif /* CONF_RTC_H */ diff --git a/DSTAT1/src/config/conf_sleepmgr.h b/DSTAT1/src/config/conf_sleepmgr.h new file mode 100644 index 0000000000000000000000000000000000000000..2ed302f272a2150e3c75be3ebd9c2fd398405187 --- /dev/null +++ b/DSTAT1/src/config/conf_sleepmgr.h @@ -0,0 +1,47 @@ +/** + * \file + * + * \brief Chip-specific sleep manager configuration + * + * Copyright (c) 2010 Atmel Corporation. All rights reserved. + * + * \asf_license_start + * + * 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. The name of Atmel may not be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * 4. This software may only be redistributed and used in connection with an + * Atmel microcontroller product. + * + * THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE + * EXPRESSLY AND SPECIFICALLY DISCLAIMED. IN NO EVENT SHALL ATMEL 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. + * + * \asf_license_stop + * + */ +#ifndef CONF_SLEEPMGR_H +#define CONF_SLEEPMGR_H + +// Sleep manager options +#define CONFIG_SLEEPMGR_ENABLE + +#endif /* CONF_SLEEPMGR_H */ diff --git a/DSTAT1/src/config/conf_spi_master.h b/DSTAT1/src/config/conf_spi_master.h new file mode 100644 index 0000000000000000000000000000000000000000..d7e3cf06042d684b48e45b8ef0245f741c46f954 --- /dev/null +++ b/DSTAT1/src/config/conf_spi_master.h @@ -0,0 +1,47 @@ +/** + * \file ********************************************************************* + * + * \brief Spi Master configuration for spi example + * + * Copyright (c) 2011 Atmel Corporation. All rights reserved. + * + * \asf_license_start + * + * 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. The name of Atmel may not be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * 4. This software may only be redistributed and used in connection with an + * Atmel microcontroller product. + * + * THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE + * EXPRESSLY AND SPECIFICALLY DISCLAIMED. IN NO EVENT SHALL ATMEL 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. + * + * \asf_license_stop + * + */ +#ifndef CONF_SPI_MASTER_H_INCLUDED +#define CONF_SPI_MASTER_H_INCLUDED + +//! Default Config Spi Master Dummy Field +#define CONFIG_SPI_MASTER_DUMMY 0xAA + +#endif /* CONF_SPI_MASTER_H_INCLUDED */ diff --git a/DSTAT1/src/config/conf_usb.h b/DSTAT1/src/config/conf_usb.h new file mode 100644 index 0000000000000000000000000000000000000000..e5aa444ecf96465c2a3ffb2f03b0f1897360cd99 --- /dev/null +++ b/DSTAT1/src/config/conf_usb.h @@ -0,0 +1,143 @@ +/** + * \file + * + * \brief USB configuration file for CDC application + * + * Copyright (c) 2009-2011 Atmel Corporation. All rights reserved. + * + * \asf_license_start + * + * 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. The name of Atmel may not be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * 4. This software may only be redistributed and used in connection with an + * Atmel microcontroller product. + * + * THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE + * EXPRESSLY AND SPECIFICALLY DISCLAIMED. IN NO EVENT SHALL ATMEL 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. + * + * \asf_license_stop + * + */ + +#ifndef _CONF_USB_H_ +#define _CONF_USB_H_ + +#include "compiler.h" + +/** + * USB Device Configuration + * @{ + */ + +//! Device definition (mandatory) +#define USB_DEVICE_VENDOR_ID 0x0092 +#define USB_DEVICE_PRODUCT_ID 0x0092 +#define USB_DEVICE_MAJOR_VERSION 1 +#define USB_DEVICE_MINOR_VERSION 0 +#define USB_DEVICE_POWER 100 // Consumption on Vbus line (mA) +#define USB_DEVICE_ATTR \ +(USB_CONFIG_ATTR_SELF_POWERED) + //(USB_CONFIG_ATTR_BUS_POWERED) +// (USB_CONFIG_ATTR_REMOTE_WAKEUP|USB_CONFIG_ATTR_SELF_POWERED) +// (USB_CONFIG_ATTR_REMOTE_WAKEUP|USB_CONFIG_ATTR_BUS_POWERED) + +//! USB Device string definitions (Optional) +#define USB_DEVICE_MANUFACTURE_NAME "Wheeler Lab" +#define USB_DEVICE_PRODUCT_NAME "DStat" +// #define USB_DEVICE_SERIAL_NAME "12...EF" + + +/** + * Device speeds support + * Low speed not supported by CDC + * @{ + */ +//! To authorize the High speed +#if (UC3A3||UC3A4) +//#define USB_DEVICE_HS_SUPPORT +#endif +//@} + + +/** + * USB Device Callbacks definitions (Optional) + * @{ + */ +#define UDC_VBUS_EVENT(b_vbus_high) stdio_usb_vbus_event(b_vbus_high) +// #define UDC_SOF_EVENT() user_callback_sof_action() +// #define UDC_SUSPEND_EVENT() user_callback_suspend_action() +// #define UDC_RESUME_EVENT() user_callback_resume_action() +//! Mandatory when USB_DEVICE_ATTR authorizes remote wakeup feature +// #define UDC_REMOTEWAKEUP_ENABLE() user_callback_remotewakeup_enable() +// #define UDC_REMOTEWAKEUP_DISABLE() user_callback_remotewakeup_disable() +//! When a extra string descriptor must be supported +//! other than manufacturer, product and serial string +// #define UDC_GET_EXTRA_STRING() +//@} + +//@} + + +/** + * USB Interface Configuration + * @{ + */ +/** + * Configuration of CDC interface + * @{ + */ + +//! Number of communication port used (1 to 3) +#define UDI_CDC_PORT_NB 1 + +//! Interface callback definition +#define UDI_CDC_ENABLE_EXT() true +#define UDI_CDC_DISABLE_EXT() +#define UDI_CDC_RX_NOTIFY() +#define UDI_CDC_SET_CODING_EXT(cfg) +#define UDI_CDC_SET_DTR_EXT(set) +#define UDI_CDC_SET_RTS_EXT(set) + +//! Define it when the transfer CDC Device to Host is a low rate (<512000 bauds) +//! to reduce CDC buffers size +//#define UDI_CDC_LOW_RATE + +//! Default configuration of communication port +#define UDI_CDC_DEFAULT_RATE 10240000 +#define UDI_CDC_DEFAULT_STOPBITS CDC_STOP_BITS_1 +#define UDI_CDC_DEFAULT_PARITY CDC_PAR_NONE +#define UDI_CDC_DEFAULT_DATABITS 8 +//@} +//@} + + +/** + * USB Device Driver Configuration + * @{ + */ +//@} + +//! The includes of classes and other headers must be done at the end of this file to avoid compile error +#include "udi_cdc_conf.h" + +#endif // _CONF_USB_H_ diff --git a/DSTAT1/src/main.c b/DSTAT1/src/main.c new file mode 100644 index 0000000000000000000000000000000000000000..1e1c819558d38ac18281ede86d444de154a5bf0c --- /dev/null +++ b/DSTAT1/src/main.c @@ -0,0 +1,1522 @@ +/** + * \file + * + * \brief Empty user application template + * + */ + +/* + * Include header files for all drivers that have been imported from + * Atmel Software Framework (ASF). + */ +#include +#include +#include +#include +#include +#include + +volatile uint8_t gain = POT_GAIN_30k; +volatile int32_t voltage = 0; +volatile uint16_t dacindex = 0; +uint16_t dacindex_stop = 0; +volatile int8_t up = 1; +volatile uint16_t iter = 0; +uint16_t* eis_ptr = 0; +volatile uint16_t cycles = 0; +volatile uint16_t samples = 0; +volatile uint16_t tcf0period = 0; +uint32_t skip_samples = 0; + +uint8_t ads_buff = ADS_BUFF_ON; +uint8_t ads_datarate = ADS_DR_60; +uint8_t ads_pga = ADS_PGA_2; + +int16_t eis_data[500]; + +typedef void (*port_callback_t) (void); + +static port_callback_t porte_int0_callback; +static port_callback_t porte_int1_callback; + +static void tcf0_ovf_callback(void); +static void tcf0_ovf_callback_eis(void); +static void tce0_ovf_callback_eis(void); +static void tcd0_ovf_callback_eis(void); +static void porte_int0_lsv(void); +static void tce1_ovf_callback_lsv(void); +static void lsv_cca_callback(void); +static void porte_int0_ca(void); +static void ca_cca_callback(void); +/*static void tce1_ovf_callback(void);*/ + +int8_t autogainswitch(void){ + extern int8_t over_under[ADS_OVER_UNDER_SAMPLES]; + int8_t overcurrent = 0; + static uint8_t hysteresis = 0; + static uint8_t last_return = 0; + + if (last_return==1) + { + last_return=0; + return 1; + } + + if (gain == POT_GAIN_500M) + return 0; + + if (hysteresis < ADS_OVER_UNDER_SAMPLES-1){ + ++hysteresis; + return 0; + } + + + for (uint16_t i = 0; i < ADS_OVER_UNDER_SAMPLES; ++i) + { + overcurrent += over_under[i]; + } + /*printf("OC: %i\n\r", overcurrent);*/ + + if (overcurrent == ADS_OVER_UNDER_SAMPLES && gain != POT_GAIN_30k) + { + pot_set_gain(--gain); + last_return=1; + hysteresis = 0; + for (uint16_t i = 0; i < ADS_OVER_UNDER_SAMPLES; ++i) + over_under[i]=0; + + return 1; + } + + if ((overcurrent*-1) == (ADS_OVER_UNDER_SAMPLES) && gain < POT_GAIN_3M) + { + if (hysteresis < ADS_OVER_UNDER_SAMPLES+3){ + ++hysteresis; + return 0; + + } + pot_set_gain(++gain); + last_return=1; + hysteresis = 0; + for (uint16_t i = 0; i < ADS_OVER_UNDER_SAMPLES; ++i) + over_under[i]=0; + + return 1; + } + + hysteresis = 0; + return 0; +} + +void pot_set_gain(uint8_t gain){ + switch (gain){ + case POT_GAIN_30k: + ioport_configure_port_pin(&PORTD, PIN3_bm, IOPORT_INIT_LOW | IOPORT_DIR_OUTPUT); + ioport_configure_port_pin(&PORTD, PIN4_bm, IOPORT_INIT_LOW | IOPORT_DIR_OUTPUT); + printf("INFO: 30k\n\r"); + break; + case POT_GAIN_300k: + ioport_configure_port_pin(&PORTD, PIN3_bm, IOPORT_INIT_LOW | IOPORT_DIR_OUTPUT); + ioport_configure_port_pin(&PORTD, PIN4_bm, IOPORT_INIT_HIGH | IOPORT_DIR_OUTPUT); + printf("INFO: 300k\n\r"); + break; + case POT_GAIN_3M: + ioport_configure_port_pin(&PORTD, PIN3_bm, IOPORT_INIT_HIGH | IOPORT_DIR_OUTPUT); + ioport_configure_port_pin(&PORTD, PIN4_bm, IOPORT_INIT_LOW | IOPORT_DIR_OUTPUT); + printf("INFO: 3M\n\r"); + break; + case POT_GAIN_500M: + ioport_configure_port_pin(&PORTD, PIN3_bm, IOPORT_INIT_HIGH | IOPORT_DIR_OUTPUT); + ioport_configure_port_pin(&PORTD, PIN4_bm, IOPORT_INIT_HIGH | IOPORT_DIR_OUTPUT); + printf("INFO: 500M\n\r");; + break; + default: + printf("WAR: Invalid pot gain.\n\r"); + break; + + return; + } +} + +void pot_LP(uint8_t lponoff){ + if (lponoff == POT_LP_OFF) + { + ioport_configure_port_pin(&PORTD, PIN5_bm, IOPORT_INIT_LOW | IOPORT_DIR_OUTPUT); + ioport_configure_port_pin(&PORTE, PIN0_bm, IOPORT_INIT_LOW | IOPORT_DIR_OUTPUT); + return; + } + if (lponoff == POT_LP_ON) + { + ioport_configure_port_pin(&PORTD, PIN5_bm, IOPORT_INIT_HIGH | IOPORT_DIR_OUTPUT); + ioport_configure_port_pin(&PORTE, PIN0_bm, IOPORT_INIT_HIGH | IOPORT_DIR_OUTPUT); + return; + } + + printf("WAR: Invalid pot LP setting.\n\r"); + return; +} + +inline void pot_exp_start(void){ + ioport_configure_port_pin(&PORTD, PIN1_bm, IOPORT_INIT_HIGH | IOPORT_DIR_OUTPUT); + ioport_configure_port_pin(&PORTD, PIN2_bm, IOPORT_INIT_HIGH | IOPORT_DIR_OUTPUT); + ioport_configure_port_pin(&PORTD, PIN0_bm, IOPORT_INIT_HIGH | IOPORT_DIR_OUTPUT); +} + +inline void pot_exp_stop(void){ + ioport_configure_port_pin(&PORTD, PIN1_bm, IOPORT_INIT_LOW | IOPORT_DIR_OUTPUT); + ioport_configure_port_pin(&PORTD, PIN2_bm, IOPORT_INIT_LOW | IOPORT_DIR_OUTPUT); + ioport_configure_port_pin(&PORTD, PIN0_bm, IOPORT_INIT_LOW | IOPORT_DIR_OUTPUT); +} + +void cv_experiment(int16_t v1, int16_t v2, int16_t start, uint8_t scans, uint16_t slope){ + // check if start is [v1,v2] + int8_t firstrun = 1; + + if((start < v1 && start < v2) || (start > v1 && start > v2)) + { + printf("ERR: Start must be within [v1, v2]\n\r"); + return; + } + + RTC.CTRL = RTC_PRESCALER_OFF_gc; + while (RTC.STATUS & RTC_SYNCBUSY_bm); + RTC.CNT = 0; + RTC.PER = 0xffff; + RTC.CTRL = RTC_PRESCALER_DIV1024_gc; // 1 s tick + + + while(scans > 0){ + if (start != v1){ + lsv_experiment(start,v1,slope,firstrun); + firstrun = 0; + } + if (start == v2){ + firstrun = -1; + } + lsv_experiment(v1,v2,slope, firstrun); + firstrun = -1; + if (start != v2) + lsv_experiment(v2,start,slope, firstrun); + scans--; + firstrun = 0; + } + + printf("Time: %lu s \n\r", rtc_get_time()); + + return; +} + +void lsv_experiment(int16_t start, int16_t stop, uint16_t slope, int8_t first_run){ + //check experiment limits + if(start<-1500 || start>1500 ||start==stop|| stop<-1500 || stop>1500 || slope>7000) + { + printf("ERR: Experiment parameters outside limits\n\r"); + return; + } + + uint16_t dacindex_start = ceil(start*(65535/(double)3000)+32767); + dacindex_stop = ceil(stop*(65535/(double)3000)+32767); +// uint16_t period; + uint32_t timer_period; + uint16_t temp_div; + + + printf("Firstrun:%i\n\r", first_run); + + max5443_set_voltage1(dacindex_start); + + if (first_run == 1 || first_run == 2){ + + pot_exp_start(); + ads1255_rdatac(); + tc_enable(&TCC1); + + ads1255_sync(); + +// voltage = TCE1.CNT; + tc_enable(&TCC0); + tc_set_overflow_interrupt_callback(&TCC0, tcf0_ovf_callback); + tc_set_overflow_interrupt_callback(&TCC1, tce1_ovf_callback_lsv); + tc_set_cca_interrupt_callback(&TCC1, lsv_cca_callback); + porte_int0_callback = porte_int0_lsv; + + //set EVCH0 event + EVSYS.CH0MUX = EVSYS_CHMUX_TCC0_OVF_gc; + EVSYS.CH0CTRL = 0; + + timer_period = ceil(1/((double)slope/(3000./65535))*(F_CPU)); + temp_div = ceil(timer_period/65535.); + + if (temp_div <= 1){ + tc_write_clock_source(&TCC0,TC_CLKSEL_DIV1_gc); + } + else if (temp_div == 2){ + tc_write_clock_source(&TCC0,TC_CLKSEL_DIV2_gc); + timer_period /= 2; + } + else if (temp_div <= 4){ + tc_write_clock_source(&TCC0,TC_CLKSEL_DIV4_gc); + timer_period /= 4; + } + else if (temp_div <= 8){ + tc_write_clock_source(&TCC0,TC_CLKSEL_DIV8_gc); + timer_period /= 8; + } + else if (temp_div <= 64){ + tc_write_clock_source(&TCC0,TC_CLKSEL_DIV64_gc); + timer_period /= 64; + } + else if (temp_div <= 256){ + tc_write_clock_source(&TCC0,TC_CLKSEL_DIV256_gc); + timer_period /= 256; + } + else if (temp_div <= 1024){ + tc_write_clock_source(&TCC0,TC_CLKSEL_DIV1024_gc); + timer_period /= 1024; + } + else{ + printf("ERR: Frequency/ADC rate is too low\n\r"); + return; + } + + printf("Period:%lu\n\r", timer_period); + ads1255_wakeup(); + tc_write_period(&TCC1, 0xffff); + tc_write_period(&TCC0, (uint16_t)timer_period); + } + + TCC1.CNT = dacindex_start; + + if (stop > start) + { + up = 1; + tc_set_direction(&TCC1, TC_UP); + } + else + { + up = -1; + tc_set_direction(&TCC1, TC_DOWN); + } + + tc_write_cc(&TCC1, TC_CCA, dacindex_stop); + tc_enable_cc_channels(&TCC1, TC_CCAEN); + TCC0.CNT = 0; + + tc_set_cca_interrupt_level(&TCC1, TC_INT_LVL_HI); + tc_set_overflow_interrupt_level(&TCC0, TC_OVFINTLVL_MED_gc); + PORTE.INTCTRL = PORT_INT0LVL_LO_gc; + + tc_write_clock_source(&TCC1, TC_CLKSEL_EVCH0_gc); + + + while (up != 0) + { + } + + if (first_run == -1 || first_run == 2) + { + tc_disable(&TCC0); + TCC0.CNT = 0x0; + tc_disable(&TCC1); + pot_exp_stop(); + ads1255_standby(); + } + + return; +} + +static void porte_int0_lsv(void){ + if (autogainswitch()==0){ + while (ioport_pin_is_high(IOPORT_CREATE_PIN(PORTE, 3))); + if (gain == POT_GAIN_30k) + { + printf("%u, %ld\n\r", TCC1.CNT, ads1255_read()*100); + } + else if (gain == POT_GAIN_300k) + { + printf("%u, %ld\n\r", TCC1.CNT, ads1255_read()*10); + } + else if (gain == POT_GAIN_3M) + { + printf("%u, %ld\n\r", TCC1.CNT, ads1255_read()); + } + else + { + printf("%u, %lu\n\r", TCC1.CNT, ads1255_read()); + } + } + else{ + while (ioport_pin_is_high(IOPORT_CREATE_PIN(PORTE, 3))); + ads1255_read(); + } +} + +static void tcf0_ovf_callback(void){ +// if (dacindex == dacindex_stop) +// { +// PORTE.INTCTRL = PORT_INT0LVL_OFF_gc; +// tc_set_overflow_interrupt_level(&TCF0, TC_OVFINTLVL_OFF_gc); +// up = 0; +// return; +// } + + max5443_set_voltage1(TCC1.CNT); + +// printf("TCC1.CNT %u\n\r", TCC1.CNT); +// voltage = (int32_t)round((dacindex-32767L)*((double)3000/65535)*1000); +// +// if (up == 1) +// dacindex++; +// else +// dacindex--; +} + +static void tce1_ovf_callback_lsv(void){ + printf("TCE1_OVF\n\r"); + PORTE.INTCTRL = PORT_INT0LVL_OFF_gc; + tc_set_overflow_interrupt_level(&TCC0, TC_OVFINTLVL_OFF_gc); + tc_set_overflow_interrupt_level(&TCC1, TC_OVFINTLVL_OFF_gc); +// tc_write_clock_source(&TCC0, TC_CLKSEL_OFF_gc); + up = 0; + return; +} + +static void lsv_cca_callback(void) + { + printf("CCA\n\r"); + PORTE.INTCTRL = PORT_INT0LVL_OFF_gc; + tc_set_overflow_interrupt_level(&TCC0, TC_OVFINTLVL_OFF_gc); +// tc_write_clock_source(&TCC0, TC_CLKSEL_OFF_gc); + tc_set_cca_interrupt_level(&TCC1, TC_INT_LVL_OFF); + up = 0; + return; + } + + +void chronoamp(uint16_t steps, uint16_t step_dac[], uint16_t step_seconds[]){ + + while (RTC.STATUS & RTC_SYNCBUSY_bm); + RTC.PER = 999; + while (RTC.STATUS & RTC_SYNCBUSY_bm); + RTC.CTRL = RTC_PRESCALER_DIV1_gc; + + EVSYS.CH0MUX = EVSYS_CHMUX_RTC_OVF_gc; + + porte_int0_callback = porte_int0_ca; + + tc_enable(&TCC0); + tc_set_cca_interrupt_callback(&TCC0, ca_cca_callback); + + ads1255_rdatac(); + ads1255_wakeup(); + + tc_write_period(&TCC0,0xffff); + tc_write_clock_source(&TCC0, TC_CLKSEL_EVCH0_gc); + tc_set_direction(&TCC0, TC_UP); + tc_enable_cc_channels(&TCC0, TC_CCAEN); + tc_set_cca_interrupt_level(&TCC0, TC_INT_LVL_HI); + TCC0.CNT = 0; + + pot_exp_start(); + + for (uint8_t i = 0; i < steps; ++i) + { + up = 1; + tc_write_cc(&TCC0, TC_CCA, TCC0.CNT+step_seconds[i]-1); + RTC.CNT=0; + max5443_set_voltage1(step_dac[i]); + PORTE.INTCTRL = PORT_INT0LVL_LO_gc; + while (up !=0); + } + + tc_set_cca_interrupt_level(&TCC0, TC_INT_LVL_OFF); + tc_write_clock_source(&TCC0, TC_CLKSEL_OFF_gc); + tc_disable(&TCC0); + pot_exp_stop(); + ads1255_standby(); + + return; +} + +static void porte_int0_ca(void){ + if (autogainswitch()==0){ + while (ioport_pin_is_high(IOPORT_CREATE_PIN(PORTE, 3))); + if (gain == POT_GAIN_30k) + { + printf("%u.%03u, %ld\n\r", TCC0.CNT, RTC.CNT, ads1255_read()*100); + } + else if (gain == POT_GAIN_300k) + { + printf("%u.%03u, %ld\n\r", TCC0.CNT, RTC.CNT, ads1255_read()*10); + } + else if (gain == POT_GAIN_3M) + { + printf("%u.%03u, %ld\n\r", TCC0.CNT, RTC.CNT, ads1255_read()); + } + else + { + printf("%u.%03u, %ld\n\r", TCC0.CNT, RTC.CNT, ads1255_read()); + } + } + else{ + while (ioport_pin_is_high(IOPORT_CREATE_PIN(PORTE, 3))); + ads1255_read(); + } +} + +static void ca_cca_callback(void) + { + PORTE.INTCTRL = PORT_INT0LVL_OFF_gc; + up = 0; + return; + } + +void swv_experiment(int16_t start, int16_t stop, uint16_t step, uint16_t pulse_height, uint16_t frequency){ + //check experiment limits +// if((start-pulse_height)<-1500 || (start+pulse_height)>(1500)|| start == stop || stop<-1500 || (stop+pulse_height)>1500 || step<1 || step>1500 || pulse_height > 1500 || pulse_height < 1) +// { +// printf("ERR: Experiment parameters outside limits\n\r"); +// //return; +// } + + int32_t forward = 0; + int32_t reverse = 0; + int32_t data_buffer; + uint8_t direction; + uint16_t dacindex_start = ceil((start)*(65535/(double)3000))+32767; + uint16_t dacindex_stop = ceil(stop*(65535/(double)3000))+32767; + uint16_t dacindex_step = ceil(step*(65535/(double)3000)); + uint16_t dacindex_pulse_height = ceil(pulse_height*(65535/(double)3000)); + uint16_t dacindex = dacindex_start; + uint32_t period; +// uint8_t adc_dr; +// uint16_t adc_period; + + if (start < stop) + { + direction = 1; + } + else + { + direction = -1; + } + +// dacindex_step *= direction; +// dacindex_pulse_height *= direction; + + tc_enable(&TCF0); + +// switch (ADCfrequency){ +// case ADS_F_2_5: +// adc_dr = ADS_DR_2_5; +// adc_period = 40018; // in ms*100 +// break; +// case ADS_F_5: +// adc_dr = ADS_DR_5; +// adc_period = 20018; +// break; +// case ADS_F_10: +// adc_dr = ADS_DR_10; +// adc_period = 10018; +// break; +// case ADS_F_15: +// adc_dr = ADS_DR_15; +// adc_period = 6684; +// break; +// case ADS_F_25: +// adc_dr = ADS_DR_25; +// adc_period = 4018; +// break; +// case ADS_F_30: +// adc_dr = ADS_DR_30; +// adc_period = 3351; +// break; +// case ADS_F_50: +// adc_dr = ADS_DR_50; +// adc_period = 2018; +// break; +// case ADS_F_60: +// adc_dr = ADS_DR_60; +// adc_period = 1684; +// break; +// case ADS_F_100: +// adc_dr = ADS_DR_100; +// adc_period = 1018; +// break; +// case ADS_F_500: +// adc_dr = ADS_DR_500; +// adc_period = 218; +// break; +// case ADS_F_1000: +// adc_dr = ADS_DR_1000; +// adc_period = 118; +// break; +// case ADS_F_2000: +// adc_dr = ADS_DR_2000; +// adc_period = 68; +// break; +// case ADS_F_3750: +// adc_dr = ADS_DR_3750; +// adc_period = 44; +// break; +// case ADS_F_7500: +// adc_dr = ADS_DR_7500; +// adc_period = 31; +// break; +// case ADS_F_15000: +// adc_dr = ADS_DR_15000; +// adc_period = 25; +// break; +// case ADS_F_30000: +// adc_dr = ADS_DR_30000; +// adc_period = 21; +// break; +// default: +// printf("ERR:Invalid ADC frequency.\n\r"); +// return; +// } + + frequency *= 2; + + //calculate time to ADC trigger + period = ceil((1/(double)frequency/*-(double)adc_period/100000.*/)*F_CPU); + uint8_t temp_div = ceil((double)period/UINT16_MAX); + + if (temp_div == 1) + tc_write_clock_source(&TCF0,TC_CLKSEL_DIV1_gc); + else if (temp_div == 2){ + tc_write_clock_source(&TCF0,TC_CLKSEL_DIV2_gc); + period /= 2; + } + else if (temp_div <= 4){ + tc_write_clock_source(&TCF0,TC_CLKSEL_DIV4_gc); + period /= 4; + } + else if (temp_div <= 8){ + tc_write_clock_source(&TCF0,TC_CLKSEL_DIV8_gc); + period /= 8; + } + else if (temp_div <= 64){ + tc_write_clock_source(&TCF0,TC_CLKSEL_DIV64_gc); + period /= 64; + } + else if (temp_div <= 256){ + tc_write_clock_source(&TCF0,TC_CLKSEL_DIV256_gc); + period /= 256; + } + else if (temp_div <= 1024){ + tc_write_clock_source(&TCF0,TC_CLKSEL_DIV1024_gc); + period /= 1024; + } + else{ + printf("Frequency/ADC rate is too low\n\r"); + return; + } + + printf("Period: %u \n\r", (uint16_t)period); + printf("Tempdiv: %u \n\r", (uint16_t)temp_div); + + tc_write_period(&TCF0, (uint16_t)period); + + +/* ads1255_setup(ADC_buff, adc_dr, ADC_pga);*/ + if (direction == 1) + max5443_set_voltage1(dacindex+dacindex_pulse_height); + else + max5443_set_voltage1(dacindex-dacindex_pulse_height); + + ads1255_wakeup(); + ads1255_rdatac(); + + ads1255_sync(); + + pot_exp_start(); + TCF0.CNT = 0; + while (!tc_is_overflow(&TCF0)); + ads1255_wakeup(); + TCF0.CNT = 0; + + while ((dacindex <= dacindex_stop && direction == 1) || (dacindex >= dacindex_stop && direction == 0)){ + tc_clear_overflow(&TCF0); + + if (gain == POT_GAIN_30k) + { + printf("%u, %li, %li\n\r", dacindex, forward*100, reverse*100); + } + else if (gain == POT_GAIN_300k) + { + printf("%u, %li\n\r", dacindex, (forward-reverse)*10); + } + else + { + printf("%u, %li\n\r", dacindex, forward-reverse); + } + + while (!tc_is_overflow(&TCF0)){ + while (ioport_pin_is_low(IOPORT_CREATE_PIN(PORTE, 3))); + while (ioport_pin_is_high(IOPORT_CREATE_PIN(PORTE, 3))); + forward = ads1255_read_fast24(); + } + + if (direction == 1) + max5443_set_voltage1(dacindex-dacindex_pulse_height); + else + max5443_set_voltage1(dacindex+dacindex_pulse_height); + + + tc_clear_overflow(&TCF0); + dacindex += dacindex_step; + + while (!tc_is_overflow(&TCF0));{ + while (ioport_pin_is_low(IOPORT_CREATE_PIN(PORTE, 3))); + while (ioport_pin_is_high(IOPORT_CREATE_PIN(PORTE, 3))); + reverse = ads1255_read_fast24(); + } + + if (direction == 1) + max5443_set_voltage1(dacindex+dacindex_pulse_height); + else + max5443_set_voltage1(dacindex-dacindex_pulse_height); + + } + + pot_exp_stop(); + tc_write_clock_source(&TCF0, TC_CLKSEL_OFF_gc); + tc_disable(&TCF0); + tc_write_count(&TCF0,0); + ads1255_standby(); + + return; +} + +// static void porte_int0_swv{ +// +// up = 0; +// }; + +void eis_waveform(int16_t offset, int16_t amplitude, uint32_t freq, uint16_t cycle){ + + cycles = cycle; + uint16_t dacindex = ceil(offset*(65535/(double)3000)+32767); + + max5443_set_voltage1(dacindex); + + tc_enable(&TCF0); + tc_set_overflow_interrupt_callback(&TCF0, tcf0_ovf_callback_eis); + tc_enable(&TCE1); + tc_enable(&TCE0); + tc_enable(&TCD0); + + tc_set_overflow_interrupt_callback(&TCE0, tce0_ovf_callback_eis); + tc_set_overflow_interrupt_callback(&TCD0, tcd0_ovf_callback_eis); + + if (freq > 10000) + { + skip_samples = 300000UL/freq; + } + + ////// + + for (int i = 0; i<500; i++) + eis_data[i]=0; + + ////// + +// if (freq > 1000) +// samples=ceil(400000/freq); +// else +// samples = 500; + samples = 500; + + uint32_t timer_period; + uint8_t temp_div; + uint16_t V[samples]; + eis_ptr = &V; + up = 1; + + for (int i = 0; i < samples; i++) + { + V[i] = dacindex + floor((cos(2*M_PI*i/(samples-1))*amplitude)*(65536/(double)3000)); +// printf("%u\n\r", V[i]); + } + + pot_exp_start(); + + timer_period = round(F_CPU/((freq)/10.*(double)samples)); + printf("timer_period %lu\n\r", timer_period); + temp_div = ceil(timer_period/65535.); + printf("temp_div %u\n\r", temp_div); + EVSYS.CH0MUX = EVSYS_CHMUX_TCF0_OVF_gc; //TCF0: DAC timer, TCE1: cos iterator, TCE0: cycle counter + EVSYS.CH1MUX = EVSYS_CHMUX_TCE1_OVF_gc; + EVSYS.CH2MUX = EVSYS_CHMUX_PORTE_PIN3_gc; + + + if (temp_div <= 1){ + tc_write_clock_source(&TCF0,TC_CLKSEL_DIV1_gc); + printf("DIV1_gc\n\r"); + } + else if (temp_div == 2){ + tc_write_clock_source(&TCF0,TC_CLKSEL_DIV2_gc); + timer_period /= 2; + } + else if (temp_div <= 4){ + tc_write_clock_source(&TCF0,TC_CLKSEL_DIV4_gc); + timer_period /= 4; + } + else if (temp_div <= 8){ + tc_write_clock_source(&TCF0,TC_CLKSEL_DIV8_gc); + timer_period /= 8; + } + else if (temp_div <= 64){ + tc_write_clock_source(&TCF0,TC_CLKSEL_DIV64_gc); + timer_period /= 64; + } + else if (temp_div <= 256){ + tc_write_clock_source(&TCF0,TC_CLKSEL_DIV256_gc); + timer_period /= 256; + } + else if (temp_div <= 1024){ + tc_write_clock_source(&TCF0,TC_CLKSEL_DIV1024_gc); + timer_period /= 1024; + } + else{ + printf("ERR: Frequency/ADC rate is too low\n\r"); + return; + } + + tcf0period = (uint16_t)timer_period; + printf("tcf0max = %lu\n\r", tcf0period*(uint32_t)samples); + + tc_write_period(&TCF0, (uint16_t)timer_period); + tc_write_period(&TCE1, samples-1); + tc_write_period(&TCE0, cycles); + tc_write_period(&TCD0, skip_samples); + + ads1255_wakeup(); + ads1255_rdatac(); + TCF0.CNT = 0; + TCE1.CNT = 0; + TCE0.CNT = 1; + TCD0.CNT = 1; + + tc_write_clock_source(&TCE1, TC_CLKSEL_EVCH0_gc); + tc_write_clock_source(&TCE0, TC_CLKSEL_EVCH1_gc); + tc_write_clock_source(&TCD0, TC_CLKSEL_EVCH2_gc); + + if (freq > 10000) + tc_set_overflow_interrupt_level(&TCD0, TC_OVFINTLVL_MED_gc); + else + PORTE.INTCTRL = PORT_INT1LVL_MED_gc; + + tc_set_overflow_interrupt_level(&TCF0, TC_OVFINTLVL_LO_gc); + tc_set_overflow_interrupt_level(&TCE0, TC_OVFINTLVL_HI_gc); + + while (up != 0) + { + } + + tc_write_clock_source(&TCF0, TC_CLKSEL_OFF_gc); + tc_write_clock_source(&TCE1, TC_CLKSEL_OFF_gc); + tc_write_clock_source(&TCE0, TC_CLKSEL_OFF_gc); + tc_write_clock_source(&TCD0, TC_CLKSEL_OFF_gc); + tc_disable(&TCF0); + TCF0.CNT = 0x0; + + ads1255_standby(); + + for (uint16_t i=0; i<500; i++){ + if (eis_data[i] !=0) + printf("%i, %i\n\r", i, eis_data[i]); + } +// tc_disable(&TCE1); +// TCE1.CNT = 0x0; + return; +} + +static void tcf0_ovf_callback_eis(void){ + + max5443_set_voltage1(*(eis_ptr+TCE1.CNT)); + return; +} + +static void tce0_ovf_callback_eis(void){ + printf("TCC0_OVF\n\r"); + tc_set_overflow_interrupt_level(&TCF0, TC_OVFINTLVL_OFF_gc); + tc_set_overflow_interrupt_level(&TCD0, TC_OVFINTLVL_OFF_gc); + PORTE.INTCTRL = PORT_INT1LVL_OFF_gc; + + up = 0; + tc_set_overflow_interrupt_level(&TCE0, TC_OVFINTLVL_OFF_gc); + return; +} + +static void tcd0_ovf_callback_eis(void){ + uint16_t position = TCE1.CNT; + int16_t data_buff = ads1255_read_fast(); + + if (eis_data[position] == 0) + eis_data[position] = data_buff; + else + eis_data[position] = (eis_data[position] & data_buff)+((eis_data[position]^data_buff)>>1); + + return; +} + +void sw_test(uint16_t frequency){ + uint16_t dacindex_start = round((-1400)*(65536/(double)3000))+32768; + uint16_t dacindex_stop = round(1400*(65536/(double)3000))+32768; + uint32_t period; + + tc_enable(&TCF0); + + //calculate time to ADC trigger + period = round(((1/(double)frequency)*F_CPU)); + uint8_t temp_div = ceil(period/UINT16_MAX); + + if (temp_div == 1) + tc_write_clock_source(&TCF0,TC_CLKSEL_DIV1_gc); + else if (temp_div == 2){ + tc_write_clock_source(&TCF0,TC_CLKSEL_DIV2_gc); + period /= 2; + } + else if (temp_div <= 4){ + tc_write_clock_source(&TCF0,TC_CLKSEL_DIV4_gc); + period /= 4; + } + else if (temp_div <= 8){ + tc_write_clock_source(&TCF0,TC_CLKSEL_DIV8_gc); + period /= 8; + } + else if (temp_div <= 64){ + tc_write_clock_source(&TCF0,TC_CLKSEL_DIV64_gc); + period /= 64; + } + else if (temp_div <= 256){ + tc_write_clock_source(&TCF0,TC_CLKSEL_DIV256_gc); + period /= 256; + } + else if (temp_div <= 1024){ + tc_write_clock_source(&TCF0,TC_CLKSEL_DIV1024_gc); + period /= 1024; + } + else{ + printf("ERR: Frequency/ADC rate is too low\n\r"); + return; + } + + tc_write_period(&TCF0, (uint16_t)period/2); + pot_exp_start(); + tc_write_count(&TCF0,0); + + while (1){ + tc_clear_overflow(&TCF0); + while (!tc_is_overflow(&TCF0)); + max5443_set_voltage1(dacindex_start); + tc_clear_overflow(&TCF0); + while (!tc_is_overflow(&TCF0)); + max5443_set_voltage1(dacindex_stop); + } + pot_exp_stop(); + tc_disable(&TCF0); + tc_write_count(&TCF0,0); + return; +} + +void sine_impedance_spec(int16_t potential, uint16_t freq_min, uint16_t freq_max, uint16_t freq_step, uint16_t amplitude, uint16_t cycles){ + if(potential<-1500 || potential>1500) + { + printf("ERR: Experiment parameters outside limits\n\r"); + return; + } + + uint16_t dacindex_start = ceil(potential*(65535/(double)3000))+32767; + /*uint16_t cycle_points = round(2*amplitude/(double)(3000/65536));*/ + uint16_t steps = ceil((freq_max-freq_min)/freq_step); + int32_t temp_mag = 0; + int32_t temp_phase = 0; + uint32_t I[SIN_IMP_CYCLEPTS]; + uint32_t timer_period; + uint8_t temp_div; + uint16_t V[SIN_IMP_CYCLEPTS]; + unsigned int minimum, maximum; + + tc_enable(&TCF0); + ads1255_rdatac(); + pot_exp_start(); + + for (int i = 0; i < SIN_IMP_CYCLEPTS; i++) + { + V[i] = dacindex_start + round((sin(2*M_PI*i/SIN_IMP_CYCLEPTS)*amplitude)*(65536/(double)3000)); + printf("%u\n\r", V[i]); + } + + for (int i = 0; i I[maximum]) + maximum = z; + if (I[z] < I[minimum]) + minimum = z; + } + + temp_mag += ((I[maximum]-I[minimum])>>1); + temp_phase += ((maximum+minimum)>>1); + } + + printf("%u, %li, %li\n\r", freq_min+freq_step*i, temp_mag/cycles, temp_phase/cycles); + + } + pot_exp_stop(); + tc_disable(&TCF0); + tc_write_count(&TCF0,0); + +} + +void menu(uint8_t selection){ + int16_t start = 2000; + int16_t stop = 2000; + uint16_t slope = 0; + uint16_t height = 0; + short unsigned int scans = 0; + int16_t v1 = 2000; + int16_t v2 = 2000; + uint32_t freq = 120000; + uint16_t periods = 0; + uint16_t amp_dac[20]; + uint16_t amp_seconds[20]; + + char input = 'x'; + + switch (selection) + { + case MENU_OPS: + printf("Options:\n\r"); + + do { + printf("ADS Buffer (Y/N): "); + scanf("%c", &input); + printf("%c\n\r", input); + + if (input == 'y' || input == 'Y') + ads_buff = ADS_BUFF_ON; + else if (input == 'n' || input == 'N') + ads_buff = ADS_BUFF_OFF; + }while (!(input == 'y'||input == 'Y'||input == 'n'||input == 'N')); + + do { + printf("ADS sample rate: \n\r"); + printf("1 2.5 Hz\n\r"); + printf("2 5 Hz\n\r"); + printf("3 10 Hz\n\r"); + printf("4 15 Hz\n\r"); + printf("5 25 Hz\n\r"); + printf("6 30 Hz\n\r"); + printf("7 50 Hz\n\r"); + printf("8 60 Hz\n\r"); + printf("9 100 Hz\n\r"); + printf("10 500 Hz\n\r"); + printf("11 1 kHz\n\r"); + printf("12 2 kHz\n\r"); + printf("13 3.75 kHz\n\r"); + printf("14 7.5 kHz\n\r"); + printf("15 15 kHz\n\r"); + printf("16 30 kHz\n\r"); + + scanf("%u", &periods); + printf("%u\n\r", periods); + + if (periods == 1) + ads_datarate = ADS_DR_2_5; + else if (periods == 2) + ads_datarate = ADS_DR_5; + else if (periods == 3) + ads_datarate = ADS_DR_10; + else if (periods == 4) + ads_datarate = ADS_DR_15; + else if (periods == 5) + ads_datarate = ADS_DR_25; + else if (periods == 6) + ads_datarate = ADS_DR_30; + else if (periods == 7) + ads_datarate = ADS_DR_50; + else if (periods == 8) + ads_datarate = ADS_DR_60; + else if (periods == 9) + ads_datarate = ADS_DR_100; + else if (periods == 10) + ads_datarate = ADS_DR_500; + else if (periods == 11) + ads_datarate = ADS_DR_1000; + else if (periods == 12) + ads_datarate = ADS_DR_2000; + else if (periods == 13) + ads_datarate = ADS_DR_3750; + else if (periods == 14) + ads_datarate = ADS_DR_7500; + else if (periods == 15) + ads_datarate = ADS_DR_15000; + else if (periods == 16) + ads_datarate = ADS_DR_30000; + }while (periods == 0 || periods > 16); + + do { + printf("ADS PGA (1,2,4,8,16,32,64): \n\r"); + + scanf("%u", &periods); + printf("%u\n\r", periods); + + if (periods == 1) + ads_pga = ADS_PGA_1; + else if (periods == 2) + ads_pga = ADS_PGA_2; + else if (periods == 4) + ads_pga = ADS_PGA_4; + else if (periods == 8) + ads_pga = ADS_PGA_8; + else if (periods == 16) + ads_pga = ADS_PGA_16; + else if (periods == 32) + ads_pga = ADS_PGA_32; + else if (periods == 64) + ads_pga = ADS_PGA_64; + else + periods = 0; + }while (periods == 0 || periods > 64); + + ads1255_setup(ads_buff,ads_datarate,ads_pga); + + break; + case MENU_LSV: + printf("LSV:\n\r"); + + do { + printf("Start (-1500 - 1500 mV): \n\r"); + scanf("%d", &start); + + if (start > 1500 && start < -1500) + { + printf("Invalid selection.\n\r"); + } + }while (start > 1500 && start < -1500); + + do { + printf("Stop (-1500 - 1500 mV): \n\r"); + scanf("%d", &stop); + + if (stop > 1500 && stop < -1500) + { + printf("Invalid selection.\n\r"); + } + }while (stop > 1500 && stop < -1500); + + do { + printf("Slope (1 - 7000 mV/s): \n\r"); + scanf("%u", &slope); + + if (slope > 7000 && slope < 1) + { + printf("Invalid selection.\n\r"); + } + }while (slope > 7000 && slope < 1); + + lsv_experiment(start,stop,slope,2); + break; + + case MENU_CV: + printf("CV:\n\r"); + + do { + printf("v1 (-1500 - 1500 mV): \n\r"); + scanf("%d", &v1); + + if (v1 > 1500 && v1 < -1500) + { + printf("Invalid selection.\n\r"); + } + }while (v1 > 1500 && v1 < -1500); + + do { + printf("v2 (-1500 - 1500 mV): \n\r"); + scanf("%d", &v2); + + if (v2 > 1500 && v2 < -1500) + { + printf("Invalid selection.\n\r"); + } + }while (v2 > 1500 && v2 < -1500); + + do { + printf("Start (-1500 - 1500 mV): \n\r"); + scanf("%d", &start); + + if (start > 1500 && start < -1500) + { + printf("Invalid selection.\n\r"); + } + }while (start > 1500 && start < -1500); + + do { + printf("Slope (1 - 7000 mV/s): \n\r"); + scanf("%u", &slope); + + if (slope > 7000 && slope < 1) + { + printf("Invalid selection.\n\r"); + } + }while (slope > 7000 && slope < 1); + + do { + printf("Scans (1-255): \n\r"); + scanf("%hu", &scans); + + if (scans < 1) + { + printf("Invalid selection.\n\r"); + } + }while (scans < 1); + + cv_experiment(v1,v2,start,scans,slope); + break; + case MENU_EIS: + printf("EIS:\n\r"); + + do { + printf("freq (1-100000 dHz): \n\r"); + scanf("%lu", &freq); + + if (freq > 100000 || freq == 0) + { + printf("Invalid selection.\n\r"); + } + }while (freq > 100000 || freq == 0); + + do { + printf("offset (-1500-1500 mV): \n\r"); + scanf("%d", &start); + + if (start > 1500 || start < -1500) + { + printf("Invalid selection.\n\r"); + } + }while (start > 1500 || start < -1500); + + do { + printf("amplitude (1-500 mV): \n\r"); + scanf("%u", &slope); + + if (slope > 500) + { + printf("Invalid selection.\n\r"); + } + }while (slope > 500); + + do { + printf("cycles: \n\r"); + scanf("%u", &periods); + + if (periods > 10000 || periods == 0) + { + printf("Invalid selection.\n\r"); + } + }while (periods > 10000 || periods == 0); + ads1255_setup(ADS_BUFF_ON,ADS_DR_30000,ADS_PGA_2); + eis_waveform(start, slope, freq, periods); + break; + case MENU_SWV: + printf("SWV:\n\r"); + + do { + printf("Start (-1500-1500 mV): \n\r"); + scanf("%d", &start); + + if (start > 1500 || start < -1500) + { + printf("Invalid selection.\n\r"); + } + }while (start > 1500 || start < -1500); + + do { + printf("Stop (-1500-1500 mV): \n\r"); + scanf("%d", &stop); + + if (stop > 1500 || stop < -1500) + { + printf("Invalid selection.\n\r"); + } + }while (stop > 1500 || stop < -1500); + + do { + printf("Step (1-400 mV): \n\r"); + scanf("%u", &slope); + + if (slope > 400 || slope < 1) + { + printf("Invalid selection.\n\r"); + } + }while (slope > 400 || slope < 1); + + do { + printf("Pulse height (1-500 mV): \n\r"); + scanf("%u", &height); + + if (height > 500) + { + printf("Invalid selection.\n\r"); + } + }while (height > 500); + + do { + printf("freq (1-10000 Hz): \n\r"); + scanf("%lu", &freq); + + if (freq > 10000 || freq == 0) + { + printf("Invalid selection.\n\r"); + } + }while (freq > 10000 || freq == 0); + + swv_experiment(start, stop, slope, height, freq); + break; + + case MENU_AMP: + printf("Chronoamperometry:\n\r"); + + do { + printf("Steps (1-20): "); + scanf("%u", &slope); + printf("%u\n\r", slope); + + if (slope > 20 || slope == 0) + { + printf("Invalid selection.\n\r"); + } + }while (slope > 20 || slope == 0); + + for (uint16_t i = 0; i 1500 || start < -1500) + printf("Invalid selection.\n\r"); + }while (start > 1500 || start < -1500); + + amp_dac[i] = ceil(start*(65535/(double)3000)+32767); + } + chronoamp(slope, amp_dac, amp_seconds); + + break; + default: + printf("Invalid selection.\n\r"); + return; + return; + } +} + +int main (void) +{ + board_init(); + pmic_init(); + + irq_initialize_vectors(); + cpu_irq_enable(); + sleepmgr_init(); + sysclk_init(); //Disables ALL peripheral clocks D: + rtc_init(); + sysclk_enable_module(SYSCLK_PORT_GEN, SYSCLK_EVSYS); + + pmic_set_scheduling(PMIC_SCH_ROUND_ROBIN); + + stdio_usb_init(&USARTD1); + stdio_usb_enable(); +// printf("DStat v1 25 Jun 2012\n\r"); + + pot_LP(POT_LP_OFF); + ads1255_init_pins(); + ads1255_init_module(); + ads1255_setup(ADS_BUFF_ON,ADS_DR_2_5,ADS_PGA_1); + PORTE.INT0MASK = PIN3_bm; + PORTE.INT1MASK = PIN3_bm; + PORTE.INTCTRL = PORT_INT0LVL_OFF_gc; + PORTE.INTCTRL = PORT_INT1LVL_OFF_gc; + + max5443_init_pins(); + max5443_init_module(); + delay_ms(300); + + uint16_t input = 0; + + while (1) + { + //scanf("%d",&testvolts); + //max5443_set_voltage1(ceil((testvolts)*(65535/(double)3000)+32767)); + //printf("%d \n\r",testvolts); + + gain = POT_GAIN_30k; + pot_set_gain(gain); +// +// getchar(); +// + ads1255_setup(ADS_BUFF_ON,ADS_DR_2_5,ADS_PGA_2); + ads1255_standby(); + +// getchar(); +// +// ads1255_wakeup(); +// +// while (ioport_pin_is_high(IOPORT_CREATE_PIN(PORTE, 3))); +// printf("%d\n\r", ads1255_read_fast_single()/**(3./65535/30000.)*/); +// +// getchar(); +// ads1255_standby(); + + printf("DStat v1 25 Jun 2012\n\r"); + printf("Choose Experiment type:\n\r"); + printf("Options:0, LSV:1, CV:2, SWV:3, AMP:4, EIS:5\n\r"); + + scanf("%u", &input); + + if (input < 6) + { + menu(input); + } + else + { + printf("Invalid selection.\n\r"); + } + } + +} + + +ISR(PORTE_INT0_vect){ + if (porte_int0_callback) { + porte_int0_callback(); + } +// if (autogainswitch()==0){ +// while (ioport_pin_is_high(IOPORT_CREATE_PIN(PORTE, 3))); +// if (gain == POT_GAIN_30k) +// { +// printf("%u, %ld\n\r", TCC1.CNT, ads1255_read()*100); +// } +// else if (gain == POT_GAIN_300k) +// { +// printf("%u, %ld\n\r", TCC1.CNT, ads1255_read()*10); +// } +// else if (gain == POT_GAIN_3M) +// { +// printf("%u, %ld\n\r", TCC1.CNT, ads1255_read()); +// } +// else +// { +// printf("%u, %lu\n\r", TCC1.CNT, ads1255_read()); +// } +// /*printf("%li, %li\n\r", voltage, ads1255_read());*/ +// } +// else{ +// while (ioport_pin_is_high(IOPORT_CREATE_PIN(PORTE, 3))); +// ads1255_read(); +// } +} + +ISR(PORTE_INT1_vect){ +// if (autogainswitch()==0){ +// printf("INT1\n\r"); +// static uint16_t skip = 0; +// if (++skip <= skip_samples) +// return; +// skip = 0; +// +// if (samples == 500){ +// printf("%u, %d\n\r", TCE1.CNT, ads1255_read_fast()); +// return; +// } +// +// uint32_t iter1 = TCE1.CNT*(uint32_t)tcf0period + TCF0.CNT; +// +// printf("%lu, %d\n\r", iter1, ads1255_read_fast()/**(3./65535/30000.)*/); + + uint16_t position = TCE1.CNT; + int16_t data_buff = ads1255_read_fast(); + + if (eis_data[position] == 0) + eis_data[position] = data_buff; + else + eis_data[position] = (eis_data[position] & data_buff)+((eis_data[position]^data_buff)>>1); + + + return; + +} + diff --git a/DSTAT1/src/main.h b/DSTAT1/src/main.h new file mode 100644 index 0000000000000000000000000000000000000000..b92b7eb178cf8a2d4cdce92eee7bf19dbba20d34 --- /dev/null +++ b/DSTAT1/src/main.h @@ -0,0 +1,57 @@ +/* + * main.h + * + * Created: 06/04/2012 1:19:58 AM + * Author: mdryden + */ + +#include +#include + +int8_t autogainswitch(void); +void menu(uint8_t selection); +void pot_set_gain(uint8_t gain); +void pot_LP(uint8_t lponoff); +void pot_exp_start(void); +void pot_exp_stop(void); +void sw_test(uint16_t frequency); +void lsv_experiment(int16_t start, int16_t stop, uint16_t slope, int8_t first_run); +void cv_experiment(int16_t v1, int16_t v2, int16_t start, uint8_t scans, uint16_t slope); +void chronoamp(uint16_t steps, uint16_t step_dac[], uint16_t step_seconds[]); +void swv_experiment(int16_t start, int16_t stop, uint16_t step, uint16_t pulse_height, uint16_t frequency); +void sine_impedance_spec(int16_t potential, uint16_t freq_min, uint16_t freq_max, uint16_t freq_step, uint16_t amplitude, uint16_t cycles); +void eis_waveform(int16_t offset, int16_t amplitude, uint32_t freq, uint16_t cycles); + + +#define MENU_LSV 1 +#define MENU_CV 2 +#define MENU_SWV 3 +#define MENU_AMP 4 +#define MENU_EIS 5 +#define MENU_OPS 0 + +#define POT_GAIN_30k 0 +#define POT_GAIN_300k 1 +#define POT_GAIN_3M 2 +#define POT_GAIN_500M 3 +#define POT_LP_OFF 0 +#define POT_LP_ON 1 + +#define ADS_F_2_5 0 +#define ADS_F_5 1 +#define ADS_F_10 2 +#define ADS_F_15 3 +#define ADS_F_25 4 +#define ADS_F_30 5 +#define ADS_F_50 6 +#define ADS_F_60 7 +#define ADS_F_100 8 +#define ADS_F_500 9 +#define ADS_F_1000 10 +#define ADS_F_2000 11 +#define ADS_F_3750 12 +#define ADS_F_7500 13 +#define ADS_F_15000 14 +#define ADS_F_30000 15 + +#define SIN_IMP_CYCLEPTS 50 diff --git a/DSTAT1/src/main1.c b/DSTAT1/src/main1.c new file mode 100644 index 0000000000000000000000000000000000000000..15a5564ed88a4d29bd970493a876c56cf38c4f0f --- /dev/null +++ b/DSTAT1/src/main1.c @@ -0,0 +1,206 @@ +/** + * \file + * + * \brief Empty user application template + * + */ + +/* + * Include header files for all drivers that have been imported from + * Atmel Software Framework (ASF). + */ +#include +#include +#include + +static bool main_b_vbus_event = false; +static bool main_b_resume_event = false; +static bool main_b_suspend_event = false; +static bool main_b_sof_event = false; +static bool main_b_cdc_configurated = false; +static bool main_b_cdc_enumerated = false; + + +void usblog(char logdata[], int length){ + for (int i = 0; i +#include +#include +#include + +struct spi_device spi_device_conf_c = { + .id = IOPORT_CREATE_PIN(PORTC, 4) + }; + +void max5443_init_pins(void){ + ioport_configure_port_pin(&PORTC, PIN4_bm, IOPORT_INIT_HIGH | IOPORT_DIR_OUTPUT); + ioport_configure_port_pin(&PORTC, PIN5_bm, IOPORT_INIT_HIGH | IOPORT_DIR_OUTPUT); + ioport_configure_port_pin(&PORTC, PIN7_bm, IOPORT_INIT_HIGH | IOPORT_DIR_OUTPUT); + //CLR + ioport_configure_port_pin(&PORTC, PIN3_bm, IOPORT_INIT_LOW | IOPORT_DIR_OUTPUT); + delay_us(1); + ioport_configure_port_pin(&PORTC, PIN3_bm, IOPORT_INIT_HIGH | IOPORT_DIR_OUTPUT); +} + +void max5443_init_module(void) + { + spi_master_init(&SPIC); + spi_master_setup_device(&SPIC, &spi_device_conf_c, SPI_MODE_0, 24000000UL, 0); + spi_enable(&SPIC); + } + +void max5443_set_voltage1(uint16_t dacindex){ +/* char logstr[10];*/ + + static union{ + uint8_t ui8[2]; + uint16_t ui16; + } buffer; + + if (buffer.ui16 == dacindex) + return; + + buffer.ui16 = dacindex; + +// irqflags_t flags; +// flags = cpu_irq_save(); + + spi_select_device(&SPIC, &spi_device_conf_c); + spi_write_single(&SPIC, buffer.ui8[1]); + delay_cycles(20); + spi_write_single(&SPIC, buffer.ui8[0]); + spi_deselect_device(&SPIC, &spi_device_conf_c); + +/* cpu_irq_restore(flags);*/ + return; +} + +void max5443_set_voltage_8bit(uint8_t dacindex){ + spi_select_device(&SPIC, &spi_device_conf_c); + spi_write_single(&SPIC, dacindex); + spi_deselect_device(&SPIC, &spi_device_conf_c); + return; +} + +/*void max5443_set_voltage(uint8_t msb, uint8_t lsb){ + irqflags_t flags; + flags = cpu_irq_save(); + + spi_select_device(&SPIC, &spi_device_conf_c); + spi_write_single(&SPIC, msb); + spi_write_single(&SPIC, lsb); + spi_deselect_device(&SPIC, &spi_device_conf_c); + + cpu_irq_restore(flags); +}*/ \ No newline at end of file diff --git a/DSTAT1/src/max5443.h b/DSTAT1/src/max5443.h new file mode 100644 index 0000000000000000000000000000000000000000..6d5e7f4b0621664e1f591be0c8cdae762f940ed5 --- /dev/null +++ b/DSTAT1/src/max5443.h @@ -0,0 +1,18 @@ +/* + * max5443.h + * + * Created: 06/04/2012 7:30:13 PM + * Author: mdryden + */ + + +#ifndef MAX5443_H_ +#define MAX5443_H_ +#include + +void max5443_init_pins(void); +void max5443_init_module(void); +void max5443_set_voltage1(uint16_t dacindex); +void max5443_set_voltage_8bit(uint8_t dacindex); + +#endif /* MAX5443_H_ */ \ No newline at end of file