28 Commits
Author SHA1 Message Date
MightyPork 9f40c6e4dd DAC advanced features 2018-03-11 00:04:54 +01:00
MightyPork b2066a9010 basic static DAC 2018-03-10 15:37:40 +01:00
MightyPork 590d550a09 pulse generation for digital out 2018-03-08 00:49:21 +01:00
MightyPork 274f2be6e0 compat with 072hub 2018-03-07 22:03:41 +01:00
MightyPork 76d1cd3a24 Merge branch 'faster' 2018-03-05 11:38:55 +01:00
MightyPork 3654bf2206 various speed-ups in TF_WriteImpl and elsewhere 2018-03-05 11:38:25 +01:00
MightyPork 5687196bdd small speed up using larger buffer and multipart Tx 2018-03-05 10:21:23 +01:00
MightyPork da330b4b73 experimental speed-up of cdc Tx 2018-03-04 13:19:41 +01:00
MightyPork 0b14e5dda4 fix 1wire bugginess with addressing 2018-03-04 00:50:15 +01:00
MightyPork 887887b675 Removed timers use from 1wire, timers disabled, fixed overflow bug 2018-03-04 00:13:31 +01:00
MightyPork e96ecceec9 Merge branch 'simple-pwm' 2018-03-04 00:02:00 +01:00
MightyPork d8bdaf7203 simple pwm 2018-03-04 00:01:28 +01:00
MightyPork 3fdd51ba2e rm commented out crap 2018-03-03 16:46:33 +01:00
MightyPork 5dd350ffe4 fix ini parser wrt spaces in value 2018-03-03 16:04:14 +01:00
MightyPork 4b8d24ae0f rewritten ini parser for smaller size 2018-03-03 15:59:31 +01:00
MightyPork ed7a4c80a0 size reduction by using specialized entry funcs 2018-03-03 11:05:16 +01:00
MightyPork 78897f84b3 touch button mode 2018-03-03 01:32:30 +01:00
MightyPork 8410c273ab Merge branch 'wd' 2018-02-28 08:17:27 +01:00
MightyPork 2812f962d9 added watchdog 2018-02-28 08:17:21 +01:00
MightyPork 7f4c06ae4b Merge branch 'tsc' 2018-02-26 09:02:51 +01:00
MightyPork 5019bf225d touch interleaved sense mode, improved blinking in file writes via the api 2018-02-26 09:02:41 +01:00
MightyPork 41ad18cc7c improvements + added a toggle for interlaced, not yet fully implemented 2018-02-25 22:47:40 +01:00
MightyPork 101d2534f4 tsc disable debug 2018-02-25 13:40:47 +01:00
MightyPork 1f2d346e23 tsc ini structure + debug msgs 2018-02-25 13:37:57 +01:00
MightyPork 639031fc38 added template install script and utouch config 2018-02-25 00:03:05 +01:00
MightyPork 1a888366af fixes, and use the new rsc parsing for some unit pins 2018-02-23 11:24:10 +01:00
MightyPork a60b736834 massive utils refactoring, renames, avr libc utils cleaning 2018-02-23 10:55:49 +01:00
MightyPork 8dcdaf9236 provisions for representing pins via resources in settings 2018-02-22 23:33:11 +01:00
112 changed files with 4005 additions and 2406 deletions
+2 -2
View File
@@ -110,7 +110,7 @@ extern uint32_t SystemCoreClock;
#define configCHECK_FOR_STACK_OVERFLOW 2 #define configCHECK_FOR_STACK_OVERFLOW 2
#define configENABLE_BACKWARD_COMPATIBILITY 0 #define configENABLE_BACKWARD_COMPATIBILITY 0
#define configUSE_TIMERS 1 #define configUSE_TIMERS 0
#define configTIMER_TASK_PRIORITY TSK_TIMERS_PRIO // above normal #define configTIMER_TASK_PRIORITY TSK_TIMERS_PRIO // above normal
#define configTIMER_TASK_STACK_DEPTH TSK_STACK_TIMERS //128 #define configTIMER_TASK_STACK_DEPTH TSK_STACK_TIMERS //128
#define configTIMER_QUEUE_LENGTH 4 #define configTIMER_QUEUE_LENGTH 4
@@ -151,7 +151,7 @@ to exclude the API function. */
#define configLIBRARY_MAX_SYSCALL_INTERRUPT_PRIORITY 5 #define configLIBRARY_MAX_SYSCALL_INTERRUPT_PRIORITY 5
#define configUSE_PORT_OPTIMISED_TASK_SELECTION 1 #define configUSE_PORT_OPTIMISED_TASK_SELECTION 1
#elif defined(GEX_PLAT_F072_DISCOVERY) #elif defined(STM32F072xB)
// This is for F072 // This is for F072
#define configLIBRARY_LOWEST_INTERRUPT_PRIORITY 3 #define configLIBRARY_LOWEST_INTERRUPT_PRIORITY 3
#define configLIBRARY_MAX_SYSCALL_INTERRUPT_PRIORITY 1 #define configLIBRARY_MAX_SYSCALL_INTERRUPT_PRIORITY 1
+47 -5
View File
@@ -8,6 +8,7 @@
#include "task_main.h" #include "task_main.h"
#include "USB/usbd_cdc_if.h" #include "USB/usbd_cdc_if.h"
#include "USB/usb_device.h"
#include "TinyFrame.h" #include "TinyFrame.h"
extern osSemaphoreId semVcomTxReadyHandle; extern osSemaphoreId semVcomTxReadyHandle;
@@ -15,6 +16,30 @@ extern osMutexId mutTinyFrameTxHandle;
void TF_WriteImpl(TinyFrame *tf, const uint8_t *buff, uint32_t len) void TF_WriteImpl(TinyFrame *tf, const uint8_t *buff, uint32_t len)
{ {
#if 1
const uint32_t real_size = len;
// Padding to a multiple of 64 bytes - this is supposed to maximize the bulk transfer speed
if (len&0x3F) {
uint32_t pad = (64 - (len&0x3F));
memset((void *) (buff + len), 0, pad);
len += pad; // padding to a multiple of 64 (size of the endpoint)
}
// We bypass the USBD driver library's overhead by using the HAL function directly
assert_param(HAL_OK == HAL_PCD_EP_Transmit(hUsbDeviceFS.pData, CDC_IN_EP, (uint8_t *) buff, len));
// The buffer is the TF transmit buffer, we can't leave it to work asynchronously because
// the next call could modify it before it's been transmitted (in the case of a chunked / multi-part frame)
// the assumption here is that all until the last chunk use the full buffer capacity
if (real_size == TF_SENDBUF_LEN) {
if (pdTRUE != xSemaphoreTake(semVcomTxReadyHandle, 100)) {
TF_Error("Tx stalled in WriteImpl");
return;
}
}
#else
(void) tf; (void) tf;
#define CHUNK 64 // same as TF_SENDBUF_LEN, so we should always have only one run of the loop #define CHUNK 64 // same as TF_SENDBUF_LEN, so we should always have only one run of the loop
int32_t total = (int32_t) len; int32_t total = (int32_t) len;
@@ -26,21 +51,36 @@ void TF_WriteImpl(TinyFrame *tf, const uint8_t *buff, uint32_t len)
} }
const uint16_t chunksize = (uint16_t) MIN(total, CHUNK); const uint16_t chunksize = (uint16_t) MIN(total, CHUNK);
assert_param(USBD_OK == CDC_Transmit_FS((uint8_t *) buff, chunksize));
// this is an attempt to speed it up a little by removing a couple levels of indirection
assert_param(HAL_OK == HAL_PCD_EP_Transmit(hUsbDeviceFS.pData, CDC_IN_EP, (uint8_t *) buff, chunksize));
// USBD_LL_Transmit(&hUsbDeviceFS, CDC_IN_EP, (uint8_t *) buff, chunksize);
// assert_param(USBD_OK == CDC_Transmit_FS((uint8_t *) buff, chunksize));
buff += chunksize; buff += chunksize;
total -= chunksize; total -= chunksize;
} }
#endif
} }
/** Claim the TX interface before composing and sending a frame */ /** Claim the TX interface before composing and sending a frame */
bool TF_ClaimTx(TinyFrame *tf) bool TF_ClaimTx(TinyFrame *tf)
{ {
(void) tf; (void) tf;
// assert_param(osThreadGetId() != tskMainHandle); // assert_param(!inIRQ()); // useless delay
assert_param(!inIRQ()); assert_param(pdTRUE == xSemaphoreTake(mutTinyFrameTxHandle, 5000)); // trips the wd
// The last chunk from some previous frame may still be being transmitted,
// wait for it to finish (the semaphore is given in the CDC tx done handler)
if (pdTRUE != xSemaphoreTake(semVcomTxReadyHandle, 100)) {
TF_Error("Tx stalled in Claim");
// release the guarding mutex again
assert_param(pdTRUE == xSemaphoreGive(mutTinyFrameTxHandle));
return false;
}
assert_param(osOK == osMutexWait(mutTinyFrameTxHandle, 5000));
return true; return true;
} }
@@ -48,5 +88,7 @@ bool TF_ClaimTx(TinyFrame *tf)
void TF_ReleaseTx(TinyFrame *tf) void TF_ReleaseTx(TinyFrame *tf)
{ {
(void) tf; (void) tf;
assert_param(osOK == osMutexRelease(mutTinyFrameTxHandle)); assert_param(pdTRUE == xSemaphoreGive(mutTinyFrameTxHandle));
// the last payload is sent asynchronously
} }
+7 -3
View File
@@ -870,7 +870,11 @@ static inline uint32_t _TF_FN TF_ComposeTail(uint8_t *outbuff, TF_CKSUM *cksum)
*/ */
static bool _TF_FN TF_SendFrame_Begin(TinyFrame *tf, TF_Msg *msg, TF_Listener listener, TF_TICKS timeout) static bool _TF_FN TF_SendFrame_Begin(TinyFrame *tf, TF_Msg *msg, TF_Listener listener, TF_TICKS timeout)
{ {
TF_TRY(TF_ClaimTx(tf)); bool suc = TF_ClaimTx(tf);
if (!suc) {
TF_Error("TF lock not free");
return false;
}
tf->tx_pos = (uint32_t) TF_ComposeHead(tf, tf->sendbuf, msg); // frame ID is incremented here if it's not a response tf->tx_pos = (uint32_t) TF_ComposeHead(tf, tf->sendbuf, msg); // frame ID is incremented here if it's not a response
tf->tx_len = msg->len; tf->tx_len = msg->len;
@@ -1031,10 +1035,10 @@ bool _TF_FN TF_Query_Multipart(TinyFrame *tf, TF_Msg *msg, TF_Listener listener,
return TF_Query(tf, msg, listener, timeout); return TF_Query(tf, msg, listener, timeout);
} }
void _TF_FN TF_Respond_Multipart(TinyFrame *tf, TF_Msg *msg) bool _TF_FN TF_Respond_Multipart(TinyFrame *tf, TF_Msg *msg)
{ {
msg->data = NULL; msg->data = NULL;
TF_Respond(tf, msg); return TF_Respond(tf, msg);
} }
void _TF_FN TF_Multipart_Payload(TinyFrame *tf, const uint8_t *buff, uint32_t length) void _TF_FN TF_Multipart_Payload(TinyFrame *tf, const uint8_t *buff, uint32_t length)
+1 -1
View File
@@ -369,7 +369,7 @@ bool TF_Query_Multipart(TinyFrame *tf, TF_Msg *msg, TF_Listener listener, TF_TIC
* TF_Respond() with multipart payload. * TF_Respond() with multipart payload.
* msg.data is ignored and set to NULL * msg.data is ignored and set to NULL
*/ */
void TF_Respond_Multipart(TinyFrame *tf, TF_Msg *msg); bool TF_Respond_Multipart(TinyFrame *tf, TF_Msg *msg);
/** /**
* Send the payload for a started multipart frame. This can be called multiple times * Send the payload for a started multipart frame. This can be called multiple times
@@ -1,328 +0,0 @@
--- Middlewares/ST/STM32_USB_Device_Library/Class/CDC/Src/usbd_cdc.c (date 1511202099000)
+++ Middlewares/ST/STM32_USB_Device_Library/Class/CDC/Src/usbd_cdc.c (revision )
@@ -59,6 +59,7 @@
*/
/* Includes ------------------------------------------------------------------*/
+#include "usbd_msc.h" // for rejecting bad control messages
#include "usbd_cdc.h"
#include "usbd_desc.h"
#include "usbd_ctlreq.h"
@@ -103,34 +104,7 @@
* @{
*/
-
-static uint8_t USBD_CDC_Init (USBD_HandleTypeDef *pdev,
- uint8_t cfgidx);
-
-static uint8_t USBD_CDC_DeInit (USBD_HandleTypeDef *pdev,
- uint8_t cfgidx);
-
-static uint8_t USBD_CDC_Setup (USBD_HandleTypeDef *pdev,
- USBD_SetupReqTypedef *req);
-
-static uint8_t USBD_CDC_DataIn (USBD_HandleTypeDef *pdev,
- uint8_t epnum);
-
-static uint8_t USBD_CDC_DataOut (USBD_HandleTypeDef *pdev,
- uint8_t epnum);
-
-static uint8_t USBD_CDC_EP0_RxReady (USBD_HandleTypeDef *pdev);
-
-static uint8_t *USBD_CDC_GetFSCfgDesc (uint16_t *length);
-
-static uint8_t *USBD_CDC_GetHSCfgDesc (uint16_t *length);
-
-static uint8_t *USBD_CDC_GetOtherSpeedCfgDesc (uint16_t *length);
-
-static uint8_t *USBD_CDC_GetOtherSpeedCfgDesc (uint16_t *length);
-
-uint8_t *USBD_CDC_GetDeviceQualifierDescriptor (uint16_t *length);
-
+#ifndef CDC_COMPOSITE
/* USB Standard Device Descriptor */
__ALIGN_BEGIN static uint8_t USBD_CDC_DeviceQualifierDesc[USB_LEN_DEV_QUALIFIER_DESC] __ALIGN_END =
{
@@ -156,7 +130,7 @@
/* CDC interface class callbacks structure */
-USBD_ClassTypeDef USBD_CDC =
+USBD_ClassTypeDef USBD_CDC =
{
USBD_CDC_Init,
USBD_CDC_DeInit,
@@ -172,6 +146,7 @@
USBD_CDC_GetFSCfgDesc,
USBD_CDC_GetOtherSpeedCfgDesc,
USBD_CDC_GetDeviceQualifierDescriptor,
+ NULL
};
/* USB CDC device Configuration Descriptor */
@@ -456,6 +431,7 @@
0x00,
0x00 /* bInterval */
};
+#endif
/**
* @}
@@ -463,7 +439,7 @@
/** @defgroup USBD_CDC_Private_Functions
* @{
- */
+ */
/**
* @brief USBD_CDC_Init
@@ -472,7 +448,7 @@
* @param cfgidx: Configuration index
* @retval status
*/
-static uint8_t USBD_CDC_Init (USBD_HandleTypeDef *pdev,
+uint8_t USBD_CDC_Init (USBD_HandleTypeDef *pdev,
uint8_t cfgidx)
{
uint8_t ret = 0;
@@ -514,18 +490,18 @@
CDC_CMD_PACKET_SIZE);
- pdev->pClassData = USBD_malloc(sizeof (USBD_CDC_HandleTypeDef));
+ pdev->pClassData2 = USBD_malloc(sizeof (USBD_CDC_HandleTypeDef));
- if(pdev->pClassData == NULL)
+ if(pdev->pClassData2 == NULL)
{
ret = 1;
}
else
{
- hcdc = (USBD_CDC_HandleTypeDef*) pdev->pClassData;
+ hcdc = (USBD_CDC_HandleTypeDef*) pdev->pClassData2;
/* Init physical Interface components */
- ((USBD_CDC_ItfTypeDef *)pdev->pUserData)->Init();
+ ((USBD_CDC_ItfTypeDef *)pdev->pUserData2)->Init();
/* Init Xfer states */
hcdc->TxState =0;
@@ -560,7 +536,7 @@
* @param cfgidx: Configuration index
* @retval status
*/
-static uint8_t USBD_CDC_DeInit (USBD_HandleTypeDef *pdev,
+uint8_t USBD_CDC_DeInit (USBD_HandleTypeDef *pdev,
uint8_t cfgidx)
{
uint8_t ret = 0;
@@ -579,11 +555,11 @@
/* DeInit physical Interface components */
- if(pdev->pClassData != NULL)
+ if(pdev->pClassData2 != NULL)
{
- ((USBD_CDC_ItfTypeDef *)pdev->pUserData)->DeInit();
- USBD_free(pdev->pClassData);
- pdev->pClassData = NULL;
+ ((USBD_CDC_ItfTypeDef *)pdev->pUserData2)->DeInit();
+ USBD_free(pdev->pClassData2);
+ pdev->pClassData2 = NULL;
}
return ret;
@@ -596,20 +572,23 @@
* @param req: usb requests
* @retval status
*/
-static uint8_t USBD_CDC_Setup (USBD_HandleTypeDef *pdev,
+uint8_t USBD_CDC_Setup (USBD_HandleTypeDef *pdev,
USBD_SetupReqTypedef *req)
{
- USBD_CDC_HandleTypeDef *hcdc = (USBD_CDC_HandleTypeDef*) pdev->pClassData;
+ USBD_CDC_HandleTypeDef *hcdc = (USBD_CDC_HandleTypeDef*) pdev->pClassData2;
static uint8_t ifalt = 0;
switch (req->bmRequest & USB_REQ_TYPE_MASK)
{
case USB_REQ_TYPE_CLASS :
+ if (req->bRequest == BOT_GET_MAX_LUN) break; // Not ours!
+ if (req->bRequest == BOT_RESET) break; // Not ours!
+
if (req->wLength)
{
if (req->bmRequest & 0x80)
{
- ((USBD_CDC_ItfTypeDef *)pdev->pUserData)->Control(req->bRequest,
+ ((USBD_CDC_ItfTypeDef *)pdev->pUserData2)->Control(req->bRequest,
(uint8_t *)hcdc->data,
req->wLength);
USBD_CtlSendData (pdev,
@@ -629,7 +608,7 @@
}
else
{
- ((USBD_CDC_ItfTypeDef *)pdev->pUserData)->Control(req->bRequest,
+ ((USBD_CDC_ItfTypeDef *)pdev->pUserData2)->Control(req->bRequest,
(uint8_t*)req,
0);
}
@@ -661,14 +640,15 @@
* @param epnum: endpoint number
* @retval status
*/
-static uint8_t USBD_CDC_DataIn (USBD_HandleTypeDef *pdev, uint8_t epnum)
+uint8_t USBD_CDC_DataIn (USBD_HandleTypeDef *pdev, uint8_t epnum)
{
- USBD_CDC_HandleTypeDef *hcdc = (USBD_CDC_HandleTypeDef*) pdev->pClassData;
+ USBD_CDC_HandleTypeDef *hcdc = (USBD_CDC_HandleTypeDef*) pdev->pClassData2;
- if(pdev->pClassData != NULL)
+ if(pdev->pClassData2 != NULL)
{
hcdc->TxState = 0;
+ USBD_CDC_TransmitDone(pdev);
return USBD_OK;
}
@@ -685,18 +665,18 @@
* @param epnum: endpoint number
* @retval status
*/
-static uint8_t USBD_CDC_DataOut (USBD_HandleTypeDef *pdev, uint8_t epnum)
+uint8_t USBD_CDC_DataOut (USBD_HandleTypeDef *pdev, uint8_t epnum)
{
- USBD_CDC_HandleTypeDef *hcdc = (USBD_CDC_HandleTypeDef*) pdev->pClassData;
+ USBD_CDC_HandleTypeDef *hcdc = (USBD_CDC_HandleTypeDef*) pdev->pClassData2;
/* Get the received data length */
hcdc->RxLength = USBD_LL_GetRxDataSize (pdev, epnum);
/* USB data will be immediately processed, this allow next USB traffic being
NAKed till the end of the application Xfer */
- if(pdev->pClassData != NULL)
+ if(pdev->pClassData2 != NULL)
{
- ((USBD_CDC_ItfTypeDef *)pdev->pUserData)->Receive(hcdc->RxBuffer, &hcdc->RxLength);
+ ((USBD_CDC_ItfTypeDef *)pdev->pUserData2)->Receive(hcdc->RxBuffer, &hcdc->RxLength);
return USBD_OK;
}
@@ -715,13 +695,13 @@
* @param epnum: endpoint number
* @retval status
*/
-static uint8_t USBD_CDC_EP0_RxReady (USBD_HandleTypeDef *pdev)
+uint8_t USBD_CDC_EP0_RxReady (USBD_HandleTypeDef *pdev)
{
- USBD_CDC_HandleTypeDef *hcdc = (USBD_CDC_HandleTypeDef*) pdev->pClassData;
+ USBD_CDC_HandleTypeDef *hcdc = (USBD_CDC_HandleTypeDef*) pdev->pClassData2;
- if((pdev->pUserData != NULL) && (hcdc->CmdOpCode != 0xFF))
+ if((pdev->pUserData2 != NULL) && (hcdc->CmdOpCode != 0xFF))
{
- ((USBD_CDC_ItfTypeDef *)pdev->pUserData)->Control(hcdc->CmdOpCode,
+ ((USBD_CDC_ItfTypeDef *)pdev->pUserData2)->Control(hcdc->CmdOpCode,
(uint8_t *)hcdc->data,
hcdc->CmdLength);
hcdc->CmdOpCode = 0xFF;
@@ -730,6 +710,7 @@
return USBD_OK;
}
+#ifndef CDC_COMPOSITE
/**
* @brief USBD_CDC_GetFSCfgDesc
* Return configuration descriptor
@@ -737,7 +718,7 @@
* @param length : pointer data length
* @retval pointer to descriptor buffer
*/
-static uint8_t *USBD_CDC_GetFSCfgDesc (uint16_t *length)
+uint8_t *USBD_CDC_GetFSCfgDesc (uint16_t *length)
{
*length = sizeof (USBD_CDC_CfgFSDesc);
return USBD_CDC_CfgFSDesc;
@@ -750,7 +731,7 @@
* @param length : pointer data length
* @retval pointer to descriptor buffer
*/
-static uint8_t *USBD_CDC_GetHSCfgDesc (uint16_t *length)
+uint8_t *USBD_CDC_GetHSCfgDesc (uint16_t *length)
{
*length = sizeof (USBD_CDC_CfgHSDesc);
return USBD_CDC_CfgHSDesc;
@@ -763,7 +744,7 @@
* @param length : pointer data length
* @retval pointer to descriptor buffer
*/
-static uint8_t *USBD_CDC_GetOtherSpeedCfgDesc (uint16_t *length)
+uint8_t *USBD_CDC_GetOtherSpeedCfgDesc (uint16_t *length)
{
*length = sizeof (USBD_CDC_OtherSpeedCfgDesc);
return USBD_CDC_OtherSpeedCfgDesc;
@@ -780,6 +761,7 @@
*length = sizeof (USBD_CDC_DeviceQualifierDesc);
return USBD_CDC_DeviceQualifierDesc;
}
+#endif
/**
* @brief USBD_CDC_RegisterInterface
@@ -794,7 +776,7 @@
if(fops != NULL)
{
- pdev->pUserData= fops;
+ pdev->pUserData2= fops;
ret = USBD_OK;
}
@@ -811,7 +793,7 @@
uint8_t *pbuff,
uint16_t length)
{
- USBD_CDC_HandleTypeDef *hcdc = (USBD_CDC_HandleTypeDef*) pdev->pClassData;
+ USBD_CDC_HandleTypeDef *hcdc = (USBD_CDC_HandleTypeDef*) pdev->pClassData2;
hcdc->TxBuffer = pbuff;
hcdc->TxLength = length;
@@ -829,7 +811,7 @@
uint8_t USBD_CDC_SetRxBuffer (USBD_HandleTypeDef *pdev,
uint8_t *pbuff)
{
- USBD_CDC_HandleTypeDef *hcdc = (USBD_CDC_HandleTypeDef*) pdev->pClassData;
+ USBD_CDC_HandleTypeDef *hcdc = (USBD_CDC_HandleTypeDef*) pdev->pClassData2;
hcdc->RxBuffer = pbuff;
@@ -845,9 +827,9 @@
*/
uint8_t USBD_CDC_TransmitPacket(USBD_HandleTypeDef *pdev)
{
- USBD_CDC_HandleTypeDef *hcdc = (USBD_CDC_HandleTypeDef*) pdev->pClassData;
+ USBD_CDC_HandleTypeDef *hcdc = (USBD_CDC_HandleTypeDef*) pdev->pClassData2;
- if(pdev->pClassData != NULL)
+ if(pdev->pClassData2 != NULL)
{
if(hcdc->TxState == 0)
{
@@ -882,10 +864,10 @@
*/
uint8_t USBD_CDC_ReceivePacket(USBD_HandleTypeDef *pdev)
{
- USBD_CDC_HandleTypeDef *hcdc = (USBD_CDC_HandleTypeDef*) pdev->pClassData;
+ USBD_CDC_HandleTypeDef *hcdc = (USBD_CDC_HandleTypeDef*) pdev->pClassData2;
/* Suspend or Resume USB Out process */
- if(pdev->pClassData != NULL)
+ if(pdev->pClassData2 != NULL)
{
if(pdev->dev_speed == USBD_SPEED_HIGH )
{
@@ -1,60 +0,0 @@
--- Middlewares/ST/STM32_USB_Device_Library/Class/MSC/Inc/usbd_msc.h (date 1511202099000)
+++ Middlewares/ST/STM32_USB_Device_Library/Class/MSC/Inc/usbd_msc.h (revision )
@@ -58,9 +58,10 @@
#define BOT_RESET 0xFF
#define USB_MSC_CONFIG_DESC_SIZ 32
-
+#ifndef MSC_CUSTOM_EPS
#define MSC_EPIN_ADDR 0x81
-#define MSC_EPOUT_ADDR 0x01
+#define MSC_EPOUT_ADDR 0x01
+#endif
/**
* @}
@@ -107,7 +108,7 @@
USBD_MSC_BOT_HandleTypeDef;
/* Structure for MSC process */
-extern USBD_ClassTypeDef USBD_MSC;
+extern USBD_ClassTypeDef USBD_MSC;
#define USBD_MSC_CLASS &USBD_MSC
uint8_t USBD_MSC_RegisterStorage (USBD_HandleTypeDef *pdev,
@@ -118,8 +119,34 @@
/**
* @}
- */
+ */
+// XXX "static" moved here for use in composite driver
+
+uint8_t USBD_MSC_Init (USBD_HandleTypeDef *pdev,
+ uint8_t cfgidx);
+
+uint8_t USBD_MSC_DeInit (USBD_HandleTypeDef *pdev,
+ uint8_t cfgidx);
+
+uint8_t USBD_MSC_Setup (USBD_HandleTypeDef *pdev,
+ USBD_SetupReqTypedef *req);
+
+uint8_t USBD_MSC_DataIn (USBD_HandleTypeDef *pdev,
+ uint8_t epnum);
+
+
+uint8_t USBD_MSC_DataOut (USBD_HandleTypeDef *pdev,
+ uint8_t epnum);
+
+uint8_t *USBD_MSC_GetHSCfgDesc (uint16_t *length);
+
+uint8_t *USBD_MSC_GetFSCfgDesc (uint16_t *length);
+
+uint8_t *USBD_MSC_GetOtherSpeedCfgDesc (uint16_t *length);
+
+uint8_t *USBD_MSC_GetDeviceQualifierDescriptor (uint16_t *length);
+
#ifdef __cplusplus
}
#endif
@@ -1,35 +0,0 @@
--- Middlewares/ST/STM32_USB_Device_Library/Class/MSC/Src/usbd_msc.c (date 1511202099000)
+++ Middlewares/ST/STM32_USB_Device_Library/Class/MSC/Src/usbd_msc.c (revision )
@@ -116,7 +116,7 @@
* @{
*/
-
+#ifndef MSC_COMPOSITE
USBD_ClassTypeDef USBD_MSC =
{
USBD_MSC_Init,
@@ -279,6 +279,7 @@
0x01,
0x00,
};
+#endif
/**
* @}
*/
@@ -530,6 +531,7 @@
return 0;
}
+#ifndef MSC_COMPOSITE
/**
* @brief USBD_MSC_GetHSCfgDesc
* return configuration descriptor
@@ -576,6 +578,7 @@
*length = sizeof (USBD_MSC_DeviceQualifierDesc);
return USBD_MSC_DeviceQualifierDesc;
}
+#endif
/**
* @brief USBD_MSC_RegisterStorage
@@ -1,37 +0,0 @@
--- Middlewares/ST/STM32_USB_Device_Library/Class/MSC/Src/usbd_msc_scsi.c (date 1511202099000)
+++ Middlewares/ST/STM32_USB_Device_Library/Class/MSC/Src/usbd_msc_scsi.c (revision )
@@ -190,14 +190,27 @@
INVALID_CDB);
return -1;
}
-
- if(((USBD_StorageTypeDef *)pdev->pUserData)->IsReady(lun) !=0 )
+
+ // XXX THIS SECTION IS MODIFIED FOR NOTIFY!
+ // https://www.microchip.com/forums/m401735.aspx
+ int8_t changeStatus = ((USBD_StorageTypeDef *)pdev->pUserData)->IsReady(lun);
+ if(changeStatus != 0)
{
- SCSI_SenseCode(pdev,
- lun,
- NOT_READY,
- MEDIUM_NOT_PRESENT);
-
+ if (changeStatus == -1)
+ {
+ SCSI_SenseCode(pdev,
+ lun,
+ UNIT_ATTENTION,
+ MEDIUM_HAVE_CHANGED);
+ }
+ else
+ {
+ SCSI_SenseCode(pdev,
+ lun,
+ NOT_READY,
+ MEDIUM_NOT_PRESENT);
+ }
+
hmsc->bot_state = USBD_BOT_NO_DATA;
return -1;
}
@@ -265,8 +265,8 @@ typedef struct _USBD_HandleTypeDef
#define SWAPBYTE(addr) (((uint16_t)(*((uint8_t *)(addr)))) + \ #define SWAPBYTE(addr) (((uint16_t)(*((uint8_t *)(addr)))) + \
(((uint16_t)(*(((uint8_t *)(addr)) + 1))) << 8)) (((uint16_t)(*(((uint8_t *)(addr)) + 1))) << 8))
#define LOBYTE(x) ((uint8_t)(x & 0x00FF)) #define LOBYTE(x) ((uint8_t)((x) & 0x00FF))
#define HIBYTE(x) ((uint8_t)((x & 0xFF00) >>8)) #define HIBYTE(x) ((uint8_t)(((x) & 0xFF00) >>8))
#ifndef MIN #ifndef MIN
#define MIN(a, b) (((a) < (b)) ? (a) : (b)) #define MIN(a, b) (((a) < (b)) ? (a) : (b))
@@ -1,62 +0,0 @@
--- Middlewares/ST/STM32_USB_Device_Library/Core/Inc/usbd_def.h (date 1511202099000)
+++ Middlewares/ST/STM32_USB_Device_Library/Core/Inc/usbd_def.h (revision )
@@ -99,6 +99,7 @@
#define USB_DESC_TYPE_ENDPOINT 5
#define USB_DESC_TYPE_DEVICE_QUALIFIER 6
#define USB_DESC_TYPE_OTHER_SPEED_CONFIGURATION 7
+#define USB_DESC_TYPE_IFACE_ASSOCIATION 11
#define USB_DESC_TYPE_BOS 0x0F
#define USB_CONFIG_REMOTE_WAKEUP 2
@@ -147,7 +148,7 @@
typedef struct usb_setup_req
{
-
+
uint8_t bmRequest;
uint8_t bRequest;
uint16_t wValue;
@@ -230,7 +231,7 @@
uint32_t dev_config_status;
USBD_SpeedTypeDef dev_speed;
USBD_EndpointTypeDef ep_in[15];
- USBD_EndpointTypeDef ep_out[15];
+ USBD_EndpointTypeDef ep_out[15];
uint32_t ep0_state;
uint32_t ep0_data_len;
uint8_t dev_state;
@@ -242,10 +243,14 @@
USBD_SetupReqTypedef request;
USBD_DescriptorsTypeDef *pDesc;
- USBD_ClassTypeDef *pClass;
- void *pClassData;
- void *pUserData;
- void *pData;
+ USBD_ClassTypeDef *pClass; // the composite class
+ void *pClassData;
+ void *pUserData;
+ void *pClassData2; // used for secondary class
+ void *pUserData2; // used for secondary class
+ void *pClassData3; // used for tertiary class
+ void *pUserData3; // used for tertiary class
+ void *pData; // this is a pointer to the low level registers struct
} USBD_HandleTypeDef;
/**
@@ -262,8 +267,14 @@
#define LOBYTE(x) ((uint8_t)(x & 0x00FF))
#define HIBYTE(x) ((uint8_t)((x & 0xFF00) >>8))
+
+#ifndef MIN
#define MIN(a, b) (((a) < (b)) ? (a) : (b))
+#endif
+
+#ifndef MAX
#define MAX(a, b) (((a) > (b)) ? (a) : (b))
+#endif
#if defined ( __GNUC__ )
+1
View File
@@ -66,6 +66,7 @@ PCD_HandleTypeDef hpcd_USB_FS;
/* init function */ /* init function */
void MX_USB_DEVICE_Init(void) void MX_USB_DEVICE_Init(void)
{ {
dbg("USB device init ...");
/* USER CODE BEGIN USB_DEVICE_Init_PreTreatment */ /* USER CODE BEGIN USB_DEVICE_Init_PreTreatment */
/* USER CODE END USB_DEVICE_Init_PreTreatment */ /* USER CODE END USB_DEVICE_Init_PreTreatment */
+1 -1
View File
@@ -314,7 +314,7 @@ void USBD_CDC_TransmitDone(USBD_HandleTypeDef *pdev)
assert_param(inIRQ()); assert_param(inIRQ());
portBASE_TYPE taskWoken = pdFALSE; portBASE_TYPE taskWoken = pdFALSE;
assert_param(xSemaphoreGiveFromISR(semVcomTxReadyHandle, &taskWoken) == pdTRUE); assert_param(pdTRUE == xSemaphoreGiveFromISR(semVcomTxReadyHandle, &taskWoken));
portYIELD_FROM_ISR(taskWoken); portYIELD_FROM_ISR(taskWoken);
} }
/* USER CODE END PRIVATE_FUNCTIONS_IMPLEMENTATION */ /* USER CODE END PRIVATE_FUNCTIONS_IMPLEMENTATION */
+6 -6
View File
@@ -84,13 +84,13 @@ void HAL_PCD_MspInit(PCD_HandleTypeDef* pcdHandle)
__HAL_RCC_USB_CLK_ENABLE(); __HAL_RCC_USB_CLK_ENABLE();
/* Peripheral interrupt init */ /* Peripheral interrupt init */
#if defined(GEX_PLAT_F103_BLUEPILL) #if GEX_PLAT_F103_BLUEPILL
HAL_NVIC_SetPriority(USB_LP_CAN1_RX0_IRQn, 5, 0); HAL_NVIC_SetPriority(USB_LP_CAN1_RX0_IRQn, 5, 0);
HAL_NVIC_EnableIRQ(USB_LP_CAN1_RX0_IRQn); HAL_NVIC_EnableIRQ(USB_LP_CAN1_RX0_IRQn);
#elif defined(GEX_PLAT_F072_DISCOVERY) #elif STM32F072xB
HAL_NVIC_SetPriority(USB_IRQn, 3, 0); HAL_NVIC_SetPriority(USB_IRQn, 3, 0);
HAL_NVIC_EnableIRQ(USB_IRQn); HAL_NVIC_EnableIRQ(USB_IRQn);
#elif defined(GEX_PLAT_F303_DISCOVERY) #elif GEX_PLAT_F303_DISCOVERY
// Pins need to be configured here // Pins need to be configured here
/**USB GPIO Configuration /**USB GPIO Configuration
@@ -149,11 +149,11 @@ void HAL_PCD_MspDeInit(PCD_HandleTypeDef* pcdHandle)
__HAL_RCC_USB_CLK_DISABLE(); __HAL_RCC_USB_CLK_DISABLE();
/* Peripheral interrupt Deinit*/ /* Peripheral interrupt Deinit*/
#if defined(GEX_PLAT_F103_BLUEPILL) #if GEX_PLAT_F103_BLUEPILL
HAL_NVIC_DisableIRQ(USB_LP_CAN1_RX0_IRQn); HAL_NVIC_DisableIRQ(USB_LP_CAN1_RX0_IRQn);
#elif defined(GEX_PLAT_F072_DISCOVERY) #elif STM32F072xB
HAL_NVIC_DisableIRQ(USB_IRQn); HAL_NVIC_DisableIRQ(USB_IRQn);
#elif defined(GEX_PLAT_F303_DISCOVERY) #elif GEX_PLAT_F303_DISCOVERY
HAL_NVIC_DisableIRQ(USB_LP_CAN_RX0_IRQn); HAL_NVIC_DisableIRQ(USB_LP_CAN_RX0_IRQn);
#else #else
#error "BAD PLATFORM" #error "BAD PLATFORM"
+9 -4
View File
@@ -2,6 +2,7 @@
// Created by MightyPork on 2017/11/21. // Created by MightyPork on 2017/11/21.
// //
#include <platform/status_led.h>
#include "platform.h" #include "platform.h"
#include "framework/settings.h" #include "framework/settings.h"
#include "utils/ini_parser.h" #include "utils/ini_parser.h"
@@ -64,7 +65,7 @@ static void settings_bulkread_cb(BulkRead *bulk, uint32_t chunk, uint8_t *buffer
if (buffer == NULL) { if (buffer == NULL) {
free_ck(bulk); free_ck(bulk);
iw_end(); iw_end();
dbg("INI read complete."); // dbg("INI read complete.");
return; return;
} }
@@ -80,7 +81,7 @@ static void settings_bulkread_cb(BulkRead *bulk, uint32_t chunk, uint8_t *buffer
*/ */
static TF_Result lst_ini_export(TinyFrame *tf, TF_Msg *msg) static TF_Result lst_ini_export(TinyFrame *tf, TF_Msg *msg)
{ {
dbg("Bulk read INI file"); // dbg("Bulk read INI file");
BulkRead *bulk = malloc_ck(sizeof(BulkRead)); BulkRead *bulk = malloc_ck(sizeof(BulkRead));
assert_param(bulk != NULL); assert_param(bulk != NULL);
@@ -91,6 +92,7 @@ static TF_Result lst_ini_export(TinyFrame *tf, TF_Msg *msg)
bulk->userdata = NULL; bulk->userdata = NULL;
bulkread_start(tf, bulk); bulkread_start(tf, bulk);
Indicator_Effect(STATUS_DISK_BUSY_SHORT);
return TF_STAY; return TF_STAY;
} }
@@ -112,7 +114,7 @@ static void settings_bulkwrite_cb(BulkWrite *bulk, const uint8_t *chunk, uint32_
if (bulk->offset > 0) { if (bulk->offset > 0) {
settings_load_ini_end(); settings_load_ini_end();
dbg("INI write complete"); // dbg("INI write complete");
} else { } else {
dbg("INI write failed"); dbg("INI write failed");
} }
@@ -129,7 +131,7 @@ static void settings_bulkwrite_cb(BulkWrite *bulk, const uint8_t *chunk, uint32_
*/ */
static TF_Result lst_ini_import(TinyFrame *tf, TF_Msg *msg) static TF_Result lst_ini_import(TinyFrame *tf, TF_Msg *msg)
{ {
dbg("Bulk write INI file"); // dbg("Bulk write INI file");
BulkWrite *bulk = malloc_ck(sizeof(BulkWrite)); BulkWrite *bulk = malloc_ck(sizeof(BulkWrite));
assert_param(bulk); assert_param(bulk);
@@ -152,6 +154,8 @@ static TF_Result lst_ini_import(TinyFrame *tf, TF_Msg *msg)
bulkwrite_start(tf, bulk); bulkwrite_start(tf, bulk);
Indicator_Effect(STATUS_DISK_BUSY);
done: done:
return TF_STAY; return TF_STAY;
} }
@@ -161,6 +165,7 @@ done:
/** Listener: Save settings to Flash */ /** Listener: Save settings to Flash */
static TF_Result lst_persist_cfg(TinyFrame *tf, TF_Msg *msg) static TF_Result lst_persist_cfg(TinyFrame *tf, TF_Msg *msg)
{ {
Indicator_Effect(STATUS_DISK_REMOVED);
settings_save(); settings_save();
return TF_STAY; return TF_STAY;
} }
+4 -2
View File
@@ -13,8 +13,10 @@
void SysTick_Handler(void) void SysTick_Handler(void)
{ {
GEX_MsTick(); // OS first, avoids jitter
osSystickHandler(); osSystickHandler();
// GEX periodic updates
GEX_MsTick();
} }
@@ -34,7 +36,7 @@ void vApplicationStackOverflowHook(TaskHandle_t xTask, signed char *pcTaskName)
// && (__CORTEX_M >= 3) // && (__CORTEX_M >= 3)
#if VERBOSE_HARDFAULT #if VERBOSE_HARDFAULT
void __attribute__((used)) HardFault_DumpRegisters( uint32_t *origStack, uint32_t lr_value) void __attribute__((used)) HardFault_DumpRegisters(const uint32_t *origStack, uint32_t lr_value)
{ {
/* These are volatile to try and prevent the compiler/linker optimising them /* These are volatile to try and prevent the compiler/linker optimising them
away as the variables never actually get used. If the debugger won't show the away as the variables never actually get used. If the debugger won't show the
+42 -26
View File
@@ -6,6 +6,7 @@
#include "unit.h" #include "unit.h"
#include "resources.h" #include "resources.h"
#include "hw_utils.h" #include "hw_utils.h"
#include "cfg_utils.h"
#include "unit_registry.h" #include "unit_registry.h"
static bool rsc_initialized = false; static bool rsc_initialized = false;
@@ -21,10 +22,8 @@ const char *const rsc_names[] = {
#undef X #undef X
}; };
// Check that EXTI have higher values than GPIOs in the enum COMPILER_ASSERT(R_PF15 < R_EXTI0);
// (determines the logic in the name generation code below) COMPILER_ASSERT(R_PA0 == 0);
COMPILER_ASSERT(R_EXTI0 > R_PA0);
const char * rsc_get_name(Resource rsc) const char * rsc_get_name(Resource rsc)
{ {
@@ -34,23 +33,45 @@ const char * rsc_get_name(Resource rsc)
// we assume the returned value is not stored anywhere // we assume the returned value is not stored anywhere
// and is directly used in a sprintf call, hence a static buffer is OK to use // and is directly used in a sprintf call, hence a static buffer is OK to use
if (rsc >= R_EXTI0) { // R_PA0 is 0
if (rsc <= R_PF15) {
// we assume the returned value is not stored anywhere
// and is directly used in a sprintf call.
uint8_t index = rsc;
SNPRINTF(gpionamebuf, 8, "P%c%d", 'A'+(index/16), index%16);
return gpionamebuf;
}
if (rsc >= R_EXTI0 && rsc <= R_EXTI15) {
uint8_t index = rsc - R_EXTI0; uint8_t index = rsc - R_EXTI0;
SNPRINTF(gpionamebuf, 8, "EXTI%d", index); SNPRINTF(gpionamebuf, 8, "EXTI%d", index);
return gpionamebuf; return gpionamebuf;
} }
if (rsc >= R_PA0) { return rsc_names[rsc - R_EXTI15 - 1];
// we assume the returned value is not stored anywhere
// and is directly used in a sprintf call.
uint8_t index = rsc - R_PA0;
SNPRINTF(gpionamebuf, 8, "P%c%d", 'A'+(index/16), index%16);
return gpionamebuf;
} }
return rsc_names[rsc]; /** Convert a pin to resource handle */
Resource rsc_portpin2rsc(char port_name, uint8_t pin_number, bool *suc)
{
assert_param(suc != NULL);
if(port_name < 'A' || port_name >= ('A'+PORTS_COUNT)) {
dbg("Bad port: %c", port_name); // TODO proper report
*suc = false;
return R_NONE;
} }
if(pin_number > 15) {
dbg("Bad pin: %d", pin_number); // TODO proper report
*suc = false;
return R_NONE;
}
uint8_t num = (uint8_t) (port_name - 'A');
return R_PA0 + num*16 + pin_number;
}
const char * rsc_get_owner_name(Resource rsc) const char * rsc_get_owner_name(Resource rsc)
{ {
@@ -64,11 +85,12 @@ const char * rsc_get_owner_name(Resource rsc)
void rsc_init_registry(void) void rsc_init_registry(void)
{ {
for(uint32_t i = 0; i < RSCMAP_LEN; i++) { memset(UNIT_PLATFORM.resources, 0xFF, RSCMAP_LEN);
UNIT_PLATFORM.resources[i] = global_rscmap[i] = 0xFF; memset(global_rscmap, 0xFF, RSCMAP_LEN);
}
rsc_initialized = true; rsc_initialized = true;
rsc_dbg("Total %d hw resources, bitmap has %d bytes.", RESOURCE_COUNT, RSCMAP_LEN);
} }
@@ -121,17 +143,11 @@ error_t rsc_claim_range(Unit *unit, Resource rsc0, Resource rsc1)
return E_SUCCESS; return E_SUCCESS;
} }
error_t rsc_claim_gpios(Unit *unit, char port_name, uint16_t pins) error_t rsc_claim_gpios(Unit *unit, char port_name, uint16_t pins)
{ {
bool suc = true;
for (int i = 0; i < 16; i++) { for (int i = 0; i < 16; i++) {
if (pins & (1 << i)) { if (pins & (1 << i)) {
Resource rsc = hw_pin2resource(port_name, (uint8_t) i, &suc); TRY(rsc_claim_pin(unit, port_name, (uint8_t)i));
if (!suc) return E_BAD_CONFIG;
TRY(rsc_claim(unit, rsc));
} }
} }
return E_SUCCESS; return E_SUCCESS;
@@ -141,7 +157,7 @@ error_t rsc_claim_gpios(Unit *unit, char port_name, uint16_t pins)
error_t rsc_claim_pin(Unit *unit, char port_name, uint8_t pin) error_t rsc_claim_pin(Unit *unit, char port_name, uint8_t pin)
{ {
bool suc = true; bool suc = true;
Resource rsc = hw_pin2resource(port_name, pin, &suc); Resource rsc = rsc_portpin2rsc(port_name, pin, &suc);
if (!suc) return E_BAD_CONFIG; if (!suc) return E_BAD_CONFIG;
TRY(rsc_claim(unit, rsc)); TRY(rsc_claim(unit, rsc));
return E_SUCCESS; return E_SUCCESS;
@@ -222,7 +238,7 @@ void rsc_print_all_available(IniWriter *iw)
uint32_t count0 = (iw->count + iw->skip); uint32_t count0 = (iw->count + iw->skip);
bool first = true; bool first = true;
for (uint32_t rsc = 0; rsc < R_PA0; rsc++) { for (uint32_t rsc = R_EXTI15+1; rsc < R_NONE; rsc++) {
if (RSC_IS_HELD(scratchmap, (Resource)rsc)) continue; if (RSC_IS_HELD(scratchmap, (Resource)rsc)) continue;
if (!first) iw_string(iw, ", "); if (!first) iw_string(iw, ", ");
@@ -242,7 +258,7 @@ void rsc_print_all_available(IniWriter *iw)
if (i%16 == 0) { if (i%16 == 0) {
// here we print the previous port // here we print the previous port
if (bitmap != 0) { if (bitmap != 0) {
iw_string(iw, pinmask2str(bitmap, iwbuffer)); iw_string(iw, cfg_pinmask_encode(bitmap, iwbuffer, 0));
bitmap = 0; bitmap = 0;
} }
@@ -257,7 +273,7 @@ void rsc_print_all_available(IniWriter *iw)
} }
// the last one // the last one
if (bitmap != 0) { if (bitmap != 0) {
iw_string(iw, pinmask2str(bitmap, iwbuffer)); iw_string(iw, cfg_pinmask_encode(bitmap, iwbuffer, 0));
} }
iw_newline(iw); iw_newline(iw);
iw_newline(iw); iw_newline(iw);
+10
View File
@@ -94,6 +94,16 @@ void rsc_free(Unit *unit, Resource rsc);
*/ */
void rsc_free_range(Unit *unit, Resource rsc0, Resource rsc1); void rsc_free_range(Unit *unit, Resource rsc0, Resource rsc1);
/**
* Convert pin name and number to a resource enum
*
* @param port_name - char 'A'..'Z'
* @param pin_number - number 0..15
* @param suc - set to false on failure, left unchanged on success
* @return the resource, or R_NONE
*/
Resource rsc_portpin2rsc(char port_name, uint8_t pin_number, bool *suc);
/** /**
* Get name of a resource by the Resource enum. * Get name of a resource by the Resource enum.
* Uses a static buffer, DO NOT store the returned pointer. * Uses a static buffer, DO NOT store the returned pointer.
+7 -3
View File
@@ -12,7 +12,8 @@
X(SPI1) X(SPI2) X(SPI3) \ X(SPI1) X(SPI2) X(SPI3) \
X(I2C1) X(I2C2) X(I2C3) \ X(I2C1) X(I2C2) X(I2C3) \
X(ADC1) X(ADC2) X(ADC3) X(ADC4) \ X(ADC1) X(ADC2) X(ADC3) X(ADC4) \
X(DAC1) X(DAC2) \ X(DAC1) \
X(TSC) \
X(USART1) X(USART2) X(USART3) X(USART4) X(USART5) X(USART6) \ X(USART1) X(USART2) X(USART3) X(USART4) X(USART5) X(USART6) \
X(TIM1) X(TIM2) X(TIM3) X(TIM4) X(TIM5) \ X(TIM1) X(TIM2) X(TIM3) X(TIM4) X(TIM5) \
X(TIM6) X(TIM7) X(TIM8) X(TIM9) X(TIM10) X(TIM11) X(TIM12) X(TIM13) X(TIM14) \ X(TIM6) X(TIM7) X(TIM8) X(TIM9) X(TIM10) X(TIM11) X(TIM12) X(TIM13) X(TIM14) \
@@ -24,7 +25,6 @@
// X(I2S1) X(I2S2) X(I2S3) // X(I2S1) X(I2S2) X(I2S3)
// X(OPAMP1) X(OPAMP2) X(OPAMP3) X(OPAMP4) // X(OPAMP1) X(OPAMP2) X(OPAMP3) X(OPAMP4)
// X(CAN1) X(CAN2) // X(CAN1) X(CAN2)
// X(TSC)
// X(DCMI) // X(DCMI)
// X(ETH) // X(ETH)
// X(FSMC) // X(FSMC)
@@ -59,9 +59,13 @@ typedef enum hw_resource Resource;
/** Enum of all resources */ /** Enum of all resources */
enum hw_resource { enum hw_resource {
#define X(res_name) R_##res_name, #define X(res_name) R_##res_name,
XX_RESOURCES // GPIO are at the beginning, because some units use the constants in their config to represent
// selected pins and those must not change with adding more stuff to the main list
XX_RESOURCES_GPIO XX_RESOURCES_GPIO
// EXTIs (same like GPIOs) have dynamically generated labels to save rom space. Must be contiguous.
XX_RESOURCES_EXTI XX_RESOURCES_EXTI
// All the rest ...
XX_RESOURCES
#undef X #undef X
R_NONE, R_NONE,
RESOURCE_COUNT = R_NONE, RESOURCE_COUNT = R_NONE,
+1 -1
View File
@@ -2,7 +2,6 @@
// Created by MightyPork on 2017/11/26. // Created by MightyPork on 2017/11/26.
// //
#include "utils/avrlibc.h"
#include "platform.h" #include "platform.h"
#include "utils/hexdump.h" #include "utils/hexdump.h"
#include "settings.h" #include "settings.h"
@@ -10,6 +9,7 @@
#include "system_settings.h" #include "system_settings.h"
#include "utils/str_utils.h" #include "utils/str_utils.h"
#include "unit_base.h" #include "unit_base.h"
#include "utils/avrlibc.h"
// pre-declarations // pre-declarations
static void savebuf_flush(PayloadBuilder *pb, bool final); static void savebuf_flush(PayloadBuilder *pb, bool final);
+3 -2
View File
@@ -6,6 +6,7 @@
#include "system_settings.h" #include "system_settings.h"
#include "utils/str_utils.h" #include "utils/str_utils.h"
#include "platform/lock_jumper.h" #include "platform/lock_jumper.h"
#include "cfg_utils.h"
struct system_settings SystemSettings; struct system_settings SystemSettings;
@@ -77,12 +78,12 @@ bool systemsettings_load_ini(const char *restrict key, const char *restrict valu
{ {
bool suc = true; bool suc = true;
if (streq(key, "expose_vcom")) { if (streq(key, "expose_vcom")) {
bool yn = str_parse_yn(value, &suc); bool yn = cfg_bool_parse(value, &suc);
if (suc) SystemSettings.visible_vcom = yn; if (suc) SystemSettings.visible_vcom = yn;
} }
if (streq(key, "ini_comments")) { if (streq(key, "ini_comments")) {
bool yn = str_parse_yn(value, &suc); bool yn = cfg_bool_parse(value, &suc);
if (suc) SystemSettings.ini_comments = yn; if (suc) SystemSettings.ini_comments = yn;
} }
+1
View File
@@ -8,6 +8,7 @@
#include "platform.h" #include "platform.h"
#include "unit.h" #include "unit.h"
#include "hw_utils.h" #include "hw_utils.h"
#include "cfg_utils.h"
#include "resources.h" #include "resources.h"
#include "utils/str_utils.h" #include "utils/str_utils.h"
#include "utils/malloc_safe.h" #include "utils/malloc_safe.h"
+1 -1
View File
@@ -147,7 +147,7 @@ void MX_FREERTOS_Init(void) {
stackmon_register("Main", mainTaskStack, sizeof(mainTaskStack)); stackmon_register("Main", mainTaskStack, sizeof(mainTaskStack));
stackmon_register("Job+Msg", msgJobQueTaskStack, sizeof(msgJobQueTaskStack)); stackmon_register("Job+Msg", msgJobQueTaskStack, sizeof(msgJobQueTaskStack));
stackmon_register("Idle", xIdleStack, sizeof(xIdleStack)); stackmon_register("Idle", xIdleStack, sizeof(xIdleStack));
stackmon_register("Timers", xTimersStack, sizeof(xTimersStack)); // stackmon_register("Timers", xTimersStack, sizeof(xTimersStack));
/* USER CODE END Init */ /* USER CODE END Init */
/* Create the mutex(es) */ /* Create the mutex(es) */
+3
View File
@@ -16,6 +16,9 @@ GEX_SRC_DIR = \
User/units/adc \ User/units/adc \
User/units/sipo \ User/units/sipo \
User/units/fcap \ User/units/fcap \
User/units/touch \
User/units/simple_pwm \
User/units/dac \
User/TinyFrame \ User/TinyFrame \
User/CWPack \ User/CWPack \
User/tasks User/tasks
+12
View File
@@ -43,6 +43,18 @@ void GEX_PreInit(void)
dbg("\r\n\033[37;1m*** GEX "GEX_VERSION" on "GEX_PLATFORM" ***\033[m"); dbg("\r\n\033[37;1m*** GEX "GEX_VERSION" on "GEX_PLATFORM" ***\033[m");
dbg("Build "__DATE__" "__TIME__); dbg("Build "__DATE__" "__TIME__);
PRINTF("Reset cause:");
if (LL_RCC_IsActiveFlag_LPWRRST()) PRINTF(" LPWR");
if (LL_RCC_IsActiveFlag_WWDGRST()) PRINTF(" WWDG");
if (LL_RCC_IsActiveFlag_IWDGRST()) PRINTF(" IWDG");
if (LL_RCC_IsActiveFlag_SFTRST()) PRINTF(" SFT");
if (LL_RCC_IsActiveFlag_PORRST()) PRINTF(" POR");
if (LL_RCC_IsActiveFlag_PINRST()) PRINTF(" PIN");
if (LL_RCC_IsActiveFlag_OBLRST()) PRINTF(" OBL");
if (LL_RCC_IsActiveFlag_V18PWRRST()) PRINTF(" V18PWR");
PUTNL();
LL_RCC_ClearResetFlags();
plat_init(); plat_init();
MX_USB_DEVICE_Init(); MX_USB_DEVICE_Init();
+299
View File
@@ -0,0 +1,299 @@
//
// Created by MightyPork on 2018/02/23.
//
#include "cfg_utils.h"
#include "hw_utils.h"
#include "utils/avrlibc.h"
#include "utils/str_utils.h"
/** Parse a string representation of a pin directly to a resource constant */
Resource cfg_pinrsc_parse(const char *str, bool *suc)
{
char pname;
uint8_t pnum;
if (!cfg_portpin_parse(str, &pname, &pnum)) {
*suc = false;
return R_NONE;
}
return rsc_portpin2rsc(pname, pnum, suc);
}
/** Convert a resource to a pin name - uses a static buffer, result must not be stored! */
char *cfg_pinrsc_encode(Resource rsc)
{
static char buf[4];
uint32_t index = rsc - R_PA0;
uint32_t portnum = (index/16);
uint8_t pinnum = (uint8_t) (index % 16);
if (portnum >= PORTS_COUNT) return "";
buf[0] = (char) ('A' + portnum);
if (pinnum>9) {
buf[1] = '1';
buf[2] = (char) ('0' + (pinnum - 10));
buf[3] = 0;
} else {
buf[1] = (char) ('0' + pinnum);
buf[2] = 0;
}
return buf;
}
/** Parse single pin */
bool cfg_portpin_parse(const char *value, char *targetName, uint8_t *targetNumber)
{
// discard leading 'P'
if (value[0] == 'P') {
value++;
}
size_t len = strlen(value);
if (len<2||len>3) return false;
*targetName = (uint8_t) value[0];
if (!(*targetName >= 'A' && *targetName <= 'H')) return false;
// lets just hope it's OK
*targetNumber = (uint8_t) avr_atoi(value + 1);
return true;
}
/** Parse port name */
bool cfg_port_parse(const char *value, char *targetName)
{
*targetName = (uint8_t) value[0];
if (!(*targetName >= 'A' && *targetName < 'A' + PORTS_COUNT)) return false;
return true;
}
/** Parse a list of pin numbers with ranges and commans/semicolons to a bitmask */
uint32_t cfg_pinmask_parse_32(const char *value, bool *suc)
{
uint32_t bits = 0;
uint32_t acu = 0;
bool inrange = false;
uint32_t rangestart = 0;
// shortcut if none are set
if (value[0] == 0) return 0;
char c;
do {
c = *value++;
if (c == ' ' || c == '\t') {
// skip
}
else if (c >= '0' && c <= '9') {
acu = acu*10 + (c-'0');
}
else if (c == ',' || c == ';' || c == 0) {
// end of number or range
if (!inrange) rangestart = acu;
// swap them if they're in the wrong order
if (acu < rangestart) {
uint32_t swp = acu;
acu = rangestart;
rangestart = swp;
}
if (rangestart > 31) rangestart = 31;
if (acu > 31) acu = 31;
for(uint32_t i=rangestart; i <= acu; i++) {
bits |= 1<<i;
}
inrange = false;
rangestart = 0;
acu = 0;
}
else if (c == '-' || c == ':') {
rangestart = acu;
inrange = true;
acu=0;
} else {
*suc = false;
}
} while (c != 0);
return bits;
}
/** Convert a pin bitmask to the ASCII format understood by str_parse_pinmask() */
char *cfg_pinmask_encode(uint32_t pins, char *buffer, bool ascending)
{
char *b = buffer;
uint32_t start = 0;
bool on = false;
bool first = true;
bool bit;
// shortcut if none are set
if (pins == 0) {
buffer[0] = 0;
return buffer;
}
if (ascending) {
for (int32_t i = 0; i <= 32; i++) {
if (i == 32) {
bit = false;
} else {
bit = 0 != (pins & 1);
pins >>= 1;
}
if (bit) {
if (!on) {
start = (uint32_t) i;
on = true;
}
} else {
if (on) {
if (!first) {
b += SPRINTF(b, ", ");
}
if (start == (uint32_t)(i - 1)) {
b += SPRINTF(b, "%"PRIu32, start);
} else {
b += SPRINTF(b, "%"PRIu32"-%"PRIu32, start, i - 1);
}
first = false;
on = false;
}
}
}
} else {
for (int32_t i = 31; i >= -1; i--) {
if (i == -1) {
bit = false;
} else {
bit = 0 != (pins & 0x80000000);
pins <<= 1;
}
if (bit) {
if (!on) {
start = (uint32_t) i;
on = true;
}
} else {
if (on) {
if (!first) {
b += SPRINTF(b, ", ");
}
if (start == (uint32_t) (i + 1)) {
b += SPRINTF(b, "%"PRIu32, start);
} else {
b += SPRINTF(b, "%"PRIu32"-%"PRIu32, start, i + 1);
}
first = false;
on = false;
}
}
}
}
return buffer;
}
bool cfg_bool_parse(const char *str, bool *suc)
{
// TODO implement strcasecmp without the locale crap from newlib and use it here
if (streq(str, "Y")) return true;
if (streq(str, "N")) return false;
if (streq(str, "1")) return true;
if (streq(str, "0")) return false;
if (streq(str, "H")) return true;
if (streq(str, "L")) return false;
if (streq(str, "YES")) return true;
if (streq(str, "NO")) return false;
if (streq(str, "ON")) return true;
if (streq(str, "OFF")) return false;
*suc = false;
return false;
}
/** Convert number to one of 2 options */
const char *cfg_enum2_encode(uint32_t n,
uint32_t na, const char *a,
uint32_t nb, const char *b)
{
if (n == nb) return b;
return a;
}
/** Convert number to one of 3 options */
const char *cfg_enum3_encode(uint32_t n,
uint32_t na, const char *a,
uint32_t nb, const char *b,
uint32_t nc, const char *c)
{
if (n == nb) return b;
if (n == nc) return c;
return a;
}
/** Convert number to one of 4 options */
const char *cfg_enum4_encode(uint32_t n,
uint32_t na, const char *a,
uint32_t nb, const char *b,
uint32_t nc, const char *c,
uint32_t nd, const char *d)
{
if (n == nb) return b;
if (n == nc) return c;
if (n == nd) return d;
return a;
}
uint32_t cfg_enum2_parse(const char *value,
const char *a, uint32_t na,
const char *b, uint32_t nb,
bool *suc)
{
if (streq(value, a)) return na;
if (streq(value, b)) return nb;
*suc = false;
return na;
}
uint32_t cfg_enum3_parse(const char *value,
const char *a, uint32_t na,
const char *b, uint32_t nb,
const char *c, uint32_t nc,
bool *suc)
{
if (streq(value, a)) return na;
if (streq(value, b)) return nb;
if (streq(value, c)) return nc;
*suc = false;
return na;
}
uint32_t cfg_enum4_parse(const char *value,
const char *a, uint32_t na,
const char *b, uint32_t nb,
const char *c, uint32_t nc,
const char *d, uint32_t nd,
bool *suc)
{
if (streq(value, a)) return na;
if (streq(value, b)) return nb;
if (streq(value, c)) return nc;
if (streq(value, d)) return nd;
*suc = false;
return na;
}
+153
View File
@@ -0,0 +1,153 @@
//
// Created by MightyPork on 2018/02/23.
//
#ifndef GEX_F072_CFG_UTILS_H
#define GEX_F072_CFG_UTILS_H
#include "platform.h"
#include "rsc_enum.h"
#include "utils/avrlibc.h"
/**
* Parse a pin name (e.g. PA0 or A0) to port name and pin number
*
* @param str - source string
* @param targetName - output: port name (one character)
* @param targetNumber - output: pin number 0-15
* @return success
*/
bool cfg_portpin_parse(const char *str, char *targetName, uint8_t *targetNumber);
/**
* Parse a string representation of a pin directly to a resource constant
*
* @param[in] str - source string - e.g. PA0 or A0
* @param[out] suc - written to false on failure
* @return the parsed resource
*/
Resource cfg_pinrsc_parse(const char *str, bool *suc);
/**
* Convert a resource to a pin name - uses a static buffer, result must not be stored!
*
* @param[in] rsc - resource to print
* @return a pointer to a static buffer used for exporting the names
*/
char *cfg_pinrsc_encode(Resource rsc);
/**
* Parse a port name (one character) - validates that it's within range
*
* @param value - source string
* @param targetName - output: port name (one character)
* @return success
*/
bool cfg_port_parse(const char *value, char *targetName);
/**
* Parse a list of pin numbers with ranges and commands/semicolons to a bitmask.
* Supported syntax:
* - comma separated numbers
* - numbers connected by dash or colon form a range (can be in any order)
*
* @param value - source string
* @param suc - set to False if parsing failed
* @return the resulting bitmap
*/
uint32_t cfg_pinmask_parse_32(const char *value, bool *suc);
/** same as cfg_pinmask_parse_32(), but with a cast to u16 */
static inline uint16_t cfg_pinmask_parse(const char *value, bool *suc)
{
return (uint16_t) cfg_pinmask_parse_32(value, suc);
}
/**
* Convert a pin bitmap to the ASCII format understood by str_parse_pinmask()
*
* @param[in] pins - sparse pin map
* @param[out] buffer - output string buffer
* @param[in] ascending - use ordering 0..31 rather than 31..0
* @return the output buffer
*/
char *cfg_pinmask_encode(uint32_t pins, char *buffer, bool ascending);
/** Parse Y/N to bool */
bool cfg_bool_parse(const char *str, bool *suc);
/** Convert number to one of 4 options */
const char *cfg_enum2_encode(uint32_t n,
uint32_t na, const char *a,
uint32_t nb, const char *b);
/** Convert number to one of 4 options */
const char *cfg_enum3_encode(uint32_t n,
uint32_t na, const char *a,
uint32_t nb, const char *b,
uint32_t nc, const char *c);
/** Convert number to one of 4 options */
const char *cfg_enum4_encode(uint32_t n,
uint32_t na, const char *a,
uint32_t nb, const char *b,
uint32_t nc, const char *c,
uint32_t nd, const char *d);
/** Convert string to one of two numeric options */
uint32_t cfg_enum2_parse(const char *tpl,
const char *a, uint32_t na,
const char *b, uint32_t nb,
bool *suc);
/** Convert string to one of three numeric options */
uint32_t cfg_enum3_parse(const char *tpl,
const char *a, uint32_t na,
const char *b, uint32_t nb,
const char *c, uint32_t nc,
bool *suc);
/** Convert string to one of four numeric options */
uint32_t cfg_enum4_parse(const char *tpl,
const char *a, uint32_t na,
const char *b, uint32_t nb,
const char *c, uint32_t nc,
const char *d, uint32_t nd,
bool *suc);
/** Convert bool to a Y or N constant string */
#define str_yn(cond) ((cond) ? ("Y") : ("N"))
static inline uint8_t cfg_u8_parse(const char *value, bool *suc)
{
return (uint8_t) avr_atoi(value);
}
static inline int8_t cfg_i8_parse(const char *value, bool *suc)
{
return (int8_t) avr_atoi(value);
}
static inline uint16_t cfg_u16_parse(const char *value, bool *suc)
{
return (uint16_t) avr_atoi(value);
}
static inline int16_t cfg_i16_parse(const char *value, bool *suc)
{
return (int16_t) avr_atoi(value);
}
static inline uint32_t cfg_u32_parse(const char *value, bool *suc)
{
return (uint32_t) avr_atoi(value);
}
static inline int32_t cfg_i32_parse(const char *value, bool *suc)
{
return (int32_t) avr_atoi(value);
}
#endif //GEX_F072_CFG_UTILS_H
+1 -1
View File
@@ -12,7 +12,7 @@
#define DEBUG_USART_BAUD 115200 #define DEBUG_USART_BAUD 115200
#if GEX_PLAT_F072_DISCOVERY #if GEX_PLAT_F072_DISCOVERY || GEX_PLAT_F072_HUB
#define DEBUG_USART USART1 #define DEBUG_USART USART1
#define DEBUG_USART_RSC R_USART1 #define DEBUG_USART_RSC R_USART1
+49 -219
View File
@@ -3,10 +3,8 @@
// //
#include "platform.h" #include "platform.h"
#include "utils/avrlibc.h"
#include "hw_utils.h" #include "hw_utils.h"
/** Convert pin number to LL bitfield */ /** Convert pin number to LL bitfield */
uint32_t hw_pin2ll(uint8_t pin_number, bool *suc) uint32_t hw_pin2ll(uint8_t pin_number, bool *suc)
{ {
@@ -36,210 +34,19 @@ GPIO_TypeDef *hw_port2periph(char port_name, bool *suc)
return GPIO_PERIPHS[num]; return GPIO_PERIPHS[num];
} }
/** Convert a pin to resource handle */ /** Convert a pin resource to it's LL lib values */
Resource hw_pin2resource(char port_name, uint8_t pin_number, bool *suc) bool hw_pinrsc2ll(Resource rsc, GPIO_TypeDef **port, uint32_t *llpin)
{ {
assert_param(suc != NULL); if (rsc > R_PF15) return false;
uint32_t index = rsc - R_PA0;
if(port_name < 'A' || port_name >= ('A'+PORTS_COUNT)) { uint32_t pname = (index/16);
dbg("Bad port: %c", port_name); // TODO proper report uint8_t pnum = (uint8_t) (index % 16);
*suc = false; if (pname >= PORTS_COUNT) return false;
return R_NONE; *port = GPIO_PERIPHS[pname];
} *llpin = LL_GPIO_PINS[pnum];
if(pin_number > 15) {
dbg("Bad pin: %d", pin_number); // TODO proper report
*suc = false;
return R_NONE;
}
uint8_t num = (uint8_t) (port_name - 'A');
return R_PA0 + num*16 + pin_number;
}
/** Parse single pin */
bool parse_pin(const char *value, char *targetName, uint8_t *targetNumber)
{
// discard leading 'P'
if (value[0] == 'P') {
value++;
}
size_t len = strlen(value);
if (len<2||len>3) return false;
*targetName = (uint8_t) value[0];
if (!(*targetName >= 'A' && *targetName <= 'H')) return false;
// lets just hope it's OK
*targetNumber = (uint8_t) avr_atoi(value + 1);
return true; return true;
} }
/** Parse port name */
bool parse_port_name(const char *value, char *targetName)
{
*targetName = (uint8_t) value[0];
if (!(*targetName >= 'A' && *targetName < 'A' + PORTS_COUNT)) return false;
return true;
}
/** Parse a list of pin numbers with ranges and commans/semicolons to a bitmask */
uint32_t parse_pinmask(const char *value, bool *suc)
{
uint32_t bits = 0;
uint32_t acu = 0;
bool inrange = false;
uint32_t rangestart = 0;
// shortcut if none are set
if (value[0] == 0) return 0;
char c;
do {
c = *value++;
if (c == ' ' || c == '\t') {
// skip
}
else if (c >= '0' && c <= '9') {
acu = acu*10 + (c-'0');
}
else if (c == ',' || c == ';' || c == 0) {
// end of number or range
if (!inrange) rangestart = acu;
// swap them if they're in the wrong order
if (acu < rangestart) {
uint32_t swp = acu;
acu = rangestart;
rangestart = swp;
}
if (rangestart > 31) rangestart = 31;
if (acu > 31) acu = 31;
for(uint32_t i=rangestart; i <= acu; i++) {
bits |= 1<<i;
}
inrange = false;
rangestart = 0;
acu = 0;
}
else if (c == '-' || c == ':') {
rangestart = acu;
inrange = true;
acu=0;
} else {
*suc = false;
}
} while (c != 0);
return bits;
}
/** Convert a pin bitmask to the ASCII format understood by str_parse_pinmask() */
char * pinmask2str(uint32_t pins, char *buffer)
{
char *b = buffer;
uint32_t start = 0;
bool on = false;
bool first = true;
// shortcut if none are set
if (pins == 0) {
buffer[0] = 0;
return buffer;
}
for (int32_t i = 31; i >= -1; i--) {
bool bit;
if (i == -1) {
bit = false;
} else {
bit = 0 != (pins & 0x80000000);
pins <<= 1;
}
if (bit) {
if (!on) {
start = (uint32_t) i;
on = true;
}
} else {
if (on) {
if (!first) {
b += SPRINTF(b, ", ");
}
if (start == (uint32_t)(i+1)) {
b += SPRINTF(b, "%"PRIu32, start);
}
else {
b += SPRINTF(b, "%"PRIu32"-%"PRIu32, start, i + 1);
}
first = false;
on = false;
}
}
}
return buffer;
}
char * pinmask2str_up(uint32_t pins, char *buffer)
{
char *b = buffer;
uint32_t start = 0;
bool on = false;
bool first = true;
// shortcut if none are set
if (pins == 0) {
buffer[0] = 0;
return buffer;
}
for (int32_t i = 0; i <= 32; i++) {
bool bit;
if (i == 32) {
bit = false;
} else {
bit = 0 != (pins & 1);
pins >>= 1;
}
if (bit) {
if (!on) {
start = (uint32_t) i;
on = true;
}
} else {
if (on) {
if (!first) {
b += SPRINTF(b, ", ");
}
if (start == (uint32_t)(i-1)) {
b += SPRINTF(b, "%"PRIu32, start);
}
else {
b += SPRINTF(b, "%"PRIu32"-%"PRIu32, start, i - 1);
}
first = false;
on = false;
}
}
}
return buffer;
}
#pragma GCC push_options #pragma GCC push_options
#pragma GCC optimize ("O2") #pragma GCC optimize ("O2")
/** spread a packed pinfield using a mask */ /** spread a packed pinfield using a mask */
@@ -285,25 +92,13 @@ uint32_t pinmask_pack_32(uint32_t spread, uint32_t mask)
return result; return result;
} }
/** Convert spread port pin number to a packed index using a mask */
uint8_t pinmask_translate(uint32_t mask, uint8_t index)
{
int cnt = 0;
for (int i = 0; i<32; i++) {
if (mask & (1<<i)) {
if (i == index) return (uint8_t) cnt;
cnt++;
}
}
return 0;
}
#pragma GCC pop_options #pragma GCC pop_options
/** Configure unit pins as analog (part of unit teardown) */ /** Configure unit pins as analog (part of unit teardown) */
void hw_deinit_unit_pins(Unit *unit) void hw_deinit_unit_pins(Unit *unit)
{ {
for (uint32_t rsc = R_PA0; rsc <= R_PF15; rsc++) { for (uint32_t rsc = R_PA0; rsc <= R_PF15; rsc++) {
if (RSC_IS_HELD(unit->resources, rsc)) { if (RSC_IS_HELD(unit->resources, (Resource)rsc)) {
rsc_dbg("Freeing pin %s", rsc_get_name((Resource)rsc)); rsc_dbg("Freeing pin %s", rsc_get_name((Resource)rsc));
GPIO_TypeDef *port = GPIO_PERIPHS[(rsc-R_PA0) / 16]; GPIO_TypeDef *port = GPIO_PERIPHS[(rsc-R_PA0) / 16];
uint32_t ll_pin = LL_GPIO_PINS[(rsc-R_PA0)%16]; uint32_t ll_pin = LL_GPIO_PINS[(rsc-R_PA0)%16];
@@ -335,6 +130,30 @@ error_t hw_configure_gpio_af(char port_name, uint8_t pin_num, uint32_t ll_af)
return E_SUCCESS; return E_SUCCESS;
} }
/** Configure a pin to alternate function */
error_t hw_configure_gpiorsc_af(Resource rsc, uint32_t ll_af)
{
#if PLAT_NO_AFNUM
trap("Illegal call to hw_configure_gpio_af() on this platform");
#else
bool suc = true;
GPIO_TypeDef *port;
uint32_t ll_pin;
suc = hw_pinrsc2ll(rsc, &port, &ll_pin);
if (!suc) return E_BAD_CONFIG;
if (ll_pin & 0xFF)
LL_GPIO_SetAFPin_0_7(port, ll_pin, ll_af);
else
LL_GPIO_SetAFPin_8_15(port, ll_pin, ll_af);
LL_GPIO_SetPinMode(port, ll_pin, LL_GPIO_MODE_ALTERNATE);
#endif
return E_SUCCESS;
}
/** Configure pins using sparse map */ /** Configure pins using sparse map */
error_t hw_configure_sparse_pins(char port_name, uint16_t mask, GPIO_TypeDef **port_dest, error_t hw_configure_sparse_pins(char port_name, uint16_t mask, GPIO_TypeDef **port_dest,
uint32_t ll_mode, uint32_t ll_otype) uint32_t ll_mode, uint32_t ll_otype)
@@ -360,7 +179,7 @@ error_t hw_configure_sparse_pins(char port_name, uint16_t mask, GPIO_TypeDef **p
} }
/** Solve a timer/counter's count and prescaller value */ /** Solve a timer/counter's count and prescaller value */
bool solve_timer(uint32_t base_freq, uint32_t required_freq, bool is16bit, bool hw_solve_timer(uint32_t base_freq, uint32_t required_freq, bool is16bit,
uint16_t *presc, uint32_t *count, float *real_freq) uint16_t *presc, uint32_t *count, float *real_freq)
{ {
if (required_freq == 0) return false; if (required_freq == 0) return false;
@@ -394,7 +213,6 @@ bool solve_timer(uint32_t base_freq, uint32_t required_freq, bool is16bit,
return true; return true;
} }
void hw_periph_clock_enable(void *periph) void hw_periph_clock_enable(void *periph)
{ {
// GPIOs are enabled by default on start-up // GPIOs are enabled by default on start-up
@@ -445,7 +263,7 @@ void hw_periph_clock_enable(void *periph)
else if (periph == TIM5) __HAL_RCC_TIM5_CLK_ENABLE(); else if (periph == TIM5) __HAL_RCC_TIM5_CLK_ENABLE();
#endif #endif
#ifdef TIM6 #ifdef TIM6
else if (periph == TIM6) __HAL_RCC_TIM7_CLK_ENABLE(); else if (periph == TIM6) __HAL_RCC_TIM6_CLK_ENABLE();
#endif #endif
#ifdef TIM7 #ifdef TIM7
else if (periph == TIM7) __HAL_RCC_TIM7_CLK_ENABLE(); else if (periph == TIM7) __HAL_RCC_TIM7_CLK_ENABLE();
@@ -493,6 +311,12 @@ void hw_periph_clock_enable(void *periph)
#ifdef DAC2 #ifdef DAC2
else if (periph == DAC2) __HAL_RCC_DAC2_CLK_ENABLE(); else if (periph == DAC2) __HAL_RCC_DAC2_CLK_ENABLE();
#endif #endif
// --- TSC ---
#ifdef TSC
else if (periph == TSC) __HAL_RCC_TSC_CLK_ENABLE();
#endif
else { else {
dbg("Periph 0x%p missing in hw clock enable func", periph); dbg("Periph 0x%p missing in hw clock enable func", periph);
trap("BUG"); trap("BUG");
@@ -550,7 +374,7 @@ void hw_periph_clock_disable(void *periph)
else if (periph == TIM5) __HAL_RCC_TIM5_CLK_DISABLE(); else if (periph == TIM5) __HAL_RCC_TIM5_CLK_DISABLE();
#endif #endif
#ifdef TIM6 #ifdef TIM6
else if (periph == TIM6) __HAL_RCC_TIM7_CLK_DISABLE(); else if (periph == TIM6) __HAL_RCC_TIM6_CLK_DISABLE();
#endif #endif
#ifdef TIM7 #ifdef TIM7
else if (periph == TIM7) __HAL_RCC_TIM7_CLK_DISABLE(); else if (periph == TIM7) __HAL_RCC_TIM7_CLK_DISABLE();
@@ -598,6 +422,12 @@ void hw_periph_clock_disable(void *periph)
#ifdef DAC2 #ifdef DAC2
else if (periph == DAC2) __HAL_RCC_DAC2_CLK_DISABLE(); else if (periph == DAC2) __HAL_RCC_DAC2_CLK_DISABLE();
#endif #endif
// --- TSC ---
#ifdef TSC
else if (periph == TSC) __HAL_RCC_TSC_CLK_DISABLE();
#endif
else { else {
dbg("Periph 0x%p missing in hw clock disable func", periph); dbg("Periph 0x%p missing in hw clock disable func", periph);
trap("BUG"); trap("BUG");
+10 -65
View File
@@ -21,16 +21,6 @@
*/ */
uint32_t hw_pin2ll(uint8_t pin_number, bool *suc); uint32_t hw_pin2ll(uint8_t pin_number, bool *suc);
/**
* Convert pin name and number to a resource enum
*
* @param port_name - char 'A'..'Z'
* @param pin_number - number 0..15
* @param suc - set to false on failure, left unchanged on success
* @return the resource, or R_NONE
*/
Resource hw_pin2resource(char port_name, uint8_t pin_number, bool *suc);
/** /**
* Convert port name to peripheral instance * Convert port name to peripheral instance
* *
@@ -41,55 +31,14 @@ Resource hw_pin2resource(char port_name, uint8_t pin_number, bool *suc);
GPIO_TypeDef *hw_port2periph(char port_name, bool *suc); GPIO_TypeDef *hw_port2periph(char port_name, bool *suc);
/** /**
* Parse a pin name (e.g. PA0 or A0) to port name and pin number * Convert a pin resource to it's LL lib values
* *
* @param str - source string * @param[in] rsc - resource to process
* @param targetName - output: port name (one character) * @param[out] port - output port
* @param targetNumber - output: pin number 0-15 * @param[out] llpin - output LL pin mask
* @return success * @return success
*/ */
bool parse_pin(const char *str, char *targetName, uint8_t *targetNumber); bool hw_pinrsc2ll(Resource rsc, GPIO_TypeDef **port, uint32_t *llpin) __attribute__((warn_unused_result));
/**
* Parse a port name (one character) - validates that it's within range
*
* @param value - source string
* @param targetName - output: port name (one character)
* @return success
*/
bool parse_port_name(const char *value, char *targetName);
/**
* Parse a list of pin numbers with ranges and commands/semicolons to a bitmask.
* Supported syntax:
* - comma separated numbers
* - numbers connected by dash or colon form a range (can be in any order)
*
* @param value - source string
* @param suc - set to False if parsing failed
* @return the resulting bitmap
*/
uint32_t parse_pinmask(const char *value, bool *suc);
/**
* Convert a pin bitmap to the ASCII format understood by str_parse_pinmask()
* This is the downto variant (15..0)
*
* @param pins - sparse pin map
* @param buffer - output string buffer
* @return the output buffer
*/
char * pinmask2str(uint32_t pins, char *buffer);
/**
* Convert a pin bitmap to the ASCII format understood by str_parse_pinmask()
* This is the ascending variant (0..15)
*
* @param pins - sparse pin map
* @param buffer - output string buffer
* @return the output buffer
*/
char * pinmask2str_up(uint32_t pins, char *buffer);
/** /**
* Spread packed port pins using a mask * Spread packed port pins using a mask
@@ -121,13 +70,6 @@ static inline uint16_t pinmask_pack(uint32_t spread, uint32_t mask)
return (uint16_t) pinmask_pack_32(spread, mask); return (uint16_t) pinmask_pack_32(spread, mask);
} }
/**
* Convert spread port pin number to a packed index using a mask
*
* eg. with a mask 0b1010 and index 3, the result is 1 (bit 1 of the packed - 0bX0)
*/
uint8_t pinmask_translate(uint32_t mask, uint8_t index);
/** /**
* Set all GPIO resources held by unit to analog. * Set all GPIO resources held by unit to analog.
* This is a part of unit teardown. * This is a part of unit teardown.
@@ -146,6 +88,9 @@ void hw_deinit_unit_pins(Unit *unit);
*/ */
error_t hw_configure_gpio_af(char port_name, uint8_t pin_num, uint32_t ll_af) __attribute__((warn_unused_result)); error_t hw_configure_gpio_af(char port_name, uint8_t pin_num, uint32_t ll_af) __attribute__((warn_unused_result));
/** Configure a pin to alternate function via rsc */
error_t hw_configure_gpiorsc_af(Resource rsc, uint32_t ll_af) __attribute__((warn_unused_result));
/** /**
* Configure multiple pins using the bitmap pattern * Configure multiple pins using the bitmap pattern
* *
@@ -192,8 +137,8 @@ void hw_periph_clock_disable(void *periph);
* @param[out] real_freq - field for storing the computed real frequency * @param[out] real_freq - field for storing the computed real frequency
* @return true on success * @return true on success
*/ */
bool solve_timer(uint32_t base_freq, uint32_t required_freq, bool is16bit, bool hw_solve_timer(uint32_t base_freq, uint32_t required_freq, bool is16bit,
uint16_t *presc, uint32_t *count, float *real_freq); uint16_t *presc, uint32_t *count, float *real_freq) __attribute__((warn_unused_result));
#define hw_wait_while(call, timeout) \ #define hw_wait_while(call, timeout) \
do { \ do { \
+11 -2
View File
@@ -69,6 +69,7 @@ static struct callbacks_ {
struct cbslot tim16; struct cbslot tim16;
struct cbslot adc1; struct cbslot adc1;
struct cbslot tsc;
// XXX add more callbacks here when needed // XXX add more callbacks here when needed
} callbacks; } callbacks;
@@ -92,7 +93,8 @@ void irqd_init(void)
HAL_NVIC_SetPriority(EXTI2_3_IRQn, 2, 0); HAL_NVIC_SetPriority(EXTI2_3_IRQn, 2, 0);
HAL_NVIC_SetPriority(EXTI4_15_IRQn, 2, 0); HAL_NVIC_SetPriority(EXTI4_15_IRQn, 2, 0);
// NVIC_EnableIRQ(TSC_IRQn); /*!< Touch Sensing Controller Interrupts */ NVIC_EnableIRQ(TSC_IRQn); /*!< Touch Sensing Controller Interrupts */
HAL_NVIC_SetPriority(TSC_IRQn, 2, 0);
NVIC_EnableIRQ(DMA1_Channel1_IRQn); /*!< DMA1 Channel 1 Interrupt */ NVIC_EnableIRQ(DMA1_Channel1_IRQn); /*!< DMA1 Channel 1 Interrupt */
NVIC_EnableIRQ(DMA1_Channel2_3_IRQn); /*!< DMA1 Channel 2 and Channel 3 Interrupt */ NVIC_EnableIRQ(DMA1_Channel2_3_IRQn); /*!< DMA1 Channel 2 and Channel 3 Interrupt */
@@ -111,7 +113,7 @@ void irqd_init(void)
// NVIC_EnableIRQ(TIM3_IRQn); /*!< TIM3 global Interrupt */ // NVIC_EnableIRQ(TIM3_IRQn); /*!< TIM3 global Interrupt */
NVIC_EnableIRQ(TIM6_DAC_IRQn); /*!< TIM6 global and DAC channel underrun error Interrupt */ NVIC_EnableIRQ(TIM6_DAC_IRQn); /*!< TIM6 global and DAC channel underrun error Interrupt */
HAL_NVIC_SetPriority(TIM7_IRQn, 2, 0); // Used for DAC timing HAL_NVIC_SetPriority(TIM6_DAC_IRQn, 2, 0); // Used for DAC timing
NVIC_EnableIRQ(TIM7_IRQn); /*!< TIM7 global Interrupt */ NVIC_EnableIRQ(TIM7_IRQn); /*!< TIM7 global Interrupt */
HAL_NVIC_SetPriority(TIM7_IRQn, 2, 0);// this will be for dac (?) HAL_NVIC_SetPriority(TIM7_IRQn, 2, 0);// this will be for dac (?)
@@ -178,6 +180,8 @@ static struct cbslot *get_slot_for_periph(void *periph)
else if (periph == TIM16) slot = &callbacks.tim16; else if (periph == TIM16) slot = &callbacks.tim16;
// 17 - used by timebase // 17 - used by timebase
else if (periph == TSC) slot = &callbacks.tsc;
else if (periph == ADC1) slot = &callbacks.adc1; else if (periph == ADC1) slot = &callbacks.adc1;
else if (periph >= EXTIS[0] && periph <= EXTIS[15]) { else if (periph >= EXTIS[0] && periph <= EXTIS[15]) {
@@ -352,6 +356,11 @@ void ADC1_COMP_IRQHandler(void)
CALL_IRQ_HANDLER(callbacks.adc1); CALL_IRQ_HANDLER(callbacks.adc1);
} }
void TSC_IRQHandler(void)
{
CALL_IRQ_HANDLER(callbacks.tsc);
}
// other ISRs... // other ISRs...
+3 -8
View File
@@ -26,16 +26,11 @@ void LockJumper_Init(void)
{ {
bool suc = true; bool suc = true;
// Resolve and claim resource Resource pinrsc = rsc_portpin2rsc(LOCK_JUMPER_PORT, LOCK_JUMPER_PIN, &suc);
Resource rsc = hw_pin2resource(LOCK_JUMPER_PORT, LOCK_JUMPER_PIN, &suc);
assert_param(suc); assert_param(suc);
assert_param(E_SUCCESS == rsc_claim(&UNIT_SYSTEM, rsc)); assert_param(E_SUCCESS == rsc_claim(&UNIT_SYSTEM, pinrsc));
assert_param(hw_pinrsc2ll(pinrsc, &lock_periph, &lock_llpin));
// Resolve pin
lock_periph = hw_port2periph(LOCK_JUMPER_PORT, &suc);
lock_llpin = hw_pin2ll(LOCK_JUMPER_PIN, &suc);
assert_param(suc);
// Configure for input // Configure for input
LL_GPIO_SetPinMode(lock_periph, lock_llpin, LL_GPIO_MODE_INPUT); LL_GPIO_SetPinMode(lock_periph, lock_llpin, LL_GPIO_MODE_INPUT);
+27 -6
View File
@@ -21,7 +21,7 @@
#endif #endif
// 180 is normally enough if not doing extensive debug logging // 180 is normally enough if not doing extensive debug logging
#define TSK_STACK_MSG 200 // TF message handler task stack size (all unit commands run on this thread) #define TSK_STACK_MSG 220 // TF message handler task stack size (all unit commands run on this thread)
#define TSK_STACK_IDLE 64 //configMINIMAL_STACK_SIZE #define TSK_STACK_IDLE 64 //configMINIMAL_STACK_SIZE
#define TSK_STACK_TIMERS 64 //configTIMER_TASK_STACK_DEPTH #define TSK_STACK_TIMERS 64 //configTIMER_TASK_STACK_DEPTH
@@ -30,7 +30,7 @@
#define BULK_READ_BUF_LEN 256 // Buffer for TF bulk reads #define BULK_READ_BUF_LEN 256 // Buffer for TF bulk reads
#define UNIT_TMP_LEN 512 // Buffer for internal unit operations #define UNIT_TMP_LEN 256 // Buffer for internal unit operations
#define FLASH_SAVE_BUF_LEN 128 // Malloc'd buffer for saving to flash #define FLASH_SAVE_BUF_LEN 128 // Malloc'd buffer for saving to flash
@@ -38,7 +38,7 @@
#define RX_QUE_CAPACITY 16 // TinyFrame rx queue size (64 bytes each) #define RX_QUE_CAPACITY 16 // TinyFrame rx queue size (64 bytes each)
#define TF_MAX_PAYLOAD_RX 512 // TF max Rx payload #define TF_MAX_PAYLOAD_RX 512 // TF max Rx payload
#define TF_SENDBUF_LEN 64 // TF transmit buffer (can be less than a full frame) #define TF_SENDBUF_LEN 512 // TF transmit buffer (can be less than a full frame)
#define TF_MAX_ID_LST 4 // Frame ID listener count #define TF_MAX_ID_LST 4 // Frame ID listener count
#define TF_MAX_TYPE_LST 6 // Frame Type listener count #define TF_MAX_TYPE_LST 6 // Frame Type listener count
@@ -70,6 +70,7 @@
// PLAT_LOCK_BTN - use a lock button instead of a lock jumper (push to toggle) // PLAT_LOCK_BTN - use a lock button instead of a lock jumper (push to toggle)
// PLAT_LOCK_1CLOSED - lock jumper is active (closed / button pressed) in logical 1 // PLAT_LOCK_1CLOSED - lock jumper is active (closed / button pressed) in logical 1
// PLAT_NO_AFNUM - legacy platform without numbered AF alternatives // PLAT_NO_AFNUM - legacy platform without numbered AF alternatives
// PLAT_FULL_XTAL - use two-wire xtal attachment
#if defined(GEX_PLAT_F103_BLUEPILL) #if defined(GEX_PLAT_F103_BLUEPILL)
@@ -124,10 +125,8 @@
#define STATUS_LED_PORT 'C' #define STATUS_LED_PORT 'C'
#define STATUS_LED_PIN 13 #define STATUS_LED_PIN 13
#elif defined(GEX_PLAT_F072_DISCOVERY) #elif defined(STM32F072xB)
// platform name for the version string
#define GEX_PLATFORM "STM32F072-Discovery"
#define PLAT_AHB_MHZ 48 #define PLAT_AHB_MHZ 48
#define PLAT_APB1_MHZ 48 #define PLAT_APB1_MHZ 48
@@ -162,6 +161,10 @@
// Number of GPIO ports A,B,C... // Number of GPIO ports A,B,C...
#define PORTS_COUNT 6 #define PORTS_COUNT 6
#if defined(GEX_PLAT_F072_DISCOVERY)
// platform name for the version string
#define GEX_PLATFORM "STM32F072-Discovery"
// Lock jumper config // Lock jumper config
#define LOCK_JUMPER_PORT 'A' #define LOCK_JUMPER_PORT 'A'
#define LOCK_JUMPER_PIN 0 #define LOCK_JUMPER_PIN 0
@@ -171,6 +174,24 @@
// Status LED config // Status LED config
#define STATUS_LED_PORT 'C' #define STATUS_LED_PORT 'C'
#define STATUS_LED_PIN 6 // RED LED "UP" #define STATUS_LED_PIN 6 // RED LED "UP"
#elif defined(GEX_PLAT_F072_HUB)
// platform name for the version string
#define GEX_PLATFORM "STM32F072-HUB"
#define PLAT_FULL_XTAL 1
// Lock jumper config
#define LOCK_JUMPER_PORT 'D'
#define LOCK_JUMPER_PIN 2
#define PLAT_LOCK_BTN 1 // toggle button instead of a jumper
#define PLAT_LOCK_1CLOSED 0 // toggle button active in log. 1
// Status LED config
#define STATUS_LED_PORT 'A'
#define STATUS_LED_PIN 15 // RED LED "UP"
#else
#error Bad platform
#endif
#elif defined(GEX_PLAT_F303_DISCOVERY) #elif defined(GEX_PLAT_F303_DISCOVERY)
+3
View File
@@ -15,6 +15,7 @@
#include "debug_uart.h" #include "debug_uart.h"
#include "irq_dispatcher.h" #include "irq_dispatcher.h"
#include "timebase.h" #include "timebase.h"
#include "watchdog.h"
void plat_init(void) void plat_init(void)
{ {
@@ -39,4 +40,6 @@ void plat_init(void)
settings_load(); // XXX maybe this should be moved to the main task settings_load(); // XXX maybe this should be moved to the main task
comm_init(); comm_init();
wd_init();
} }
+18 -8
View File
@@ -2,7 +2,7 @@
// Created by MightyPork on 2017/11/26. // Created by MightyPork on 2017/11/26.
// //
#include <units/fcap/unit_fcap.h> #include <units/dac/unit_dac.h>
#include "platform.h" #include "platform.h"
#include "usbd_core.h" #include "usbd_core.h"
#include "USB/usb_device.h" #include "USB/usb_device.h"
@@ -19,6 +19,9 @@
#include "units/usart/unit_usart.h" #include "units/usart/unit_usart.h"
#include "units/spi/unit_spi.h" #include "units/spi/unit_spi.h"
#include "units/sipo/unit_sipo.h" #include "units/sipo/unit_sipo.h"
#include "units/fcap/unit_fcap.h"
#include "units/touch/unit_touch.h"
#include "units/simple_pwm/unit_pwmdim.h"
#include "hw_utils.h" #include "hw_utils.h"
void plat_init_resources(void) void plat_init_resources(void)
@@ -73,7 +76,7 @@ void plat_init_resources(void)
// BOOT pin(s) // BOOT pin(s)
rv |= rsc_claim(&UNIT_SYSTEM, R_PB2); // BOOT1 rv |= rsc_claim(&UNIT_SYSTEM, R_PB2); // BOOT1
} }
#elif defined(GEX_PLAT_F072_DISCOVERY) #elif defined(STM32F072xB)
// Platform STM32F073RBT // Platform STM32F073RBT
// Additional GPIO ports // Additional GPIO ports
@@ -90,6 +93,9 @@ void plat_init_resources(void)
ureg_add_type(&UNIT_ADC); ureg_add_type(&UNIT_ADC);
ureg_add_type(&UNIT_SIPO); ureg_add_type(&UNIT_SIPO);
ureg_add_type(&UNIT_FCAP); ureg_add_type(&UNIT_FCAP);
ureg_add_type(&UNIT_TOUCH);
ureg_add_type(&UNIT_PWMDIM);
ureg_add_type(&UNIT_DAC);
// Free all present resources // Free all present resources
{ {
@@ -98,7 +104,7 @@ void plat_init_resources(void)
// rsc_free_range(NULL, R_COMP1, R_COMP2); // rsc_free_range(NULL, R_COMP1, R_COMP2);
rsc_free(NULL, R_DAC1); rsc_free(NULL, R_DAC1);
// rsc_free(NULL, R_HDMI_CEC); // rsc_free(NULL, R_HDMI_CEC);
// rsc_free(NULL, R_TSC); rsc_free(NULL, R_TSC);
rsc_free_range(NULL, R_I2C1, R_I2C2); rsc_free_range(NULL, R_I2C1, R_I2C2);
// rsc_free_range(NULL, R_I2S1, R_I2S2); // rsc_free_range(NULL, R_I2S1, R_I2S2);
rsc_free_range(NULL, R_SPI1, R_SPI2); rsc_free_range(NULL, R_SPI1, R_SPI2);
@@ -118,13 +124,17 @@ void plat_init_resources(void)
// Claim resources not available due to board layout or internal usage // Claim resources not available due to board layout or internal usage
{ {
// HAL timebase // HAL timebase
rv |= rsc_claim(&UNIT_SYSTEM, R_TIM1); rv |= rsc_claim(&UNIT_SYSTEM, R_TIM17);
// HSE crystal // HSE crystal
rv |= rsc_claim(&UNIT_SYSTEM, R_PF0); rv |= rsc_claim(&UNIT_SYSTEM, R_PF0);
//rv |= rsc_claim(&UNIT_SYSTEM, R_PF1); // - not used in BYPASS mode
#if PLAT_FULL_XTAL
rv |= rsc_claim(&UNIT_SYSTEM, R_PF1); // - not used in BYPASS mode
#endif
// SWD // SWD
rv |= rsc_claim(&UNIT_SYSTEM, R_PA13); // rv |= rsc_claim(&UNIT_SYSTEM, R_PA13);
rv |= rsc_claim(&UNIT_SYSTEM, R_PA14); // rv |= rsc_claim(&UNIT_SYSTEM, R_PA14);
// USB // USB
rv |= rsc_claim(&UNIT_SYSTEM, R_PA11); rv |= rsc_claim(&UNIT_SYSTEM, R_PA11);
rv |= rsc_claim(&UNIT_SYSTEM, R_PA12); rv |= rsc_claim(&UNIT_SYSTEM, R_PA12);
@@ -154,7 +164,7 @@ void plat_init_resources(void)
rsc_free_range(NULL, R_TIM1, R_TIM4); rsc_free_range(NULL, R_TIM1, R_TIM4);
rsc_free_range(NULL, R_TIM6, R_TIM8); rsc_free_range(NULL, R_TIM6, R_TIM8);
rsc_free_range(NULL, R_TIM15, R_TIM17); rsc_free_range(NULL, R_TIM15, R_TIM17);
// rsc_free(NULL, R_TSC); rsc_free(NULL, R_TSC);
rsc_free_range(NULL, R_USART1, R_USART5); rsc_free_range(NULL, R_USART1, R_USART5);
rsc_free_range(NULL, R_PA0, R_PA15); rsc_free_range(NULL, R_PA0, R_PA15);
+16 -8
View File
@@ -50,13 +50,7 @@ static inline void led_off(void)
/** Set up the LED */ /** Set up the LED */
void Indicator_Init(void) void Indicator_Init(void)
{ {
bool suc = true; assert_param(E_SUCCESS == rsc_claim_pin(&UNIT_SYSTEM, STATUS_LED_PORT, STATUS_LED_PIN));
// Resolve and claim resource
Resource rsc = hw_pin2resource(STATUS_LED_PORT, STATUS_LED_PIN, &suc);
assert_param(suc);
assert_param(E_SUCCESS == rsc_claim(&UNIT_SYSTEM, rsc));
} }
/** Set indicator ON */ /** Set indicator ON */
@@ -67,6 +61,12 @@ void Indicator_Effect(enum GEX_StatusIndicator indicator)
led_on(); led_on();
} }
// prevent the two disk ops interfering (happens in write-reload)
if (indicator == STATUS_DISK_BUSY && active_effect == STATUS_DISK_BUSY_SHORT) return;
if (indicator == STATUS_DISK_BUSY_SHORT && active_effect == STATUS_DISK_BUSY) return;
// TODO add some better protection against effect overlap?
active_effect = indicator; active_effect = indicator;
effect_time = 0; effect_time = 0;
} }
@@ -125,7 +125,15 @@ void Indicator_Tick(void)
active_effect = STATUS_NONE; active_effect = STATUS_NONE;
} }
else if (effect_time % 100 == 0) led_on(); else if (effect_time % 100 == 0) led_on();
else if (effect_time % 100 == 50) led_off(); else if (effect_time % 100 == 20) led_off();
}
else if (active_effect == STATUS_DISK_BUSY_SHORT) {
if (effect_time >= 200) {
led_off();
active_effect = STATUS_NONE;
}
else if (effect_time % 100 == 0) led_on();
else if (effect_time % 100 == 20) led_off();
} }
else if (active_effect == STATUS_WELCOME) { else if (active_effect == STATUS_WELCOME) {
if (effect_time == 0) led_on(); if (effect_time == 0) led_on();
+1
View File
@@ -16,6 +16,7 @@ enum GEX_StatusIndicator {
STATUS_NONE = 0, STATUS_NONE = 0,
STATUS_FAULT, STATUS_FAULT,
STATUS_DISK_BUSY, STATUS_DISK_BUSY,
STATUS_DISK_BUSY_SHORT,
STATUS_DISK_ATTACHED, STATUS_DISK_ATTACHED,
STATUS_DISK_REMOVED, STATUS_DISK_REMOVED,
STATUS_WELCOME, STATUS_WELCOME,
+20 -7
View File
@@ -7,8 +7,6 @@
// ---------------------------- HAL TIMEBASE ----------------------------- // ---------------------------- HAL TIMEBASE -----------------------------
#define TIMEBASE_TIMER TIM17
HAL_StatusTypeDef HAL_InitTick(uint32_t TickPriority) HAL_StatusTypeDef HAL_InitTick(uint32_t TickPriority)
{ {
// EDIT - used 17 instead because 14 was needed for fcap // EDIT - used 17 instead because 14 was needed for fcap
@@ -102,21 +100,36 @@ uint64_t PTIM_GetMicrotime(void)
return (uint64_t) uwMillis * 1000 + uwMicros; return (uint64_t) uwMillis * 1000 + uwMicros;
} }
/** microsecond delay */ /** microsecond delay */
void PTIM_MicroDelay(uint16_t usec) void PTIM_MicroDelayAligned(uint32_t usec, register const uint32_t start)
{ {
assert_param(usec < 1000); assert_param(usec < 1000);
const uint16_t start = (uint16_t) TIMEBASE_TIMER->CNT; register const uint32_t remain = (1000 - start);
const uint16_t remain = (uint16_t) (999 - start);
if (remain > usec) { if (remain > usec) {
// timer still has enough space going forward to pass the required wait time // timer still has enough space going forward to pass the required wait time
for (; TIMEBASE_TIMER->CNT < start + usec;); register const uint32_t end = start + usec;
while (TIMEBASE_TIMER->CNT < end) {
__NOP();
__NOP();
__NOP();
}
return;
} }
else { else {
// timer is too close to the end // timer is too close to the end
usec -= remain; usec -= remain;
for (; TIMEBASE_TIMER->CNT >= start || TIMEBASE_TIMER->CNT < usec;); while (1) {
register const uint32_t t = TIMEBASE_TIMER->CNT;
if (t < start && t >= usec) return;
} }
} }
}
/** microsecond delay */
void PTIM_MicroDelay(const uint32_t usec)
{
PTIM_MicroDelayAligned(usec, TIMEBASE_TIMER->CNT);
}
+21 -1
View File
@@ -13,6 +13,8 @@
#include "platform.h" #include "platform.h"
#define TIMEBASE_TIMER TIM17
/** /**
* Precision timer: get microtime as uint64_t * Precision timer: get microtime as uint64_t
* This timestamp should be monotonously increasing with a precision of ±0.5µs * This timestamp should be monotonously increasing with a precision of ±0.5µs
@@ -36,6 +38,24 @@ static inline uint32_t PTIM_GetTime(void)
* *
* @param usec - max 998 * @param usec - max 998
*/ */
void PTIM_MicroDelay(uint16_t usec); void PTIM_MicroDelay(uint32_t usec);
/**
* Microsecond busy delay with alignment (reduced length jitter but possible up to 1 us delay)
*
* @param usec
*/
void PTIM_MicroDelayAligned(uint32_t usec, uint32_t start);
/**
* Wait until the next micro timer tick
*/
static inline uint32_t PTIM_MicroDelayAlign(void)
{
const uint32_t c = TIMEBASE_TIMER->CNT;
uint32_t res;
while ((res = TIMEBASE_TIMER->CNT) == c);
return res;
}
#endif //GEX_F072_TIMEBASE_H #endif //GEX_F072_TIMEBASE_H
+57
View File
@@ -0,0 +1,57 @@
//
// Created by MightyPork on 2018/02/27.
//
#include "platform.h"
#include "watchdog.h"
static volatile uint16_t suspend_depth = 0;
static volatile bool restart_pending = false;
void wd_init(void)
{
dbg("IWDG init, time 2s");
LL_IWDG_Enable(IWDG);
LL_IWDG_EnableWriteAccess(IWDG);
LL_IWDG_SetPrescaler(IWDG, LL_IWDG_PRESCALER_32); // 0.8 ms
LL_IWDG_SetReloadCounter(IWDG, 2500); // 2s. max 4095
while (!LL_IWDG_IsReady(IWDG));
// reload
LL_IWDG_ReloadCounter(IWDG);
}
void wd_suspend(void)
{
vPortEnterCritical();
if (suspend_depth < 0xFFFF) {
suspend_depth++;
}
vPortExitCritical();
}
void wd_resume(void)
{
vPortEnterCritical();
if (suspend_depth > 0) {
suspend_depth--;
if (suspend_depth == 0 && restart_pending) {
restart_pending = false;
LL_IWDG_ReloadCounter(IWDG);
}
}
vPortExitCritical();
}
void wd_restart(void)
{
vPortEnterCritical();
if (suspend_depth == 0) {
LL_IWDG_ReloadCounter(IWDG);
} else {
restart_pending = true;
}
vPortExitCritical();
}
+32
View File
@@ -0,0 +1,32 @@
//
// Created by MightyPork on 2018/02/27.
//
#ifndef GEX_F072_WATCHDOG_H
#define GEX_F072_WATCHDOG_H
/**
* Initialize the application watchdog
*/
void wd_init(void);
/**
* Suspend watchdog restarts until resumed
* (used in other tasks to prevent the main task clearing the wd if the other task is locked up)
*
* The suspend/resume calls can be stacked.
*/
void wd_suspend(void);
/**
* Resume restarts
*/
void wd_resume(void);
/**
* Restart the wd. If restarts are suspended, postpone the restart until resumed
* and then restart immediately.
*/
void wd_restart(void);
#endif //GEX_F072_WATCHDOG_H
+3 -2
View File
@@ -4,6 +4,7 @@
#include "platform.h" #include "platform.h"
#include "platform/lock_jumper.h" #include "platform/lock_jumper.h"
#include "platform/watchdog.h"
#include "status_led.h" #include "status_led.h"
#include "utils/stacksmon.h" #include "utils/stacksmon.h"
#include "vfs/vfs_manager.h" #include "vfs/vfs_manager.h"
@@ -12,8 +13,6 @@
#include "usbd_msc.h" #include "usbd_msc.h"
#include "task_main.h" #include "task_main.h"
extern void plat_init(void);
/* TaskUsbEvent function */ /* TaskUsbEvent function */
void TaskMain(void const * argument) void TaskMain(void const * argument)
{ {
@@ -47,6 +46,8 @@ void TaskMain(void const * argument)
cnt++; cnt++;
Indicator_Heartbeat(); Indicator_Heartbeat();
wd_restart();
} }
// if no message and it just timed out, go wait some more... // if no message and it just timed out, go wait some more...
+3
View File
@@ -3,6 +3,7 @@
// //
#include "platform.h" #include "platform.h"
#include "platform/watchdog.h"
#include "comm/messages.h" #include "comm/messages.h"
#include "task_msg.h" #include "task_msg.h"
@@ -85,7 +86,9 @@ void TaskMsgJob(const void *argument)
#if CDC_LOOPBACK_TEST #if CDC_LOOPBACK_TEST
TF_WriteImpl(comm, slot.msg.data, slot.msg.len); TF_WriteImpl(comm, slot.msg.data, slot.msg.len);
#else #else
wd_suspend();
TF_Accept(comm, slot.msg.data, slot.msg.len); TF_Accept(comm, slot.msg.data, slot.msg.len);
wd_resume();
#endif #endif
} }
+1 -13
View File
@@ -14,15 +14,6 @@ error_t OW_preInit(Unit *unit)
struct priv *priv = unit->data = calloc_ck(1, sizeof(struct priv)); struct priv *priv = unit->data = calloc_ck(1, sizeof(struct priv));
if (priv == NULL) return E_OUT_OF_MEM; if (priv == NULL) return E_OUT_OF_MEM;
// the timer is not started until needed
priv->busyWaitTimer = xTimerCreate("1w_tim", // name
750, // interval (will be changed when starting it)
true, // periodic (we use this only for the polling variant, the one-shot will stop the timer in the CB)
unit, // user data
OW_TimerCb); // callback
if (priv->busyWaitTimer == NULL) return E_OUT_OF_MEM;
// some defaults // some defaults
priv->pin_number = 0; priv->pin_number = 0;
priv->port_name = 'A'; priv->port_name = 'A';
@@ -40,7 +31,7 @@ error_t OW_init(Unit *unit)
// --- Parse config --- // --- Parse config ---
priv->ll_pin = hw_pin2ll(priv->pin_number, &suc); priv->ll_pin = hw_pin2ll(priv->pin_number, &suc);
priv->port = hw_port2periph(priv->port_name, &suc); priv->port = hw_port2periph(priv->port_name, &suc);
Resource rsc = hw_pin2resource(priv->port_name, priv->pin_number, &suc); Resource rsc = rsc_portpin2rsc(priv->port_name, priv->pin_number, &suc);
if (!suc) return E_BAD_CONFIG; if (!suc) return E_BAD_CONFIG;
// --- Claim resources --- // --- Claim resources ---
@@ -63,9 +54,6 @@ void OW_deInit(Unit *unit)
// Release all resources // Release all resources
rsc_teardown(unit); rsc_teardown(unit);
// Delete the software timer
assert_param(pdPASS == xTimerDelete(priv->busyWaitTimer, 1000));
// Free memory // Free memory
free_ck(unit->data); free_ck(unit->data);
} }
+4 -6
View File
@@ -18,17 +18,15 @@ void OW_loadBinary(Unit *unit, PayloadParser *pp)
priv->port_name = pp_char(pp); priv->port_name = pp_char(pp);
priv->pin_number = pp_u8(pp); priv->pin_number = pp_u8(pp);
if (version >= 1) {
priv->parasitic = pp_bool(pp); priv->parasitic = pp_bool(pp);
} }
}
/** Write to a binary buffer for storing in Flash */ /** Write to a binary buffer for storing in Flash */
void OW_writeBinary(Unit *unit, PayloadBuilder *pb) void OW_writeBinary(Unit *unit, PayloadBuilder *pb)
{ {
struct priv *priv = unit->data; struct priv *priv = unit->data;
pb_u8(pb, 1); // version pb_u8(pb, 0); // version
pb_char(pb, priv->port_name); pb_char(pb, priv->port_name);
pb_u8(pb, priv->pin_number); pb_u8(pb, priv->pin_number);
@@ -44,10 +42,10 @@ error_t OW_loadIni(Unit *unit, const char *key, const char *value)
struct priv *priv = unit->data; struct priv *priv = unit->data;
if (streq(key, "pin")) { if (streq(key, "pin")) {
suc = parse_pin(value, &priv->port_name, &priv->pin_number); suc = cfg_portpin_parse(value, &priv->port_name, &priv->pin_number);
} }
else if (streq(key, "parasitic")) { else if (streq(key, "parasitic")) {
priv->parasitic = str_parse_yn(value, &suc); priv->parasitic = cfg_bool_parse(value, &suc);
} }
else { else {
return E_BAD_KEY; return E_BAD_KEY;
@@ -66,5 +64,5 @@ void OW_writeIni(Unit *unit, IniWriter *iw)
iw_entry(iw, "pin", "%c%d", priv->port_name, priv->pin_number); iw_entry(iw, "pin", "%c%d", priv->port_name, priv->pin_number);
iw_comment(iw, "Parasitic (bus-powered) mode"); iw_comment(iw, "Parasitic (bus-powered) mode");
iw_entry(iw, "parasitic", str_yn(priv->parasitic)); iw_entry_s(iw, "parasitic", str_yn(priv->parasitic));
} }
+16 -13
View File
@@ -38,12 +38,13 @@ static void OW_TimerRespCb(Job *job)
* *
* @param xTimer * @param xTimer
*/ */
void OW_TimerCb(TimerHandle_t xTimer) void OW_tickHandler(Unit *unit)
{ {
Unit *unit = pvTimerGetTimerID(xTimer);
assert_param(unit);
struct priv *priv = unit->data; struct priv *priv = unit->data;
assert_param(priv->busy); if(!priv->busy) {
dbg("ow tick should be disabled now!");
return;
}
if (priv->parasitic) { if (priv->parasitic) {
// this is the end of the 750ms measurement time // this is the end of the 750ms measurement time
@@ -56,7 +57,8 @@ void OW_TimerCb(TimerHandle_t xTimer)
uint32_t time = PTIM_GetTime(); uint32_t time = PTIM_GetTime();
if (time - priv->busyStart > 1000) { if (time - priv->busyStart > 1000) {
xTimerStop(xTimer, 100); unit->tick_interval = 0;
unit->_tick_cnt = 0;
Job j = { Job j = {
.unit = unit, .unit = unit,
@@ -69,7 +71,8 @@ void OW_TimerCb(TimerHandle_t xTimer)
return; return;
halt_ok: halt_ok:
xTimerStop(xTimer, 100); unit->tick_interval = 0;
unit->_tick_cnt = 0;
Job j = { Job j = {
.unit = unit, .unit = unit,
@@ -79,7 +82,6 @@ halt_ok:
scheduleJob(&j); scheduleJob(&j);
} }
enum PinCmd_ { enum PinCmd_ {
CMD_CHECK_PRESENCE = 0, // simply tests that any devices are attached CMD_CHECK_PRESENCE = 0, // simply tests that any devices are attached
CMD_SEARCH_ADDR = 1, // perform a scan of the bus, retrieving all found device ROMs CMD_SEARCH_ADDR = 1, // perform a scan of the bus, retrieving all found device ROMs
@@ -87,7 +89,7 @@ enum PinCmd_ {
CMD_SEARCH_CONTINUE = 3, // continue the previously started scan, retrieving more devices CMD_SEARCH_CONTINUE = 3, // continue the previously started scan, retrieving more devices
CMD_READ_ADDR = 4, // read the ROM code from a single device (for single-device bus) CMD_READ_ADDR = 4, // read the ROM code from a single device (for single-device bus)
CMD_WRITE = 10, // write multiple bytes using the SKIP_ROM command CMD_QUERY = 10, // write multiple bytes using the SKIP_ROM command
CMD_READ = 11, // write multiple bytes using a ROM address CMD_READ = 11, // write multiple bytes using a ROM address
CMD_POLL_FOR_1 = 20, CMD_POLL_FOR_1 = 20,
@@ -120,13 +122,13 @@ static error_t OW_handleRequest(Unit *unit, TF_ID frame_id, uint8_t command, Pay
*/ */
case CMD_POLL_FOR_1: case CMD_POLL_FOR_1:
// This can't be exposed via the UU API, due to being async // This can't be exposed via the UU API, due to being async
unit->_tick_cnt = 0;
unit->tick_interval = 750;
if (priv->parasitic) { if (priv->parasitic) {
assert_param(pdPASS == xTimerChangePeriod(priv->busyWaitTimer, 750, 100)); unit->tick_interval = 750;
} else { } else {
// every 10 ticks unit->tick_interval = 10;
assert_param(pdPASS == xTimerChangePeriod(priv->busyWaitTimer, 10, 100));
} }
assert_param(pdPASS == xTimerStart(priv->busyWaitTimer, 100));
priv->busy = true; priv->busy = true;
priv->busyStart = PTIM_GetTime(); priv->busyStart = PTIM_GetTime();
priv->busyRequestId = frame_id; priv->busyRequestId = frame_id;
@@ -192,7 +194,7 @@ static error_t OW_handleRequest(Unit *unit, TF_ID frame_id, uint8_t command, Pay
* addr:u64, rest:write_data * addr:u64, rest:write_data
* if addr is 0, use SKIP_ROM * if addr is 0, use SKIP_ROM
*/ */
case CMD_WRITE: case CMD_QUERY:
addr = pp_u64(pp); addr = pp_u64(pp);
tail = pp_tail(pp, &remain); tail = pp_tail(pp, &remain);
TRY(UU_1WIRE_Write(unit, addr, tail, remain)); TRY(UU_1WIRE_Write(unit, addr, tail, remain));
@@ -242,4 +244,5 @@ const UnitDriver UNIT_1WIRE = {
.deInit = OW_deInit, .deInit = OW_deInit,
// Function // Function
.handleRequest = OW_handleRequest, .handleRequest = OW_handleRequest,
.updateTick = OW_tickHandler,
}; };
+8 -5
View File
@@ -40,7 +40,8 @@ static void UADC_JobSendBlockChunk(Job *job)
.len = (TF_LEN) (1 /*seq*/ + count * sizeof(uint16_t)), .len = (TF_LEN) (1 /*seq*/ + count * sizeof(uint16_t)),
.type = type, .type = type,
}; };
TF_Respond_Multipart(comm, &msg);
assert_param(true == TF_Respond_Multipart(comm, &msg));
TF_Multipart_Payload(comm, &priv->stream_serial, 1); TF_Multipart_Payload(comm, &priv->stream_serial, 1);
TF_Multipart_Payload(comm, (uint8_t *) (priv->dma_buffer + start), count * sizeof(uint16_t)); TF_Multipart_Payload(comm, (uint8_t *) (priv->dma_buffer + start), count * sizeof(uint16_t));
TF_Multipart_Close(comm); TF_Multipart_Close(comm);
@@ -171,7 +172,7 @@ static void handle_httc(Unit *unit, bool tc)
const bool m_fixcpt = priv->opmode == ADC_OPMODE_BLCAP; const bool m_fixcpt = priv->opmode == ADC_OPMODE_BLCAP;
if (ht) { if (ht) {
end = (priv->buf_itemcount / 2); end = (priv->buf_itemcount >> 1); // div2
} }
else { else {
end = priv->buf_itemcount; end = priv->buf_itemcount;
@@ -234,7 +235,7 @@ static void handle_httc(Unit *unit, bool tc)
priv->stream_startpos = 0; priv->stream_startpos = 0;
} }
else { else {
priv->stream_startpos = priv->buf_itemcount / 2; priv->stream_startpos = priv->buf_itemcount >> 1; // div2
} }
} }
@@ -289,7 +290,7 @@ void UADC_DMA_Handler(void *arg)
const bool m_stream = priv->opmode == ADC_OPMODE_STREAM; const bool m_stream = priv->opmode == ADC_OPMODE_STREAM;
const bool m_fixcpt = priv->opmode == ADC_OPMODE_BLCAP; const bool m_fixcpt = priv->opmode == ADC_OPMODE_BLCAP;
if (m_trigd || m_stream || m_fixcpt) { if (m_trigd || m_stream || m_fixcpt) {
const uint32_t half = (uint32_t) (priv->buf_itemcount / 2); const uint32_t half = (uint32_t) (priv->buf_itemcount >> 1); // div2
if (ht && tc) { if (ht && tc) {
// dual event interrupt - may happen if we missed both and they were pending after // dual event interrupt - may happen if we missed both and they were pending after
// interrupts became enabled again (this can happen due to the EOS or other higher prio irq's) // interrupts became enabled again (this can happen due to the EOS or other higher prio irq's)
@@ -336,8 +337,10 @@ void UADC_ADC_EOS_Handler(void *arg)
if (priv->opmode == ADC_OPMODE_UNINIT) return; if (priv->opmode == ADC_OPMODE_UNINIT) return;
// Wait for the DMA to complete copying the last sample // Wait for the DMA to complete copying the last sample
uint32_t dmapos; uint32_t dmapos = DMA_POS(priv);
if ((DMA_POS(priv) % priv->nb_channels) != 0) {
hw_wait_while((dmapos = DMA_POS(priv)) % priv->nb_channels != 0, 100); // XXX this could be changed to reading it from the DR instead hw_wait_while((dmapos = DMA_POS(priv)) % priv->nb_channels != 0, 100); // XXX this could be changed to reading it from the DR instead
}
uint32_t sample_pos; uint32_t sample_pos;
if (dmapos == 0) { if (dmapos == 0) {
+1 -1
View File
@@ -35,7 +35,7 @@ error_t UADC_SetSampleRate(Unit *unit, uint32_t hertz)
uint16_t presc; uint16_t presc;
uint32_t count; uint32_t count;
if (!solve_timer(PLAT_APB1_HZ, hertz, true, &presc, &count, &priv->real_frequency)) { if (!hw_solve_timer(PLAT_APB1_HZ, hertz, true, &presc, &count, &priv->real_frequency)) {
dbg("Failed to resolve timer params."); dbg("Failed to resolve timer params.");
return E_BAD_VALUE; return E_BAD_VALUE;
} }
+10 -10
View File
@@ -48,20 +48,20 @@ error_t UADC_loadIni(Unit *unit, const char *key, const char *value)
struct priv *priv = unit->data; struct priv *priv = unit->data;
if (streq(key, "channels")) { if (streq(key, "channels")) {
priv->cfg.channels = parse_pinmask(value, &suc); priv->cfg.channels = cfg_pinmask_parse_32(value, &suc);
} }
else if (streq(key, "sample_time")) { else if (streq(key, "sample_time")) {
priv->cfg.sample_time = (uint8_t) avr_atoi(value); priv->cfg.sample_time = cfg_u8_parse(value, &suc);
if (priv->cfg.sample_time > 7) return E_BAD_VALUE; if (priv->cfg.sample_time > 7) return E_BAD_VALUE;
} }
else if (streq(key, "frequency")) { else if (streq(key, "frequency")) {
priv->cfg.frequency = (uint32_t) avr_atoi(value); priv->cfg.frequency = cfg_u32_parse(value, &suc);
} }
else if (streq(key, "buffer_size")) { else if (streq(key, "buffer_size")) {
priv->cfg.buffer_size = (uint32_t) avr_atoi(value); priv->cfg.buffer_size = cfg_u32_parse(value, &suc);
} }
else if (streq(key, "avg_factor")) { else if (streq(key, "avg_factor")) {
priv->cfg.averaging_factor = (uint16_t) avr_atoi(value); priv->cfg.averaging_factor = cfg_u16_parse(value, &suc);
if (priv->cfg.averaging_factor > 1000) return E_BAD_VALUE; if (priv->cfg.averaging_factor > 1000) return E_BAD_VALUE;
} }
else { else {
@@ -80,14 +80,14 @@ void UADC_writeIni(Unit *unit, IniWriter *iw)
iw_comment(iw, "Enabled channels, comma separated"); iw_comment(iw, "Enabled channels, comma separated");
iw_comment(iw, " 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17"); iw_comment(iw, " 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17");
iw_comment(iw, "A0 A1 A2 A3 A4 A5 A6 A7 B0 B1 C0 C1 C2 C3 C4 C5 Tsens Vref"); iw_comment(iw, "A0 A1 A2 A3 A4 A5 A6 A7 B0 B1 C0 C1 C2 C3 C4 C5 Tsens Vref");
iw_entry(iw, "channels", "%s", pinmask2str_up(priv->cfg.channels, unit_tmp512)); iw_entry_s(iw, "channels", cfg_pinmask_encode(priv->cfg.channels, unit_tmp512, true));
iw_cmt_newline(iw); iw_cmt_newline(iw);
iw_comment(iw, "Sampling time (0-7)"); iw_comment(iw, "Sampling time (0-7)");
iw_entry(iw, "sample_time", "%d", (int)priv->cfg.sample_time); iw_entry_d(iw, "sample_time", priv->cfg.sample_time);
iw_comment(iw, "Sampling frequency (Hz)"); iw_comment(iw, "Sampling frequency (Hz)");
iw_entry(iw, "frequency", "%d", (int)priv->cfg.frequency); iw_entry_d(iw, "frequency", priv->cfg.frequency);
iw_cmt_newline(iw); iw_cmt_newline(iw);
iw_comment(iw, "Sample buffer size"); iw_comment(iw, "Sample buffer size");
@@ -95,12 +95,12 @@ void UADC_writeIni(Unit *unit, IniWriter *iw)
iw_comment(iw, "- defines the maximum pre-trigger size (divide by # of channels)"); iw_comment(iw, "- defines the maximum pre-trigger size (divide by # of channels)");
iw_comment(iw, "- captured data is sent in half-buffer chunks"); iw_comment(iw, "- captured data is sent in half-buffer chunks");
iw_comment(iw, "- buffer overrun aborts the data capture"); iw_comment(iw, "- buffer overrun aborts the data capture");
iw_entry(iw, "buffer_size", "%d", (int)priv->cfg.buffer_size); iw_entry_d(iw, "buffer_size", priv->cfg.buffer_size);
iw_cmt_newline(iw); iw_cmt_newline(iw);
iw_comment(iw, "Exponential averaging coefficient (permil, range 0-1000 ~ 0.000-1.000)"); iw_comment(iw, "Exponential averaging coefficient (permil, range 0-1000 ~ 0.000-1.000)");
iw_comment(iw, "- used formula: y[t]=(1-k)*y[t-1]+k*u[t]"); iw_comment(iw, "- used formula: y[t]=(1-k)*y[t-1]+k*u[t]");
iw_comment(iw, "- not available when a capture is running"); iw_comment(iw, "- not available when a capture is running");
iw_entry(iw, "avg_factor", "%d", priv->cfg.averaging_factor); iw_entry_d(iw, "avg_factor", priv->cfg.averaging_factor);
} }
+84
View File
@@ -0,0 +1,84 @@
//
// Created by MightyPork on 2018/02/03.
//
#include "platform.h"
#include "unit_base.h"
#include "unit_dac.h"
#define DAC_INTERNAL
#include "_dac_internal.h"
/**
* Re-configure the
* @param unit
*/
void UDAC_Reconfigure(Unit *unit)
{
struct priv *priv = unit->data;
// back-up IT state
bool IT_enabled = (bool) LL_TIM_IsEnabledIT_UPDATE(priv->TIMx);
if (IT_enabled) {
LL_TIM_DisableIT_UPDATE(priv->TIMx);
}
// ...
DAC->CR &= ~(DAC_CR_EN1 | DAC_CR_EN2);
uint32_t CR = 0;
if (priv->cfg.ch[0].enable) {
CR |=
(priv->cfg.ch[0].buffered ? 0 : DAC_CR_BOFF1) |
(priv->ch[0].noise_type << DAC_CR_WAVE1_Pos) |
(priv->ch[0].noise_level & 0xF) << DAC_CR_MAMP1_Pos |
DAC_CR_TEN1 |
(0b111 << DAC_CR_TSEL1_Pos); // software trigger;
CR |= DAC_CR_EN1;
}
if (priv->cfg.ch[1].enable) {
CR |=
(priv->cfg.ch[1].buffered ? 0 : DAC_CR_BOFF2) |
(priv->ch[1].noise_type << DAC_CR_WAVE2_Pos) |
(priv->ch[1].noise_level & 0xF) << DAC_CR_MAMP2_Pos |
DAC_CR_TEN2 |
(0b111 << DAC_CR_TSEL2_Pos); // software trigger
CR |= DAC_CR_EN2;
}
DAC->CR = CR;
// ...
if (IT_enabled) {
LL_TIM_EnableIT_UPDATE(priv->TIMx);
}
}
error_t UDAC_SetFreq(Unit *unit, int channel, float freq)
{
struct priv *priv = unit->data;
priv->ch[channel].increment = (uint32_t) roundf(25.0f * freq * UDAC_VALUE_COUNT * // FIXME constant seems derived from the divide ...?
((float)UDAC_TIM_FREQ_DIVIDER / PLAT_AHB_MHZ)
);
// dbg("Ch %d: Computed increment: %d", channel+1, (int)priv->ch[channel].increment);
return E_SUCCESS;
}
void UDAC_ToggleTimerIfNeeded(Unit *unit)
{
struct priv *priv = unit->data;
if (priv->ch[0].waveform == UDAC_WAVE_DC && priv->ch[1].waveform == UDAC_WAVE_DC) {
LL_TIM_DisableCounter(priv->TIMx);
// manually call the interrupt function to update the level
UDAC_HandleIT(unit);
} else {
LL_TIM_EnableCounter(priv->TIMx);
}
}
+392
View File
@@ -0,0 +1,392 @@
//
// Created by MightyPork on 2018/03/10.
//
#include "platform.h"
#include "unit_dac.h"
#define DAC_INTERNAL
#include "_dac_internal.h"
#pragma GCC push_options
#pragma GCC optimize ("O2")
void UDAC_HandleIT(void *arg)
{
Unit *unit = arg;
struct priv *priv = unit->data;
LL_TIM_ClearFlag_UPDATE(priv->TIMx);
// TODO optimize to allow faster update speed
uint16_t vals[2];
for (int i = 0; i < 2; i++) {
struct udac_channel_live *const ch = &priv->ch[i];
if (ch->waveform == UDAC_WAVE_DC) {
// skip the whole counter thing for DC
vals[i] = ch->dc_level;
continue;
}
ch->counter += ch->increment;
const uint16_t index = (uint16_t) (ch->counter >> UDAC_INDEX_SHIFT);
switch (ch->waveform) {
case UDAC_WAVE_SINE: {
const uint32_t phase = index >> (UDAC_INDEX_WIDTH - 2);
uint32_t pos = (uint32_t) index & (((1<<(UDAC_INDEX_WIDTH - 2)) - 1));
if (phase & 0b01) {
// 2nd and 4th quarter (01, 11)
pos = (UDAC_VALUE_COUNT/4 - 1) - pos;
}
uint32_t value;
/* unpack */
const uint32_t nthbyte = (pos * 3) / 2;
const uint8_t topbyte = LUT_sine_8192_quad_packed[nthbyte];
const uint8_t botbyte = LUT_sine_8192_quad_packed[nthbyte + 1];
if (pos & 1) {
// odd index
value = (uint32_t) (((topbyte & 0xF) << 8) | botbyte);
}
else {
value = (uint32_t) ((topbyte << 4) | ((botbyte & 0xF0) >> 4));
}
/* end unpack -> value */
if (phase & 0b10) {
// 3rd and 4th quarter (10, 11)
value = 2047 - value;
}
else {
// 1st and 2nd quarter (00, 01)
value = 2048 + value;
}
vals[i] = (uint16_t) value;
break;
}
case UDAC_WAVE_RECTANGLE:
if (index < ch->rectangle_ontime) {
vals[i] = ch->rectangle_high;
} else {
vals[i] = ch->rectangle_low;
}
break;
case UDAC_WAVE_SAWTOOTH_UP:
vals[i] = (uint16_t) (index / 2); // for 8192 steps, this will produce 0-4095
break;
case UDAC_WAVE_SAWTOOTH_DOWN:
vals[i] = (uint16_t) (4095 - (index / 2)); // for 8192 steps, this will produce 0-4095
break;
case UDAC_WAVE_TRIANGLE: {
if (index < 4096) {
vals[i] = index;
}
else {
vals[i] = (uint16_t) (8191 - index);
}
break;
}
default:
vals[i] = 0; // this shouldn't happen
break;
} // end select waveform
} // end for 0,1
DAC->DHR12RD = (vals[1] << 16) | vals[0];
// Trigger a conversion
DAC->SWTRIGR = (DAC_SWTR_CH1 | DAC_SWTR_CH2);
}
#pragma GCC pop_options
/**
* This is the first 1/4 of a 12-bit sine wave sampled in 8192 points, each two points packed into three bytes (saves 1/4 of space used by uint16_t's)
* The array holds 2048 data points which can be easily offset / flipped to cover the entire waveform.
*
* |<-->|
* _---_
* / \
* / \
* /---------\---------/
* \ /
* \_ _/
* ---
*/
#if 0 // this is rail to rail, but the dac doesn't work well at the rails and it gets flattened
const uint8_t LUT_sine_8192_quad_packed[] = {
0x00, 0x00, 0x02, 0x00, 0x30, 0x05, 0x00, 0x60, 0x08, 0x00, 0x90, 0x0B, 0x00, 0xD0, 0x0E, 0x01, 0x00, 0x11, 0x01, 0x30, 0x14, 0x01, 0x60, 0x18,
0x01, 0x90, 0x1B, 0x01, 0xC0, 0x1E, 0x01, 0xF0, 0x21, 0x02, 0x30, 0x24, 0x02, 0x60, 0x27, 0x02, 0x90, 0x2A, 0x02, 0xC0, 0x2E, 0x02, 0xF0, 0x31,
0x03, 0x20, 0x34, 0x03, 0x50, 0x37, 0x03, 0x90, 0x3A, 0x03, 0xC0, 0x3D, 0x03, 0xF0, 0x40, 0x04, 0x20, 0x43, 0x04, 0x50, 0x47, 0x04, 0x80, 0x4A,
0x04, 0xB0, 0x4D, 0x04, 0xE0, 0x50, 0x05, 0x20, 0x53, 0x05, 0x50, 0x56, 0x05, 0x80, 0x59, 0x05, 0xB0, 0x5D, 0x05, 0xE0, 0x60, 0x06, 0x10, 0x63,
0x06, 0x40, 0x66, 0x06, 0x80, 0x69, 0x06, 0xB0, 0x6C, 0x06, 0xE0, 0x6F, 0x07, 0x10, 0x73, 0x07, 0x40, 0x76, 0x07, 0x70, 0x79, 0x07, 0xA0, 0x7C,
0x07, 0xE0, 0x7F, 0x08, 0x10, 0x82, 0x08, 0x40, 0x85, 0x08, 0x70, 0x88, 0x08, 0xA0, 0x8C, 0x08, 0xD0, 0x8F, 0x09, 0x00, 0x92, 0x09, 0x30, 0x95,
0x09, 0x70, 0x98, 0x09, 0xA0, 0x9B, 0x09, 0xD0, 0x9E, 0x0A, 0x00, 0xA2, 0x0A, 0x30, 0xA5, 0x0A, 0x60, 0xA8, 0x0A, 0x90, 0xAB, 0x0A, 0xC0, 0xAE,
0x0B, 0x00, 0xB1, 0x0B, 0x30, 0xB4, 0x0B, 0x60, 0xB7, 0x0B, 0x90, 0xBB, 0x0B, 0xC0, 0xBE, 0x0B, 0xF0, 0xC1, 0x0C, 0x20, 0xC4, 0x0C, 0x60, 0xC7,
0x0C, 0x90, 0xCA, 0x0C, 0xC0, 0xCD, 0x0C, 0xF0, 0xD0, 0x0D, 0x20, 0xD4, 0x0D, 0x50, 0xD7, 0x0D, 0x80, 0xDA, 0x0D, 0xB0, 0xDD, 0x0D, 0xF0, 0xE0,
0x0E, 0x20, 0xE3, 0x0E, 0x50, 0xE6, 0x0E, 0x80, 0xE9, 0x0E, 0xB0, 0xED, 0x0E, 0xE0, 0xF0, 0x0F, 0x10, 0xF3, 0x0F, 0x40, 0xF6, 0x0F, 0x70, 0xF9,
0x0F, 0xB0, 0xFC, 0x0F, 0xE0, 0xFF, 0x10, 0x11, 0x02, 0x10, 0x41, 0x05, 0x10, 0x71, 0x09, 0x10, 0xA1, 0x0C, 0x10, 0xD1, 0x0F, 0x11, 0x01, 0x12,
0x11, 0x31, 0x15, 0x11, 0x71, 0x18, 0x11, 0xA1, 0x1B, 0x11, 0xD1, 0x1E, 0x12, 0x01, 0x21, 0x12, 0x31, 0x25, 0x12, 0x61, 0x28, 0x12, 0x91, 0x2B,
0x12, 0xC1, 0x2E, 0x12, 0xF1, 0x31, 0x13, 0x31, 0x34, 0x13, 0x61, 0x37, 0x13, 0x91, 0x3A, 0x13, 0xC1, 0x3D, 0x13, 0xF1, 0x41, 0x14, 0x21, 0x44,
0x14, 0x51, 0x47, 0x14, 0x81, 0x4A, 0x14, 0xB1, 0x4D, 0x14, 0xE1, 0x50, 0x15, 0x21, 0x53, 0x15, 0x51, 0x56, 0x15, 0x81, 0x59, 0x15, 0xB1, 0x5C,
0x15, 0xE1, 0x60, 0x16, 0x11, 0x63, 0x16, 0x41, 0x66, 0x16, 0x71, 0x69, 0x16, 0xA1, 0x6C, 0x16, 0xD1, 0x6F, 0x17, 0x11, 0x72, 0x17, 0x41, 0x75,
0x17, 0x71, 0x78, 0x17, 0xA1, 0x7B, 0x17, 0xD1, 0x7E, 0x18, 0x01, 0x81, 0x18, 0x31, 0x85, 0x18, 0x61, 0x88, 0x18, 0x91, 0x8B, 0x18, 0xC1, 0x8E,
0x18, 0xF1, 0x91, 0x19, 0x21, 0x94, 0x19, 0x61, 0x97, 0x19, 0x91, 0x9A, 0x19, 0xC1, 0x9D, 0x19, 0xF1, 0xA0, 0x1A, 0x21, 0xA3, 0x1A, 0x51, 0xA6,
0x1A, 0x81, 0xA9, 0x1A, 0xB1, 0xAD, 0x1A, 0xE1, 0xB0, 0x1B, 0x11, 0xB3, 0x1B, 0x41, 0xB6, 0x1B, 0x71, 0xB9, 0x1B, 0xA1, 0xBC, 0x1B, 0xD1, 0xBF,
0x1C, 0x11, 0xC2, 0x1C, 0x41, 0xC5, 0x1C, 0x71, 0xC8, 0x1C, 0xA1, 0xCB, 0x1C, 0xD1, 0xCE, 0x1D, 0x01, 0xD1, 0x1D, 0x31, 0xD4, 0x1D, 0x61, 0xD7,
0x1D, 0x91, 0xDB, 0x1D, 0xC1, 0xDE, 0x1D, 0xF1, 0xE1, 0x1E, 0x21, 0xE4, 0x1E, 0x51, 0xE7, 0x1E, 0x81, 0xEA, 0x1E, 0xB1, 0xED, 0x1E, 0xE1, 0xF0,
0x1F, 0x11, 0xF3, 0x1F, 0x41, 0xF6, 0x1F, 0x71, 0xF9, 0x1F, 0xB1, 0xFC, 0x1F, 0xE1, 0xFF, 0x20, 0x12, 0x02, 0x20, 0x42, 0x05, 0x20, 0x72, 0x08,
0x20, 0xA2, 0x0B, 0x20, 0xD2, 0x0E, 0x21, 0x02, 0x11, 0x21, 0x32, 0x14, 0x21, 0x62, 0x17, 0x21, 0x92, 0x1A, 0x21, 0xC2, 0x1D, 0x21, 0xF2, 0x20,
0x22, 0x22, 0x23, 0x22, 0x52, 0x26, 0x22, 0x82, 0x2A, 0x22, 0xB2, 0x2D, 0x22, 0xE2, 0x30, 0x23, 0x12, 0x33, 0x23, 0x42, 0x36, 0x23, 0x72, 0x39,
0x23, 0xA2, 0x3C, 0x23, 0xD2, 0x3F, 0x24, 0x02, 0x42, 0x24, 0x32, 0x45, 0x24, 0x62, 0x48, 0x24, 0x92, 0x4B, 0x24, 0xC2, 0x4E, 0x24, 0xF2, 0x51,
0x25, 0x22, 0x54, 0x25, 0x52, 0x57, 0x25, 0x82, 0x5A, 0x25, 0xB2, 0x5D, 0x25, 0xE2, 0x60, 0x26, 0x12, 0x63, 0x26, 0x42, 0x66, 0x26, 0x72, 0x69,
0x26, 0xA2, 0x6C, 0x26, 0xD2, 0x6F, 0x27, 0x02, 0x72, 0x27, 0x32, 0x75, 0x27, 0x62, 0x78, 0x27, 0x92, 0x7B, 0x27, 0xC2, 0x7E, 0x27, 0xF2, 0x81,
0x28, 0x22, 0x84, 0x28, 0x52, 0x87, 0x28, 0x82, 0x8A, 0x28, 0xB2, 0x8D, 0x28, 0xE2, 0x90, 0x29, 0x12, 0x92, 0x29, 0x42, 0x95, 0x29, 0x72, 0x98,
0x29, 0xA2, 0x9B, 0x29, 0xD2, 0x9E, 0x2A, 0x02, 0xA1, 0x2A, 0x32, 0xA4, 0x2A, 0x62, 0xA7, 0x2A, 0x92, 0xAA, 0x2A, 0xC2, 0xAD, 0x2A, 0xF2, 0xB0,
0x2B, 0x22, 0xB3, 0x2B, 0x52, 0xB6, 0x2B, 0x82, 0xB9, 0x2B, 0xA2, 0xBC, 0x2B, 0xD2, 0xBF, 0x2C, 0x02, 0xC2, 0x2C, 0x32, 0xC5, 0x2C, 0x62, 0xC8,
0x2C, 0x92, 0xCB, 0x2C, 0xC2, 0xCE, 0x2C, 0xF2, 0xD1, 0x2D, 0x22, 0xD4, 0x2D, 0x52, 0xD6, 0x2D, 0x82, 0xD9, 0x2D, 0xB2, 0xDC, 0x2D, 0xE2, 0xDF,
0x2E, 0x12, 0xE2, 0x2E, 0x42, 0xE5, 0x2E, 0x72, 0xE8, 0x2E, 0x92, 0xEB, 0x2E, 0xC2, 0xEE, 0x2E, 0xF2, 0xF1, 0x2F, 0x22, 0xF4, 0x2F, 0x52, 0xF7,
0x2F, 0x82, 0xFA, 0x2F, 0xB2, 0xFC, 0x2F, 0xE2, 0xFF, 0x30, 0x13, 0x02, 0x30, 0x43, 0x05, 0x30, 0x73, 0x08, 0x30, 0xA3, 0x0B, 0x30, 0xC3, 0x0E,
0x30, 0xF3, 0x11, 0x31, 0x23, 0x14, 0x31, 0x53, 0x17, 0x31, 0x83, 0x19, 0x31, 0xB3, 0x1C, 0x31, 0xE3, 0x1F, 0x32, 0x13, 0x22, 0x32, 0x43, 0x25,
0x32, 0x73, 0x28, 0x32, 0x93, 0x2B, 0x32, 0xC3, 0x2E, 0x32, 0xF3, 0x31, 0x33, 0x23, 0x33, 0x33, 0x53, 0x36, 0x33, 0x83, 0x39, 0x33, 0xB3, 0x3C,
0x33, 0xE3, 0x3F, 0x34, 0x03, 0x42, 0x34, 0x33, 0x45, 0x34, 0x63, 0x48, 0x34, 0x93, 0x4A, 0x34, 0xC3, 0x4D, 0x34, 0xF3, 0x50, 0x35, 0x23, 0x53,
0x35, 0x43, 0x56, 0x35, 0x73, 0x59, 0x35, 0xA3, 0x5C, 0x35, 0xD3, 0x5E, 0x36, 0x03, 0x61, 0x36, 0x33, 0x64, 0x36, 0x63, 0x67, 0x36, 0x83, 0x6A,
0x36, 0xB3, 0x6D, 0x36, 0xE3, 0x6F, 0x37, 0x13, 0x72, 0x37, 0x43, 0x75, 0x37, 0x73, 0x78, 0x37, 0x93, 0x7B, 0x37, 0xC3, 0x7E, 0x37, 0xF3, 0x80,
0x38, 0x23, 0x83, 0x38, 0x53, 0x86, 0x38, 0x73, 0x89, 0x38, 0xA3, 0x8C, 0x38, 0xD3, 0x8F, 0x39, 0x03, 0x91, 0x39, 0x33, 0x94, 0x39, 0x63, 0x97,
0x39, 0x83, 0x9A, 0x39, 0xB3, 0x9D, 0x39, 0xE3, 0x9F, 0x3A, 0x13, 0xA2, 0x3A, 0x43, 0xA5, 0x3A, 0x63, 0xA8, 0x3A, 0x93, 0xAB, 0x3A, 0xC3, 0xAD,
0x3A, 0xF3, 0xB0, 0x3B, 0x23, 0xB3, 0x3B, 0x43, 0xB6, 0x3B, 0x73, 0xB8, 0x3B, 0xA3, 0xBB, 0x3B, 0xD3, 0xBE, 0x3B, 0xF3, 0xC1, 0x3C, 0x23, 0xC4,
0x3C, 0x53, 0xC6, 0x3C, 0x83, 0xC9, 0x3C, 0xA3, 0xCC, 0x3C, 0xD3, 0xCF, 0x3D, 0x03, 0xD1, 0x3D, 0x33, 0xD4, 0x3D, 0x63, 0xD7, 0x3D, 0x83, 0xDA,
0x3D, 0xB3, 0xDC, 0x3D, 0xE3, 0xDF, 0x3E, 0x13, 0xE2, 0x3E, 0x33, 0xE5, 0x3E, 0x63, 0xE7, 0x3E, 0x93, 0xEA, 0x3E, 0xB3, 0xED, 0x3E, 0xE3, 0xF0,
0x3F, 0x13, 0xF2, 0x3F, 0x43, 0xF5, 0x3F, 0x63, 0xF8, 0x3F, 0x93, 0xFB, 0x3F, 0xC3, 0xFD, 0x3F, 0xF4, 0x00, 0x40, 0x14, 0x03, 0x40, 0x44, 0x05,
0x40, 0x74, 0x08, 0x40, 0x94, 0x0B, 0x40, 0xC4, 0x0E, 0x40, 0xF4, 0x10, 0x41, 0x24, 0x13, 0x41, 0x44, 0x16, 0x41, 0x74, 0x18, 0x41, 0xA4, 0x1B,
0x41, 0xC4, 0x1E, 0x41, 0xF4, 0x20, 0x42, 0x24, 0x23, 0x42, 0x44, 0x26, 0x42, 0x74, 0x28, 0x42, 0xA4, 0x2B, 0x42, 0xC4, 0x2E, 0x42, 0xF4, 0x30,
0x43, 0x24, 0x33, 0x43, 0x54, 0x36, 0x43, 0x74, 0x39, 0x43, 0xA4, 0x3B, 0x43, 0xD4, 0x3E, 0x43, 0xF4, 0x40, 0x44, 0x24, 0x43, 0x44, 0x44, 0x46,
0x44, 0x74, 0x48, 0x44, 0xA4, 0x4B, 0x44, 0xC4, 0x4E, 0x44, 0xF4, 0x50, 0x45, 0x24, 0x53, 0x45, 0x44, 0x56, 0x45, 0x74, 0x58, 0x45, 0xA4, 0x5B,
0x45, 0xC4, 0x5E, 0x45, 0xF4, 0x60, 0x46, 0x24, 0x63, 0x46, 0x44, 0x65, 0x46, 0x74, 0x68, 0x46, 0x94, 0x6B, 0x46, 0xC4, 0x6D, 0x46, 0xF4, 0x70,
0x47, 0x14, 0x73, 0x47, 0x44, 0x75, 0x47, 0x64, 0x78, 0x47, 0x94, 0x7A, 0x47, 0xC4, 0x7D, 0x47, 0xE4, 0x80, 0x48, 0x14, 0x82, 0x48, 0x34, 0x85,
0x48, 0x64, 0x87, 0x48, 0x94, 0x8A, 0x48, 0xB4, 0x8D, 0x48, 0xE4, 0x8F, 0x49, 0x04, 0x92, 0x49, 0x34, 0x94, 0x49, 0x64, 0x97, 0x49, 0x84, 0x99,
0x49, 0xB4, 0x9C, 0x49, 0xD4, 0x9F, 0x4A, 0x04, 0xA1, 0x4A, 0x24, 0xA4, 0x4A, 0x54, 0xA6, 0x4A, 0x74, 0xA9, 0x4A, 0xA4, 0xAB, 0x4A, 0xD4, 0xAE,
0x4A, 0xF4, 0xB0, 0x4B, 0x24, 0xB3, 0x4B, 0x44, 0xB5, 0x4B, 0x74, 0xB8, 0x4B, 0x94, 0xBB, 0x4B, 0xC4, 0xBD, 0x4B, 0xE4, 0xC0, 0x4C, 0x14, 0xC2,
0x4C, 0x34, 0xC5, 0x4C, 0x64, 0xC7, 0x4C, 0x84, 0xCA, 0x4C, 0xB4, 0xCC, 0x4C, 0xD4, 0xCF, 0x4D, 0x04, 0xD1, 0x4D, 0x24, 0xD4, 0x4D, 0x54, 0xD6,
0x4D, 0x74, 0xD9, 0x4D, 0xA4, 0xDB, 0x4D, 0xC4, 0xDE, 0x4D, 0xF4, 0xE0, 0x4E, 0x14, 0xE3, 0x4E, 0x44, 0xE5, 0x4E, 0x64, 0xE8, 0x4E, 0x94, 0xEA,
0x4E, 0xB4, 0xED, 0x4E, 0xE4, 0xEF, 0x4F, 0x04, 0xF2, 0x4F, 0x34, 0xF4, 0x4F, 0x54, 0xF6, 0x4F, 0x84, 0xF9, 0x4F, 0xA4, 0xFB, 0x4F, 0xD4, 0xFE,
0x4F, 0xF5, 0x00, 0x50, 0x25, 0x03, 0x50, 0x45, 0x05, 0x50, 0x65, 0x08, 0x50, 0x95, 0x0A, 0x50, 0xB5, 0x0D, 0x50, 0xE5, 0x0F, 0x51, 0x05, 0x11,
0x51, 0x35, 0x14, 0x51, 0x55, 0x16, 0x51, 0x75, 0x19, 0x51, 0xA5, 0x1B, 0x51, 0xC5, 0x1D, 0x51, 0xF5, 0x20, 0x52, 0x15, 0x22, 0x52, 0x45, 0x25,
0x52, 0x65, 0x27, 0x52, 0x85, 0x2A, 0x52, 0xB5, 0x2C, 0x52, 0xD5, 0x2E, 0x53, 0x05, 0x31, 0x53, 0x25, 0x33, 0x53, 0x45, 0x35, 0x53, 0x75, 0x38,
0x53, 0x95, 0x3A, 0x53, 0xB5, 0x3D, 0x53, 0xE5, 0x3F, 0x54, 0x05, 0x41, 0x54, 0x35, 0x44, 0x54, 0x55, 0x46, 0x54, 0x75, 0x48, 0x54, 0xA5, 0x4B,
0x54, 0xC5, 0x4D, 0x54, 0xE5, 0x4F, 0x55, 0x15, 0x52, 0x55, 0x35, 0x54, 0x55, 0x55, 0x57, 0x55, 0x85, 0x59, 0x55, 0xA5, 0x5B, 0x55, 0xC5, 0x5E,
0x55, 0xF5, 0x60, 0x56, 0x15, 0x62, 0x56, 0x35, 0x64, 0x56, 0x65, 0x67, 0x56, 0x85, 0x69, 0x56, 0xA5, 0x6B, 0x56, 0xD5, 0x6E, 0x56, 0xF5, 0x70,
0x57, 0x15, 0x72, 0x57, 0x35, 0x75, 0x57, 0x65, 0x77, 0x57, 0x85, 0x79, 0x57, 0xA5, 0x7C, 0x57, 0xD5, 0x7E, 0x57, 0xF5, 0x80, 0x58, 0x15, 0x82,
0x58, 0x35, 0x85, 0x58, 0x65, 0x87, 0x58, 0x85, 0x89, 0x58, 0xA5, 0x8B, 0x58, 0xD5, 0x8E, 0x58, 0xF5, 0x90, 0x59, 0x15, 0x92, 0x59, 0x35, 0x94,
0x59, 0x65, 0x97, 0x59, 0x85, 0x99, 0x59, 0xA5, 0x9B, 0x59, 0xC5, 0x9D, 0x59, 0xF5, 0xA0, 0x5A, 0x15, 0xA2, 0x5A, 0x35, 0xA4, 0x5A, 0x55, 0xA6,
0x5A, 0x75, 0xA9, 0x5A, 0xA5, 0xAB, 0x5A, 0xC5, 0xAD, 0x5A, 0xE5, 0xAF, 0x5B, 0x05, 0xB1, 0x5B, 0x35, 0xB4, 0x5B, 0x55, 0xB6, 0x5B, 0x75, 0xB8,
0x5B, 0x95, 0xBA, 0x5B, 0xB5, 0xBC, 0x5B, 0xD5, 0xBF, 0x5C, 0x05, 0xC1, 0x5C, 0x25, 0xC3, 0x5C, 0x45, 0xC5, 0x5C, 0x65, 0xC7, 0x5C, 0x85, 0xC9,
0x5C, 0xB5, 0xCC, 0x5C, 0xD5, 0xCE, 0x5C, 0xF5, 0xD0, 0x5D, 0x15, 0xD2, 0x5D, 0x35, 0xD4, 0x5D, 0x55, 0xD6, 0x5D, 0x75, 0xD9, 0x5D, 0xA5, 0xDB,
0x5D, 0xC5, 0xDD, 0x5D, 0xE5, 0xDF, 0x5E, 0x05, 0xE1, 0x5E, 0x25, 0xE3, 0x5E, 0x45, 0xE5, 0x5E, 0x65, 0xE7, 0x5E, 0x95, 0xEA, 0x5E, 0xB5, 0xEC,
0x5E, 0xD5, 0xEE, 0x5E, 0xF5, 0xF0, 0x5F, 0x15, 0xF2, 0x5F, 0x35, 0xF4, 0x5F, 0x55, 0xF6, 0x5F, 0x75, 0xF8, 0x5F, 0x95, 0xFA, 0x5F, 0xB5, 0xFC,
0x5F, 0xD5, 0xFF, 0x60, 0x06, 0x01, 0x60, 0x26, 0x03, 0x60, 0x46, 0x05, 0x60, 0x66, 0x07, 0x60, 0x86, 0x09, 0x60, 0xA6, 0x0B, 0x60, 0xC6, 0x0D,
0x60, 0xE6, 0x0F, 0x61, 0x06, 0x11, 0x61, 0x26, 0x13, 0x61, 0x46, 0x15, 0x61, 0x66, 0x17, 0x61, 0x86, 0x19, 0x61, 0xA6, 0x1B, 0x61, 0xC6, 0x1D,
0x61, 0xE6, 0x1F, 0x62, 0x06, 0x21, 0x62, 0x26, 0x23, 0x62, 0x46, 0x25, 0x62, 0x66, 0x27, 0x62, 0x86, 0x29, 0x62, 0xA6, 0x2B, 0x62, 0xC6, 0x2D,
0x62, 0xE6, 0x2F, 0x63, 0x06, 0x31, 0x63, 0x26, 0x33, 0x63, 0x46, 0x35, 0x63, 0x66, 0x37, 0x63, 0x86, 0x39, 0x63, 0xA6, 0x3B, 0x63, 0xC6, 0x3D,
0x63, 0xE6, 0x3F, 0x64, 0x06, 0x41, 0x64, 0x26, 0x43, 0x64, 0x46, 0x45, 0x64, 0x66, 0x47, 0x64, 0x86, 0x49, 0x64, 0xA6, 0x4B, 0x64, 0xC6, 0x4D,
0x64, 0xE6, 0x4F, 0x65, 0x06, 0x51, 0x65, 0x26, 0x53, 0x65, 0x46, 0x54, 0x65, 0x56, 0x56, 0x65, 0x76, 0x58, 0x65, 0x96, 0x5A, 0x65, 0xB6, 0x5C,
0x65, 0xD6, 0x5E, 0x65, 0xF6, 0x60, 0x66, 0x16, 0x62, 0x66, 0x36, 0x64, 0x66, 0x56, 0x66, 0x66, 0x76, 0x67, 0x66, 0x86, 0x69, 0x66, 0xA6, 0x6B,
0x66, 0xC6, 0x6D, 0x66, 0xE6, 0x6F, 0x67, 0x06, 0x71, 0x67, 0x26, 0x73, 0x67, 0x46, 0x75, 0x67, 0x56, 0x76, 0x67, 0x76, 0x78, 0x67, 0x96, 0x7A,
0x67, 0xB6, 0x7C, 0x67, 0xD6, 0x7E, 0x67, 0xF6, 0x80, 0x68, 0x16, 0x81, 0x68, 0x26, 0x83, 0x68, 0x46, 0x85, 0x68, 0x66, 0x87, 0x68, 0x86, 0x89,
0x68, 0xA6, 0x8A, 0x68, 0xB6, 0x8C, 0x68, 0xD6, 0x8E, 0x68, 0xF6, 0x90, 0x69, 0x16, 0x92, 0x69, 0x36, 0x93, 0x69, 0x46, 0x95, 0x69, 0x66, 0x97,
0x69, 0x86, 0x99, 0x69, 0xA6, 0x9B, 0x69, 0xB6, 0x9C, 0x69, 0xD6, 0x9E, 0x69, 0xF6, 0xA0, 0x6A, 0x16, 0xA2, 0x6A, 0x36, 0xA3, 0x6A, 0x46, 0xA5,
0x6A, 0x66, 0xA7, 0x6A, 0x86, 0xA9, 0x6A, 0x96, 0xAA, 0x6A, 0xB6, 0xAC, 0x6A, 0xD6, 0xAE, 0x6A, 0xF6, 0xB0, 0x6B, 0x06, 0xB1, 0x6B, 0x26, 0xB3,
0x6B, 0x46, 0xB5, 0x6B, 0x66, 0xB6, 0x6B, 0x76, 0xB8, 0x6B, 0x96, 0xBA, 0x6B, 0xB6, 0xBC, 0x6B, 0xC6, 0xBD, 0x6B, 0xE6, 0xBF, 0x6C, 0x06, 0xC1,
0x6C, 0x16, 0xC2, 0x6C, 0x36, 0xC4, 0x6C, 0x56, 0xC6, 0x6C, 0x66, 0xC7, 0x6C, 0x86, 0xC9, 0x6C, 0xA6, 0xCB, 0x6C, 0xB6, 0xCC, 0x6C, 0xD6, 0xCE,
0x6C, 0xF6, 0xD0, 0x6D, 0x06, 0xD1, 0x6D, 0x26, 0xD3, 0x6D, 0x46, 0xD4, 0x6D, 0x56, 0xD6, 0x6D, 0x76, 0xD8, 0x6D, 0x96, 0xD9, 0x6D, 0xA6, 0xDB,
0x6D, 0xC6, 0xDD, 0x6D, 0xD6, 0xDE, 0x6D, 0xF6, 0xE0, 0x6E, 0x16, 0xE1, 0x6E, 0x26, 0xE3, 0x6E, 0x46, 0xE5, 0x6E, 0x56, 0xE6, 0x6E, 0x76, 0xE8,
0x6E, 0x96, 0xE9, 0x6E, 0xA6, 0xEB, 0x6E, 0xC6, 0xEC, 0x6E, 0xD6, 0xEE, 0x6E, 0xF6, 0xF0, 0x6F, 0x06, 0xF1, 0x6F, 0x26, 0xF3, 0x6F, 0x46, 0xF4,
0x6F, 0x56, 0xF6, 0x6F, 0x76, 0xF7, 0x6F, 0x86, 0xF9, 0x6F, 0xA6, 0xFA, 0x6F, 0xB6, 0xFC, 0x6F, 0xD6, 0xFE, 0x6F, 0xE6, 0xFF, 0x70, 0x07, 0x01,
0x70, 0x17, 0x02, 0x70, 0x37, 0x04, 0x70, 0x47, 0x05, 0x70, 0x67, 0x07, 0x70, 0x77, 0x08, 0x70, 0x97, 0x0A, 0x70, 0xA7, 0x0B, 0x70, 0xC7, 0x0D,
0x70, 0xD7, 0x0E, 0x70, 0xF7, 0x10, 0x71, 0x07, 0x11, 0x71, 0x27, 0x12, 0x71, 0x37, 0x14, 0x71, 0x57, 0x15, 0x71, 0x67, 0x17, 0x71, 0x87, 0x18,
0x71, 0x97, 0x1A, 0x71, 0xA7, 0x1B, 0x71, 0xC7, 0x1D, 0x71, 0xD7, 0x1E, 0x71, 0xF7, 0x1F, 0x72, 0x07, 0x21, 0x72, 0x27, 0x22, 0x72, 0x37, 0x24,
0x72, 0x47, 0x25, 0x72, 0x67, 0x27, 0x72, 0x77, 0x28, 0x72, 0x97, 0x29, 0x72, 0xA7, 0x2B, 0x72, 0xB7, 0x2C, 0x72, 0xD7, 0x2E, 0x72, 0xE7, 0x2F,
0x73, 0x07, 0x30, 0x73, 0x17, 0x32, 0x73, 0x27, 0x33, 0x73, 0x47, 0x34, 0x73, 0x57, 0x36, 0x73, 0x67, 0x37, 0x73, 0x87, 0x38, 0x73, 0x97, 0x3A,
0x73, 0xA7, 0x3B, 0x73, 0xC7, 0x3C, 0x73, 0xD7, 0x3E, 0x73, 0xE7, 0x3F, 0x74, 0x07, 0x40, 0x74, 0x17, 0x42, 0x74, 0x27, 0x43, 0x74, 0x47, 0x44,
0x74, 0x57, 0x46, 0x74, 0x67, 0x47, 0x74, 0x87, 0x48, 0x74, 0x97, 0x4A, 0x74, 0xA7, 0x4B, 0x74, 0xC7, 0x4C, 0x74, 0xD7, 0x4D, 0x74, 0xE7, 0x4F,
0x74, 0xF7, 0x50, 0x75, 0x17, 0x51, 0x75, 0x27, 0x53, 0x75, 0x37, 0x54, 0x75, 0x47, 0x55, 0x75, 0x67, 0x56, 0x75, 0x77, 0x58, 0x75, 0x87, 0x59,
0x75, 0x97, 0x5A, 0x75, 0xB7, 0x5B, 0x75, 0xC7, 0x5D, 0x75, 0xD7, 0x5E, 0x75, 0xE7, 0x5F, 0x76, 0x07, 0x60, 0x76, 0x17, 0x61, 0x76, 0x27, 0x63,
0x76, 0x37, 0x64, 0x76, 0x47, 0x65, 0x76, 0x67, 0x66, 0x76, 0x77, 0x67, 0x76, 0x87, 0x69, 0x76, 0x97, 0x6A, 0x76, 0xA7, 0x6B, 0x76, 0xB7, 0x6C,
0x76, 0xD7, 0x6D, 0x76, 0xE7, 0x6E, 0x76, 0xF7, 0x70, 0x77, 0x07, 0x71, 0x77, 0x17, 0x72, 0x77, 0x27, 0x73, 0x77, 0x47, 0x74, 0x77, 0x57, 0x75,
0x77, 0x67, 0x76, 0x77, 0x77, 0x78, 0x77, 0x87, 0x79, 0x77, 0x97, 0x7A, 0x77, 0xA7, 0x7B, 0x77, 0xB7, 0x7C, 0x77, 0xD7, 0x7D, 0x77, 0xE7, 0x7E,
0x77, 0xF7, 0x7F, 0x78, 0x07, 0x80, 0x78, 0x17, 0x81, 0x78, 0x27, 0x83, 0x78, 0x37, 0x84, 0x78, 0x47, 0x85, 0x78, 0x57, 0x86, 0x78, 0x67, 0x87,
0x78, 0x77, 0x88, 0x78, 0x87, 0x89, 0x78, 0x97, 0x8A, 0x78, 0xA7, 0x8B, 0x78, 0xC7, 0x8C, 0x78, 0xD7, 0x8D, 0x78, 0xE7, 0x8E, 0x78, 0xF7, 0x8F,
0x79, 0x07, 0x90, 0x79, 0x17, 0x91, 0x79, 0x27, 0x92, 0x79, 0x37, 0x93, 0x79, 0x47, 0x94, 0x79, 0x57, 0x95, 0x79, 0x67, 0x96, 0x79, 0x77, 0x97,
0x79, 0x87, 0x98, 0x79, 0x97, 0x99, 0x79, 0xA7, 0x9A, 0x79, 0xB7, 0x9B, 0x79, 0xC7, 0x9C, 0x79, 0xD7, 0x9D, 0x79, 0xE7, 0x9E, 0x79, 0xE7, 0x9F,
0x79, 0xF7, 0xA0, 0x7A, 0x07, 0xA1, 0x7A, 0x17, 0xA2, 0x7A, 0x27, 0xA3, 0x7A, 0x37, 0xA4, 0x7A, 0x47, 0xA5, 0x7A, 0x57, 0xA5, 0x7A, 0x67, 0xA6,
0x7A, 0x77, 0xA7, 0x7A, 0x87, 0xA8, 0x7A, 0x97, 0xA9, 0x7A, 0xA7, 0xAA, 0x7A, 0xA7, 0xAB, 0x7A, 0xB7, 0xAC, 0x7A, 0xC7, 0xAD, 0x7A, 0xD7, 0xAE,
0x7A, 0xE7, 0xAE, 0x7A, 0xF7, 0xAF, 0x7B, 0x07, 0xB0, 0x7B, 0x17, 0xB1, 0x7B, 0x17, 0xB2, 0x7B, 0x27, 0xB3, 0x7B, 0x37, 0xB4, 0x7B, 0x47, 0xB4,
0x7B, 0x57, 0xB5, 0x7B, 0x67, 0xB6, 0x7B, 0x77, 0xB7, 0x7B, 0x77, 0xB8, 0x7B, 0x87, 0xB9, 0x7B, 0x97, 0xB9, 0x7B, 0xA7, 0xBA, 0x7B, 0xB7, 0xBB,
0x7B, 0xB7, 0xBC, 0x7B, 0xC7, 0xBD, 0x7B, 0xD7, 0xBD, 0x7B, 0xE7, 0xBE, 0x7B, 0xF7, 0xBF, 0x7B, 0xF7, 0xC0, 0x7C, 0x07, 0xC1, 0x7C, 0x17, 0xC1,
0x7C, 0x27, 0xC2, 0x7C, 0x27, 0xC3, 0x7C, 0x37, 0xC4, 0x7C, 0x47, 0xC4, 0x7C, 0x57, 0xC5, 0x7C, 0x57, 0xC6, 0x7C, 0x67, 0xC7, 0x7C, 0x77, 0xC7,
0x7C, 0x87, 0xC8, 0x7C, 0x87, 0xC9, 0x7C, 0x97, 0xC9, 0x7C, 0xA7, 0xCA, 0x7C, 0xA7, 0xCB, 0x7C, 0xB7, 0xCC, 0x7C, 0xC7, 0xCC, 0x7C, 0xD7, 0xCD,
0x7C, 0xD7, 0xCE, 0x7C, 0xE7, 0xCE, 0x7C, 0xF7, 0xCF, 0x7C, 0xF7, 0xD0, 0x7D, 0x07, 0xD0, 0x7D, 0x17, 0xD1, 0x7D, 0x17, 0xD2, 0x7D, 0x27, 0xD2,
0x7D, 0x37, 0xD3, 0x7D, 0x37, 0xD4, 0x7D, 0x47, 0xD4, 0x7D, 0x57, 0xD5, 0x7D, 0x57, 0xD5, 0x7D, 0x67, 0xD6, 0x7D, 0x67, 0xD7, 0x7D, 0x77, 0xD7,
0x7D, 0x87, 0xD8, 0x7D, 0x87, 0xD9, 0x7D, 0x97, 0xD9, 0x7D, 0x97, 0xDA, 0x7D, 0xA7, 0xDA, 0x7D, 0xB7, 0xDB, 0x7D, 0xB7, 0xDC, 0x7D, 0xC7, 0xDC,
0x7D, 0xC7, 0xDD, 0x7D, 0xD7, 0xDD, 0x7D, 0xE7, 0xDE, 0x7D, 0xE7, 0xDE, 0x7D, 0xF7, 0xDF, 0x7D, 0xF7, 0xE0, 0x7E, 0x07, 0xE0, 0x7E, 0x07, 0xE1,
0x7E, 0x17, 0xE1, 0x7E, 0x17, 0xE2, 0x7E, 0x27, 0xE2, 0x7E, 0x27, 0xE3, 0x7E, 0x37, 0xE3, 0x7E, 0x37, 0xE4, 0x7E, 0x47, 0xE4, 0x7E, 0x57, 0xE5,
0x7E, 0x57, 0xE5, 0x7E, 0x67, 0xE6, 0x7E, 0x67, 0xE6, 0x7E, 0x67, 0xE7, 0x7E, 0x77, 0xE7, 0x7E, 0x77, 0xE8, 0x7E, 0x87, 0xE8, 0x7E, 0x87, 0xE9,
0x7E, 0x97, 0xE9, 0x7E, 0x97, 0xEA, 0x7E, 0xA7, 0xEA, 0x7E, 0xA7, 0xEA, 0x7E, 0xB7, 0xEB, 0x7E, 0xB7, 0xEB, 0x7E, 0xC7, 0xEC, 0x7E, 0xC7, 0xEC,
0x7E, 0xC7, 0xED, 0x7E, 0xD7, 0xED, 0x7E, 0xD7, 0xED, 0x7E, 0xE7, 0xEE, 0x7E, 0xE7, 0xEE, 0x7E, 0xE7, 0xEF, 0x7E, 0xF7, 0xEF, 0x7E, 0xF7, 0xEF,
0x7F, 0x07, 0xF0, 0x7F, 0x07, 0xF0, 0x7F, 0x07, 0xF1, 0x7F, 0x17, 0xF1, 0x7F, 0x17, 0xF1, 0x7F, 0x17, 0xF2, 0x7F, 0x27, 0xF2, 0x7F, 0x27, 0xF2,
0x7F, 0x37, 0xF3, 0x7F, 0x37, 0xF3, 0x7F, 0x37, 0xF3, 0x7F, 0x47, 0xF4, 0x7F, 0x47, 0xF4, 0x7F, 0x47, 0xF4, 0x7F, 0x57, 0xF5, 0x7F, 0x57, 0xF5,
0x7F, 0x57, 0xF5, 0x7F, 0x57, 0xF6, 0x7F, 0x67, 0xF6, 0x7F, 0x67, 0xF6, 0x7F, 0x67, 0xF6, 0x7F, 0x77, 0xF7, 0x7F, 0x77, 0xF7, 0x7F, 0x77, 0xF7,
0x7F, 0x77, 0xF8, 0x7F, 0x87, 0xF8, 0x7F, 0x87, 0xF8, 0x7F, 0x87, 0xF8, 0x7F, 0x87, 0xF9, 0x7F, 0x97, 0xF9, 0x7F, 0x97, 0xF9, 0x7F, 0x97, 0xF9,
0x7F, 0x97, 0xFA, 0x7F, 0xA7, 0xFA, 0x7F, 0xA7, 0xFA, 0x7F, 0xA7, 0xFA, 0x7F, 0xA7, 0xFA, 0x7F, 0xB7, 0xFB, 0x7F, 0xB7, 0xFB, 0x7F, 0xB7, 0xFB,
0x7F, 0xB7, 0xFB, 0x7F, 0xB7, 0xFB, 0x7F, 0xC7, 0xFC, 0x7F, 0xC7, 0xFC, 0x7F, 0xC7, 0xFC, 0x7F, 0xC7, 0xFC, 0x7F, 0xC7, 0xFC, 0x7F, 0xC7, 0xFC,
0x7F, 0xD7, 0xFD, 0x7F, 0xD7, 0xFD, 0x7F, 0xD7, 0xFD, 0x7F, 0xD7, 0xFD, 0x7F, 0xD7, 0xFD, 0x7F, 0xD7, 0xFD, 0x7F, 0xD7, 0xFD, 0x7F, 0xD7, 0xFE,
0x7F, 0xE7, 0xFE, 0x7F, 0xE7, 0xFE, 0x7F, 0xE7, 0xFE, 0x7F, 0xE7, 0xFE, 0x7F, 0xE7, 0xFE, 0x7F, 0xE7, 0xFE, 0x7F, 0xE7, 0xFE, 0x7F, 0xE7, 0xFE,
0x7F, 0xE7, 0xFE, 0x7F, 0xE7, 0xFE, 0x7F, 0xF7, 0xFF, 0x7F, 0xF7, 0xFF, 0x7F, 0xF7, 0xFF, 0x7F, 0xF7, 0xFF, 0x7F, 0xF7, 0xFF, 0x7F, 0xF7, 0xFF,
0x7F, 0xF7, 0xFF, 0x7F, 0xF7, 0xFF, 0x7F, 0xF7, 0xFF, 0x7F, 0xF7, 0xFF, 0x7F, 0xF7, 0xFF, 0x7F, 0xF7, 0xFF, 0x7F, 0xF7, 0xFF, 0x7F, 0xF7, 0xFF,
};
#else
// range 2000
const uint8_t LUT_sine_8192_quad_packed[3072] = {
0x00, 0x00, 0x02, 0x00, 0x30, 0x05, 0x00, 0x60, 0x08, 0x00, 0x90, 0x0B, 0x00, 0xC0, 0x0E, 0x00, 0xF0, 0x11, 0x01, 0x20, 0x14, 0x01, 0x50, 0x17,
0x01, 0x90, 0x1A, 0x01, 0xC0, 0x1D, 0x01, 0xF0, 0x20, 0x02, 0x20, 0x23, 0x02, 0x50, 0x26, 0x02, 0x80, 0x29, 0x02, 0xB0, 0x2C, 0x02, 0xE0, 0x30,
0x03, 0x10, 0x33, 0x03, 0x40, 0x36, 0x03, 0x70, 0x39, 0x03, 0xA0, 0x3C, 0x03, 0xD0, 0x3F, 0x04, 0x00, 0x42, 0x04, 0x30, 0x45, 0x04, 0x70, 0x48,
0x04, 0xA0, 0x4B, 0x04, 0xD0, 0x4E, 0x05, 0x00, 0x51, 0x05, 0x30, 0x54, 0x05, 0x60, 0x57, 0x05, 0x90, 0x5A, 0x05, 0xC0, 0x5E, 0x05, 0xF0, 0x61,
0x06, 0x20, 0x64, 0x06, 0x50, 0x67, 0x06, 0x80, 0x6A, 0x06, 0xB0, 0x6D, 0x06, 0xE0, 0x70, 0x07, 0x10, 0x73, 0x07, 0x50, 0x76, 0x07, 0x80, 0x79,
0x07, 0xB0, 0x7C, 0x07, 0xE0, 0x7F, 0x08, 0x10, 0x82, 0x08, 0x40, 0x85, 0x08, 0x70, 0x88, 0x08, 0xA0, 0x8B, 0x08, 0xD0, 0x8F, 0x09, 0x00, 0x92,
0x09, 0x30, 0x95, 0x09, 0x60, 0x98, 0x09, 0x90, 0x9B, 0x09, 0xC0, 0x9E, 0x09, 0xF0, 0xA1, 0x0A, 0x20, 0xA4, 0x0A, 0x50, 0xA7, 0x0A, 0x90, 0xAA,
0x0A, 0xC0, 0xAD, 0x0A, 0xF0, 0xB0, 0x0B, 0x20, 0xB3, 0x0B, 0x50, 0xB6, 0x0B, 0x80, 0xB9, 0x0B, 0xB0, 0xBC, 0x0B, 0xE0, 0xBF, 0x0C, 0x10, 0xC3,
0x0C, 0x40, 0xC6, 0x0C, 0x70, 0xC9, 0x0C, 0xA0, 0xCC, 0x0C, 0xD0, 0xCF, 0x0D, 0x00, 0xD2, 0x0D, 0x30, 0xD5, 0x0D, 0x60, 0xD8, 0x0D, 0x90, 0xDB,
0x0D, 0xC0, 0xDE, 0x0D, 0xF0, 0xE1, 0x0E, 0x30, 0xE4, 0x0E, 0x60, 0xE7, 0x0E, 0x90, 0xEA, 0x0E, 0xC0, 0xED, 0x0E, 0xF0, 0xF0, 0x0F, 0x20, 0xF3,
0x0F, 0x50, 0xF6, 0x0F, 0x80, 0xF9, 0x0F, 0xB0, 0xFC, 0x0F, 0xE0, 0xFF, 0x10, 0x11, 0x03, 0x10, 0x41, 0x06, 0x10, 0x71, 0x09, 0x10, 0xA1, 0x0C,
0x10, 0xD1, 0x0F, 0x11, 0x01, 0x12, 0x11, 0x31, 0x15, 0x11, 0x61, 0x18, 0x11, 0x91, 0x1B, 0x11, 0xC1, 0x1E, 0x11, 0xF1, 0x21, 0x12, 0x21, 0x24,
0x12, 0x51, 0x27, 0x12, 0x81, 0x2A, 0x12, 0xC1, 0x2D, 0x12, 0xF1, 0x30, 0x13, 0x21, 0x33, 0x13, 0x51, 0x36, 0x13, 0x81, 0x39, 0x13, 0xB1, 0x3C,
0x13, 0xE1, 0x3F, 0x14, 0x11, 0x42, 0x14, 0x41, 0x45, 0x14, 0x71, 0x48, 0x14, 0xA1, 0x4B, 0x14, 0xD1, 0x4E, 0x15, 0x01, 0x51, 0x15, 0x31, 0x54,
0x15, 0x61, 0x57, 0x15, 0x91, 0x5A, 0x15, 0xC1, 0x5D, 0x15, 0xF1, 0x60, 0x16, 0x21, 0x64, 0x16, 0x51, 0x67, 0x16, 0x81, 0x6A, 0x16, 0xB1, 0x6D,
0x16, 0xE1, 0x70, 0x17, 0x11, 0x73, 0x17, 0x41, 0x76, 0x17, 0x71, 0x79, 0x17, 0xA1, 0x7C, 0x17, 0xD1, 0x7F, 0x18, 0x01, 0x82, 0x18, 0x31, 0x85,
0x18, 0x61, 0x88, 0x18, 0x91, 0x8B, 0x18, 0xC1, 0x8E, 0x18, 0xF1, 0x91, 0x19, 0x21, 0x94, 0x19, 0x51, 0x97, 0x19, 0x81, 0x9A, 0x19, 0xB1, 0x9D,
0x19, 0xE1, 0xA0, 0x1A, 0x11, 0xA3, 0x1A, 0x41, 0xA6, 0x1A, 0x71, 0xA9, 0x1A, 0xA1, 0xAC, 0x1A, 0xD1, 0xAF, 0x1B, 0x01, 0xB2, 0x1B, 0x31, 0xB5,
0x1B, 0x61, 0xB8, 0x1B, 0x91, 0xBB, 0x1B, 0xC1, 0xBE, 0x1B, 0xF1, 0xC1, 0x1C, 0x21, 0xC4, 0x1C, 0x51, 0xC7, 0x1C, 0x81, 0xCA, 0x1C, 0xB1, 0xCD,
0x1C, 0xE1, 0xD0, 0x1D, 0x11, 0xD3, 0x1D, 0x41, 0xD6, 0x1D, 0x71, 0xD9, 0x1D, 0xA1, 0xDC, 0x1D, 0xD1, 0xDF, 0x1E, 0x01, 0xE1, 0x1E, 0x31, 0xE4,
0x1E, 0x61, 0xE7, 0x1E, 0x91, 0xEA, 0x1E, 0xC1, 0xED, 0x1E, 0xF1, 0xF0, 0x1F, 0x21, 0xF3, 0x1F, 0x51, 0xF6, 0x1F, 0x81, 0xF9, 0x1F, 0xB1, 0xFC,
0x1F, 0xE1, 0xFF, 0x20, 0x12, 0x02, 0x20, 0x42, 0x05, 0x20, 0x72, 0x08, 0x20, 0xA2, 0x0B, 0x20, 0xD2, 0x0E, 0x21, 0x02, 0x11, 0x21, 0x22, 0x14,
0x21, 0x52, 0x17, 0x21, 0x82, 0x1A, 0x21, 0xB2, 0x1D, 0x21, 0xE2, 0x20, 0x22, 0x12, 0x23, 0x22, 0x42, 0x26, 0x22, 0x72, 0x29, 0x22, 0xA2, 0x2C,
0x22, 0xD2, 0x2F, 0x23, 0x02, 0x31, 0x23, 0x32, 0x34, 0x23, 0x62, 0x37, 0x23, 0x92, 0x3A, 0x23, 0xC2, 0x3D, 0x23, 0xF2, 0x40, 0x24, 0x22, 0x43,
0x24, 0x52, 0x46, 0x24, 0x82, 0x49, 0x24, 0xA2, 0x4C, 0x24, 0xD2, 0x4F, 0x25, 0x02, 0x52, 0x25, 0x32, 0x55, 0x25, 0x62, 0x58, 0x25, 0x92, 0x5B,
0x25, 0xC2, 0x5D, 0x25, 0xF2, 0x60, 0x26, 0x22, 0x63, 0x26, 0x52, 0x66, 0x26, 0x82, 0x69, 0x26, 0xB2, 0x6C, 0x26, 0xE2, 0x6F, 0x27, 0x02, 0x72,
0x27, 0x32, 0x75, 0x27, 0x62, 0x78, 0x27, 0x92, 0x7B, 0x27, 0xC2, 0x7E, 0x27, 0xF2, 0x80, 0x28, 0x22, 0x83, 0x28, 0x52, 0x86, 0x28, 0x82, 0x89,
0x28, 0xB2, 0x8C, 0x28, 0xE2, 0x8F, 0x29, 0x02, 0x92, 0x29, 0x32, 0x95, 0x29, 0x62, 0x98, 0x29, 0x92, 0x9B, 0x29, 0xC2, 0x9D, 0x29, 0xF2, 0xA0,
0x2A, 0x22, 0xA3, 0x2A, 0x52, 0xA6, 0x2A, 0x82, 0xA9, 0x2A, 0xA2, 0xAC, 0x2A, 0xD2, 0xAF, 0x2B, 0x02, 0xB2, 0x2B, 0x32, 0xB5, 0x2B, 0x62, 0xB7,
0x2B, 0x92, 0xBA, 0x2B, 0xC2, 0xBD, 0x2B, 0xF2, 0xC0, 0x2C, 0x12, 0xC3, 0x2C, 0x42, 0xC6, 0x2C, 0x72, 0xC9, 0x2C, 0xA2, 0xCB, 0x2C, 0xD2, 0xCE,
0x2D, 0x02, 0xD1, 0x2D, 0x32, 0xD4, 0x2D, 0x62, 0xD7, 0x2D, 0x82, 0xDA, 0x2D, 0xB2, 0xDD, 0x2D, 0xE2, 0xE0, 0x2E, 0x12, 0xE2, 0x2E, 0x42, 0xE5,
0x2E, 0x72, 0xE8, 0x2E, 0x92, 0xEB, 0x2E, 0xC2, 0xEE, 0x2E, 0xF2, 0xF1, 0x2F, 0x22, 0xF3, 0x2F, 0x52, 0xF6, 0x2F, 0x82, 0xF9, 0x2F, 0xB2, 0xFC,
0x2F, 0xD2, 0xFF, 0x30, 0x03, 0x02, 0x30, 0x33, 0x04, 0x30, 0x63, 0x07, 0x30, 0x93, 0x0A, 0x30, 0xC3, 0x0D, 0x30, 0xE3, 0x10, 0x31, 0x13, 0x13,
0x31, 0x43, 0x15, 0x31, 0x73, 0x18, 0x31, 0xA3, 0x1B, 0x31, 0xC3, 0x1E, 0x31, 0xF3, 0x21, 0x32, 0x23, 0x23, 0x32, 0x53, 0x26, 0x32, 0x83, 0x29,
0x32, 0xA3, 0x2C, 0x32, 0xD3, 0x2F, 0x33, 0x03, 0x31, 0x33, 0x33, 0x34, 0x33, 0x63, 0x37, 0x33, 0x83, 0x3A, 0x33, 0xB3, 0x3D, 0x33, 0xE3, 0x3F,
0x34, 0x13, 0x42, 0x34, 0x43, 0x45, 0x34, 0x63, 0x48, 0x34, 0x93, 0x4B, 0x34, 0xC3, 0x4D, 0x34, 0xF3, 0x50, 0x35, 0x23, 0x53, 0x35, 0x43, 0x56,
0x35, 0x73, 0x58, 0x35, 0xA3, 0x5B, 0x35, 0xD3, 0x5E, 0x35, 0xF3, 0x61, 0x36, 0x23, 0x64, 0x36, 0x53, 0x66, 0x36, 0x83, 0x69, 0x36, 0xA3, 0x6C,
0x36, 0xD3, 0x6F, 0x37, 0x03, 0x71, 0x37, 0x33, 0x74, 0x37, 0x53, 0x77, 0x37, 0x83, 0x7A, 0x37, 0xB3, 0x7C, 0x37, 0xE3, 0x7F, 0x38, 0x03, 0x82,
0x38, 0x33, 0x85, 0x38, 0x63, 0x87, 0x38, 0x93, 0x8A, 0x38, 0xB3, 0x8D, 0x38, 0xE3, 0x90, 0x39, 0x13, 0x92, 0x39, 0x43, 0x95, 0x39, 0x63, 0x98,
0x39, 0x93, 0x9A, 0x39, 0xC3, 0x9D, 0x39, 0xF3, 0xA0, 0x3A, 0x13, 0xA3, 0x3A, 0x43, 0xA5, 0x3A, 0x73, 0xA8, 0x3A, 0x93, 0xAB, 0x3A, 0xC3, 0xAD,
0x3A, 0xF3, 0xB0, 0x3B, 0x13, 0xB3, 0x3B, 0x43, 0xB6, 0x3B, 0x73, 0xB8, 0x3B, 0xA3, 0xBB, 0x3B, 0xC3, 0xBE, 0x3B, 0xF3, 0xC0, 0x3C, 0x23, 0xC3,
0x3C, 0x43, 0xC6, 0x3C, 0x73, 0xC8, 0x3C, 0xA3, 0xCB, 0x3C, 0xC3, 0xCE, 0x3C, 0xF3, 0xD0, 0x3D, 0x23, 0xD3, 0x3D, 0x43, 0xD6, 0x3D, 0x73, 0xD8,
0x3D, 0xA3, 0xDB, 0x3D, 0xC3, 0xDE, 0x3D, 0xF3, 0xE0, 0x3E, 0x23, 0xE3, 0x3E, 0x43, 0xE6, 0x3E, 0x73, 0xE8, 0x3E, 0xA3, 0xEB, 0x3E, 0xC3, 0xEE,
0x3E, 0xF3, 0xF0, 0x3F, 0x23, 0xF3, 0x3F, 0x43, 0xF6, 0x3F, 0x73, 0xF8, 0x3F, 0xA3, 0xFB, 0x3F, 0xC3, 0xFE, 0x3F, 0xF4, 0x00, 0x40, 0x24, 0x03,
0x40, 0x44, 0x06, 0x40, 0x74, 0x08, 0x40, 0x94, 0x0B, 0x40, 0xC4, 0x0D, 0x40, 0xF4, 0x10, 0x41, 0x14, 0x13, 0x41, 0x44, 0x15, 0x41, 0x74, 0x18,
0x41, 0x94, 0x1A, 0x41, 0xC4, 0x1D, 0x41, 0xE4, 0x20, 0x42, 0x14, 0x22, 0x42, 0x44, 0x25, 0x42, 0x64, 0x28, 0x42, 0x94, 0x2A, 0x42, 0xB4, 0x2D,
0x42, 0xE4, 0x2F, 0x43, 0x14, 0x32, 0x43, 0x34, 0x34, 0x43, 0x64, 0x37, 0x43, 0x84, 0x3A, 0x43, 0xB4, 0x3C, 0x43, 0xE4, 0x3F, 0x44, 0x04, 0x41,
0x44, 0x34, 0x44, 0x44, 0x54, 0x47, 0x44, 0x84, 0x49, 0x44, 0xA4, 0x4C, 0x44, 0xD4, 0x4E, 0x44, 0xF4, 0x51, 0x45, 0x24, 0x53, 0x45, 0x54, 0x56,
0x45, 0x74, 0x58, 0x45, 0xA4, 0x5B, 0x45, 0xC4, 0x5E, 0x45, 0xF4, 0x60, 0x46, 0x14, 0x63, 0x46, 0x44, 0x65, 0x46, 0x64, 0x68, 0x46, 0x94, 0x6A,
0x46, 0xB4, 0x6D, 0x46, 0xE4, 0x6F, 0x47, 0x14, 0x72, 0x47, 0x34, 0x74, 0x47, 0x64, 0x77, 0x47, 0x84, 0x79, 0x47, 0xB4, 0x7C, 0x47, 0xD4, 0x7E,
0x48, 0x04, 0x81, 0x48, 0x24, 0x83, 0x48, 0x54, 0x86, 0x48, 0x74, 0x88, 0x48, 0xA4, 0x8B, 0x48, 0xC4, 0x8D, 0x48, 0xF4, 0x90, 0x49, 0x14, 0x92,
0x49, 0x44, 0x95, 0x49, 0x64, 0x97, 0x49, 0x94, 0x9A, 0x49, 0xB4, 0x9C, 0x49, 0xE4, 0x9F, 0x4A, 0x04, 0xA1, 0x4A, 0x24, 0xA4, 0x4A, 0x54, 0xA6,
0x4A, 0x74, 0xA9, 0x4A, 0xA4, 0xAB, 0x4A, 0xC4, 0xAE, 0x4A, 0xF4, 0xB0, 0x4B, 0x14, 0xB2, 0x4B, 0x44, 0xB5, 0x4B, 0x64, 0xB7, 0x4B, 0x94, 0xBA,
0x4B, 0xB4, 0xBC, 0x4B, 0xD4, 0xBF, 0x4C, 0x04, 0xC1, 0x4C, 0x24, 0xC4, 0x4C, 0x54, 0xC6, 0x4C, 0x74, 0xC8, 0x4C, 0xA4, 0xCB, 0x4C, 0xC4, 0xCD,
0x4C, 0xE4, 0xD0, 0x4D, 0x14, 0xD2, 0x4D, 0x34, 0xD5, 0x4D, 0x64, 0xD7, 0x4D, 0x84, 0xD9, 0x4D, 0xB4, 0xDC, 0x4D, 0xD4, 0xDE, 0x4D, 0xF4, 0xE1,
0x4E, 0x24, 0xE3, 0x4E, 0x44, 0xE5, 0x4E, 0x74, 0xE8, 0x4E, 0x94, 0xEA, 0x4E, 0xB4, 0xEC, 0x4E, 0xE4, 0xEF, 0x4F, 0x04, 0xF1, 0x4F, 0x24, 0xF4,
0x4F, 0x54, 0xF6, 0x4F, 0x74, 0xF8, 0x4F, 0xA4, 0xFB, 0x4F, 0xC4, 0xFD, 0x4F, 0xE4, 0xFF, 0x50, 0x15, 0x02, 0x50, 0x35, 0x04, 0x50, 0x55, 0x06,
0x50, 0x85, 0x09, 0x50, 0xA5, 0x0B, 0x50, 0xC5, 0x0E, 0x50, 0xF5, 0x10, 0x51, 0x15, 0x12, 0x51, 0x35, 0x15, 0x51, 0x65, 0x17, 0x51, 0x85, 0x19,
0x51, 0xA5, 0x1C, 0x51, 0xD5, 0x1E, 0x51, 0xF5, 0x20, 0x52, 0x15, 0x22, 0x52, 0x45, 0x25, 0x52, 0x65, 0x27, 0x52, 0x85, 0x29, 0x52, 0xB5, 0x2C,
0x52, 0xD5, 0x2E, 0x52, 0xF5, 0x30, 0x53, 0x15, 0x33, 0x53, 0x45, 0x35, 0x53, 0x65, 0x37, 0x53, 0x85, 0x39, 0x53, 0xB5, 0x3C, 0x53, 0xD5, 0x3E,
0x53, 0xF5, 0x40, 0x54, 0x15, 0x43, 0x54, 0x45, 0x45, 0x54, 0x65, 0x47, 0x54, 0x85, 0x49, 0x54, 0xA5, 0x4C, 0x54, 0xD5, 0x4E, 0x54, 0xF5, 0x50,
0x55, 0x15, 0x52, 0x55, 0x35, 0x55, 0x55, 0x65, 0x57, 0x55, 0x85, 0x59, 0x55, 0xA5, 0x5B, 0x55, 0xC5, 0x5E, 0x55, 0xF5, 0x60, 0x56, 0x15, 0x62,
0x56, 0x35, 0x64, 0x56, 0x55, 0x66, 0x56, 0x85, 0x69, 0x56, 0xA5, 0x6B, 0x56, 0xC5, 0x6D, 0x56, 0xE5, 0x6F, 0x57, 0x05, 0x71, 0x57, 0x35, 0x74,
0x57, 0x55, 0x76, 0x57, 0x75, 0x78, 0x57, 0x95, 0x7A, 0x57, 0xB5, 0x7C, 0x57, 0xE5, 0x7F, 0x58, 0x05, 0x81, 0x58, 0x25, 0x83, 0x58, 0x45, 0x85,
0x58, 0x65, 0x87, 0x58, 0x85, 0x89, 0x58, 0xB5, 0x8C, 0x58, 0xD5, 0x8E, 0x58, 0xF5, 0x90, 0x59, 0x15, 0x92, 0x59, 0x35, 0x94, 0x59, 0x55, 0x96,
0x59, 0x75, 0x99, 0x59, 0xA5, 0x9B, 0x59, 0xC5, 0x9D, 0x59, 0xE5, 0x9F, 0x5A, 0x05, 0xA1, 0x5A, 0x25, 0xA3, 0x5A, 0x45, 0xA5, 0x5A, 0x65, 0xA7,
0x5A, 0x85, 0xAA, 0x5A, 0xB5, 0xAC, 0x5A, 0xD5, 0xAE, 0x5A, 0xF5, 0xB0, 0x5B, 0x15, 0xB2, 0x5B, 0x35, 0xB4, 0x5B, 0x55, 0xB6, 0x5B, 0x75, 0xB8,
0x5B, 0x95, 0xBA, 0x5B, 0xB5, 0xBC, 0x5B, 0xD5, 0xBF, 0x5C, 0x05, 0xC1, 0x5C, 0x25, 0xC3, 0x5C, 0x45, 0xC5, 0x5C, 0x65, 0xC7, 0x5C, 0x85, 0xC9,
0x5C, 0xA5, 0xCB, 0x5C, 0xC5, 0xCD, 0x5C, 0xE5, 0xCF, 0x5D, 0x05, 0xD1, 0x5D, 0x25, 0xD3, 0x5D, 0x45, 0xD5, 0x5D, 0x65, 0xD7, 0x5D, 0x85, 0xD9,
0x5D, 0xA5, 0xDB, 0x5D, 0xC5, 0xDD, 0x5D, 0xE5, 0xDF, 0x5E, 0x05, 0xE1, 0x5E, 0x25, 0xE3, 0x5E, 0x45, 0xE5, 0x5E, 0x65, 0xE7, 0x5E, 0x85, 0xE9,
0x5E, 0xA5, 0xEB, 0x5E, 0xC5, 0xED, 0x5E, 0xE5, 0xEF, 0x5F, 0x05, 0xF1, 0x5F, 0x25, 0xF3, 0x5F, 0x45, 0xF5, 0x5F, 0x65, 0xF7, 0x5F, 0x85, 0xF9,
0x5F, 0xA5, 0xFB, 0x5F, 0xC5, 0xFD, 0x5F, 0xE5, 0xFF, 0x60, 0x06, 0x01, 0x60, 0x26, 0x03, 0x60, 0x46, 0x05, 0x60, 0x66, 0x07, 0x60, 0x86, 0x09,
0x60, 0xA6, 0x0B, 0x60, 0xC6, 0x0D, 0x60, 0xE6, 0x0F, 0x61, 0x06, 0x11, 0x61, 0x26, 0x13, 0x61, 0x46, 0x15, 0x61, 0x66, 0x17, 0x61, 0x86, 0x19,
0x61, 0x96, 0x1A, 0x61, 0xB6, 0x1C, 0x61, 0xD6, 0x1E, 0x61, 0xF6, 0x20, 0x62, 0x16, 0x22, 0x62, 0x36, 0x24, 0x62, 0x56, 0x26, 0x62, 0x76, 0x28,
0x62, 0x96, 0x2A, 0x62, 0xB6, 0x2C, 0x62, 0xC6, 0x2D, 0x62, 0xE6, 0x2F, 0x63, 0x06, 0x31, 0x63, 0x26, 0x33, 0x63, 0x46, 0x35, 0x63, 0x66, 0x37,
0x63, 0x86, 0x39, 0x63, 0xA6, 0x3A, 0x63, 0xB6, 0x3C, 0x63, 0xD6, 0x3E, 0x63, 0xF6, 0x40, 0x64, 0x16, 0x42, 0x64, 0x36, 0x44, 0x64, 0x56, 0x46,
0x64, 0x66, 0x47, 0x64, 0x86, 0x49, 0x64, 0xA6, 0x4B, 0x64, 0xC6, 0x4D, 0x64, 0xE6, 0x4F, 0x65, 0x06, 0x50, 0x65, 0x16, 0x52, 0x65, 0x36, 0x54,
0x65, 0x56, 0x56, 0x65, 0x76, 0x58, 0x65, 0x96, 0x59, 0x65, 0xA6, 0x5B, 0x65, 0xC6, 0x5D, 0x65, 0xE6, 0x5F, 0x66, 0x06, 0x61, 0x66, 0x16, 0x62,
0x66, 0x36, 0x64, 0x66, 0x56, 0x66, 0x66, 0x76, 0x68, 0x66, 0x86, 0x69, 0x66, 0xA6, 0x6B, 0x66, 0xC6, 0x6D, 0x66, 0xE6, 0x6F, 0x66, 0xF6, 0x70,
0x67, 0x16, 0x72, 0x67, 0x36, 0x74, 0x67, 0x56, 0x76, 0x67, 0x66, 0x77, 0x67, 0x86, 0x79, 0x67, 0xA6, 0x7B, 0x67, 0xC6, 0x7C, 0x67, 0xD6, 0x7E,
0x67, 0xF6, 0x80, 0x68, 0x16, 0x81, 0x68, 0x26, 0x83, 0x68, 0x46, 0x85, 0x68, 0x66, 0x87, 0x68, 0x76, 0x88, 0x68, 0x96, 0x8A, 0x68, 0xB6, 0x8C,
0x68, 0xC6, 0x8D, 0x68, 0xE6, 0x8F, 0x69, 0x06, 0x91, 0x69, 0x16, 0x92, 0x69, 0x36, 0x94, 0x69, 0x56, 0x96, 0x69, 0x66, 0x97, 0x69, 0x86, 0x99,
0x69, 0xA6, 0x9B, 0x69, 0xB6, 0x9C, 0x69, 0xD6, 0x9E, 0x69, 0xF6, 0x9F, 0x6A, 0x06, 0xA1, 0x6A, 0x26, 0xA3, 0x6A, 0x36, 0xA4, 0x6A, 0x56, 0xA6,
0x6A, 0x76, 0xA8, 0x6A, 0x86, 0xA9, 0x6A, 0xA6, 0xAB, 0x6A, 0xC6, 0xAC, 0x6A, 0xD6, 0xAE, 0x6A, 0xF6, 0xB0, 0x6B, 0x06, 0xB1, 0x6B, 0x26, 0xB3,
0x6B, 0x36, 0xB4, 0x6B, 0x56, 0xB6, 0x6B, 0x76, 0xB7, 0x6B, 0x86, 0xB9, 0x6B, 0xA6, 0xBB, 0x6B, 0xB6, 0xBC, 0x6B, 0xD6, 0xBE, 0x6B, 0xE6, 0xBF,
0x6C, 0x06, 0xC1, 0x6C, 0x16, 0xC2, 0x6C, 0x36, 0xC4, 0x6C, 0x56, 0xC5, 0x6C, 0x66, 0xC7, 0x6C, 0x86, 0xC8, 0x6C, 0x96, 0xCA, 0x6C, 0xB6, 0xCB,
0x6C, 0xC6, 0xCD, 0x6C, 0xE6, 0xCE, 0x6C, 0xF6, 0xD0, 0x6D, 0x16, 0xD1, 0x6D, 0x26, 0xD3, 0x6D, 0x46, 0xD4, 0x6D, 0x56, 0xD6, 0x6D, 0x76, 0xD7,
0x6D, 0x86, 0xD9, 0x6D, 0xA6, 0xDA, 0x6D, 0xB6, 0xDC, 0x6D, 0xD6, 0xDD, 0x6D, 0xE6, 0xDF, 0x6D, 0xF6, 0xE0, 0x6E, 0x16, 0xE2, 0x6E, 0x26, 0xE3,
0x6E, 0x46, 0xE5, 0x6E, 0x56, 0xE6, 0x6E, 0x76, 0xE7, 0x6E, 0x86, 0xE9, 0x6E, 0xA6, 0xEA, 0x6E, 0xB6, 0xEC, 0x6E, 0xC6, 0xED, 0x6E, 0xE6, 0xEF,
0x6E, 0xF6, 0xF0, 0x6F, 0x16, 0xF1, 0x6F, 0x26, 0xF3, 0x6F, 0x36, 0xF4, 0x6F, 0x56, 0xF6, 0x6F, 0x66, 0xF7, 0x6F, 0x86, 0xF8, 0x6F, 0x96, 0xFA,
0x6F, 0xA6, 0xFB, 0x6F, 0xC6, 0xFD, 0x6F, 0xD6, 0xFE, 0x6F, 0xF6, 0xFF, 0x70, 0x07, 0x01, 0x70, 0x17, 0x02, 0x70, 0x37, 0x03, 0x70, 0x47, 0x05,
0x70, 0x57, 0x06, 0x70, 0x77, 0x07, 0x70, 0x87, 0x09, 0x70, 0x97, 0x0A, 0x70, 0xB7, 0x0B, 0x70, 0xC7, 0x0D, 0x70, 0xD7, 0x0E, 0x70, 0xF7, 0x0F,
0x71, 0x07, 0x11, 0x71, 0x17, 0x12, 0x71, 0x37, 0x13, 0x71, 0x47, 0x15, 0x71, 0x57, 0x16, 0x71, 0x67, 0x17, 0x71, 0x87, 0x18, 0x71, 0x97, 0x1A,
0x71, 0xA7, 0x1B, 0x71, 0xC7, 0x1C, 0x71, 0xD7, 0x1E, 0x71, 0xE7, 0x1F, 0x71, 0xF7, 0x20, 0x72, 0x17, 0x21, 0x72, 0x27, 0x23, 0x72, 0x37, 0x24,
0x72, 0x47, 0x25, 0x72, 0x67, 0x26, 0x72, 0x77, 0x28, 0x72, 0x87, 0x29, 0x72, 0x97, 0x2A, 0x72, 0xB7, 0x2B, 0x72, 0xC7, 0x2C, 0x72, 0xD7, 0x2E,
0x72, 0xE7, 0x2F, 0x72, 0xF7, 0x30, 0x73, 0x17, 0x31, 0x73, 0x27, 0x32, 0x73, 0x37, 0x34, 0x73, 0x47, 0x35, 0x73, 0x57, 0x36, 0x73, 0x77, 0x37,
0x73, 0x87, 0x38, 0x73, 0x97, 0x3A, 0x73, 0xA7, 0x3B, 0x73, 0xB7, 0x3C, 0x73, 0xC7, 0x3D, 0x73, 0xE7, 0x3E, 0x73, 0xF7, 0x3F, 0x74, 0x07, 0x40,
0x74, 0x17, 0x42, 0x74, 0x27, 0x43, 0x74, 0x37, 0x44, 0x74, 0x47, 0x45, 0x74, 0x67, 0x46, 0x74, 0x77, 0x47, 0x74, 0x87, 0x48, 0x74, 0x97, 0x49,
0x74, 0xA7, 0x4B, 0x74, 0xB7, 0x4C, 0x74, 0xC7, 0x4D, 0x74, 0xD7, 0x4E, 0x74, 0xE7, 0x4F, 0x74, 0xF7, 0x50, 0x75, 0x17, 0x51, 0x75, 0x27, 0x52,
0x75, 0x37, 0x53, 0x75, 0x47, 0x54, 0x75, 0x57, 0x55, 0x75, 0x67, 0x56, 0x75, 0x77, 0x57, 0x75, 0x87, 0x58, 0x75, 0x97, 0x5A, 0x75, 0xA7, 0x5B,
0x75, 0xB7, 0x5C, 0x75, 0xC7, 0x5D, 0x75, 0xD7, 0x5E, 0x75, 0xE7, 0x5F, 0x75, 0xF7, 0x60, 0x76, 0x07, 0x61, 0x76, 0x17, 0x62, 0x76, 0x27, 0x63,
0x76, 0x37, 0x64, 0x76, 0x47, 0x65, 0x76, 0x57, 0x66, 0x76, 0x67, 0x67, 0x76, 0x77, 0x68, 0x76, 0x87, 0x69, 0x76, 0x97, 0x6A, 0x76, 0xA7, 0x6B,
0x76, 0xB7, 0x6C, 0x76, 0xC7, 0x6C, 0x76, 0xD7, 0x6D, 0x76, 0xE7, 0x6E, 0x76, 0xF7, 0x6F, 0x77, 0x07, 0x70, 0x77, 0x17, 0x71, 0x77, 0x27, 0x72,
0x77, 0x37, 0x73, 0x77, 0x47, 0x74, 0x77, 0x47, 0x75, 0x77, 0x57, 0x76, 0x77, 0x67, 0x77, 0x77, 0x77, 0x78, 0x77, 0x87, 0x79, 0x77, 0x97, 0x79,
0x77, 0xA7, 0x7A, 0x77, 0xB7, 0x7B, 0x77, 0xC7, 0x7C, 0x77, 0xD7, 0x7D, 0x77, 0xD7, 0x7E, 0x77, 0xE7, 0x7F, 0x77, 0xF7, 0x80, 0x78, 0x07, 0x80,
0x78, 0x17, 0x81, 0x78, 0x27, 0x82, 0x78, 0x37, 0x83, 0x78, 0x37, 0x84, 0x78, 0x47, 0x85, 0x78, 0x57, 0x85, 0x78, 0x67, 0x86, 0x78, 0x77, 0x87,
0x78, 0x87, 0x88, 0x78, 0x87, 0x89, 0x78, 0x97, 0x8A, 0x78, 0xA7, 0x8A, 0x78, 0xB7, 0x8B, 0x78, 0xC7, 0x8C, 0x78, 0xC7, 0x8D, 0x78, 0xD7, 0x8E,
0x78, 0xE7, 0x8E, 0x78, 0xF7, 0x8F, 0x79, 0x07, 0x90, 0x79, 0x07, 0x91, 0x79, 0x17, 0x91, 0x79, 0x27, 0x92, 0x79, 0x37, 0x93, 0x79, 0x37, 0x94,
0x79, 0x47, 0x94, 0x79, 0x57, 0x95, 0x79, 0x67, 0x96, 0x79, 0x67, 0x97, 0x79, 0x77, 0x97, 0x79, 0x87, 0x98, 0x79, 0x87, 0x99, 0x79, 0x97, 0x9A,
0x79, 0xA7, 0x9A, 0x79, 0xB7, 0x9B, 0x79, 0xB7, 0x9C, 0x79, 0xC7, 0x9C, 0x79, 0xD7, 0x9D, 0x79, 0xD7, 0x9E, 0x79, 0xE7, 0x9E, 0x79, 0xF7, 0x9F,
0x79, 0xF7, 0xA0, 0x7A, 0x07, 0xA0, 0x7A, 0x17, 0xA1, 0x7A, 0x17, 0xA2, 0x7A, 0x27, 0xA2, 0x7A, 0x37, 0xA3, 0x7A, 0x37, 0xA4, 0x7A, 0x47, 0xA4,
0x7A, 0x57, 0xA5, 0x7A, 0x57, 0xA6, 0x7A, 0x67, 0xA6, 0x7A, 0x77, 0xA7, 0x7A, 0x77, 0xA7, 0x7A, 0x87, 0xA8, 0x7A, 0x87, 0xA9, 0x7A, 0x97, 0xA9,
0x7A, 0xA7, 0xAA, 0x7A, 0xA7, 0xAA, 0x7A, 0xB7, 0xAB, 0x7A, 0xB7, 0xAC, 0x7A, 0xC7, 0xAC, 0x7A, 0xD7, 0xAD, 0x7A, 0xD7, 0xAD, 0x7A, 0xE7, 0xAE,
0x7A, 0xE7, 0xAE, 0x7A, 0xF7, 0xAF, 0x7A, 0xF7, 0xB0, 0x7B, 0x07, 0xB0, 0x7B, 0x07, 0xB1, 0x7B, 0x17, 0xB1, 0x7B, 0x17, 0xB2, 0x7B, 0x27, 0xB2,
0x7B, 0x37, 0xB3, 0x7B, 0x37, 0xB3, 0x7B, 0x47, 0xB4, 0x7B, 0x47, 0xB4, 0x7B, 0x57, 0xB5, 0x7B, 0x57, 0xB5, 0x7B, 0x67, 0xB6, 0x7B, 0x67, 0xB6,
0x7B, 0x77, 0xB7, 0x7B, 0x77, 0xB7, 0x7B, 0x87, 0xB8, 0x7B, 0x87, 0xB8, 0x7B, 0x97, 0xB9, 0x7B, 0x97, 0xB9, 0x7B, 0x97, 0xBA, 0x7B, 0xA7, 0xBA,
0x7B, 0xA7, 0xBB, 0x7B, 0xB7, 0xBB, 0x7B, 0xB7, 0xBB, 0x7B, 0xC7, 0xBC, 0x7B, 0xC7, 0xBC, 0x7B, 0xD7, 0xBD, 0x7B, 0xD7, 0xBD, 0x7B, 0xD7, 0xBE,
0x7B, 0xE7, 0xBE, 0x7B, 0xE7, 0xBE, 0x7B, 0xF7, 0xBF, 0x7B, 0xF7, 0xBF, 0x7B, 0xF7, 0xC0, 0x7C, 0x07, 0xC0, 0x7C, 0x07, 0xC0, 0x7C, 0x17, 0xC1,
0x7C, 0x17, 0xC1, 0x7C, 0x17, 0xC2, 0x7C, 0x27, 0xC2, 0x7C, 0x27, 0xC2, 0x7C, 0x27, 0xC3, 0x7C, 0x37, 0xC3, 0x7C, 0x37, 0xC3, 0x7C, 0x37, 0xC4,
0x7C, 0x47, 0xC4, 0x7C, 0x47, 0xC4, 0x7C, 0x47, 0xC5, 0x7C, 0x57, 0xC5, 0x7C, 0x57, 0xC5, 0x7C, 0x57, 0xC6, 0x7C, 0x67, 0xC6, 0x7C, 0x67, 0xC6,
0x7C, 0x67, 0xC7, 0x7C, 0x77, 0xC7, 0x7C, 0x77, 0xC7, 0x7C, 0x77, 0xC7, 0x7C, 0x87, 0xC8, 0x7C, 0x87, 0xC8, 0x7C, 0x87, 0xC8, 0x7C, 0x87, 0xC8,
0x7C, 0x97, 0xC9, 0x7C, 0x97, 0xC9, 0x7C, 0x97, 0xC9, 0x7C, 0x97, 0xCA, 0x7C, 0xA7, 0xCA, 0x7C, 0xA7, 0xCA, 0x7C, 0xA7, 0xCA, 0x7C, 0xA7, 0xCA,
0x7C, 0xB7, 0xCB, 0x7C, 0xB7, 0xCB, 0x7C, 0xB7, 0xCB, 0x7C, 0xB7, 0xCB, 0x7C, 0xB7, 0xCC, 0x7C, 0xC7, 0xCC, 0x7C, 0xC7, 0xCC, 0x7C, 0xC7, 0xCC,
0x7C, 0xC7, 0xCC, 0x7C, 0xC7, 0xCD, 0x7C, 0xD7, 0xCD, 0x7C, 0xD7, 0xCD, 0x7C, 0xD7, 0xCD, 0x7C, 0xD7, 0xCD, 0x7C, 0xD7, 0xCD, 0x7C, 0xD7, 0xCE,
0x7C, 0xE7, 0xCE, 0x7C, 0xE7, 0xCE, 0x7C, 0xE7, 0xCE, 0x7C, 0xE7, 0xCE, 0x7C, 0xE7, 0xCE, 0x7C, 0xE7, 0xCE, 0x7C, 0xE7, 0xCE, 0x7C, 0xF7, 0xCF,
0x7C, 0xF7, 0xCF, 0x7C, 0xF7, 0xCF, 0x7C, 0xF7, 0xCF, 0x7C, 0xF7, 0xCF, 0x7C, 0xF7, 0xCF, 0x7C, 0xF7, 0xCF, 0x7C, 0xF7, 0xCF, 0x7C, 0xF7, 0xCF,
0x7C, 0xF7, 0xCF, 0x7C, 0xF7, 0xD0, 0x7D, 0x07, 0xD0, 0x7D, 0x07, 0xD0, 0x7D, 0x07, 0xD0, 0x7D, 0x07, 0xD0, 0x7D, 0x07, 0xD0, 0x7D, 0x07, 0xD0,
0x7D, 0x07, 0xD0, 0x7D, 0x07, 0xD0, 0x7D, 0x07, 0xD0, 0x7D, 0x07, 0xD0, 0x7D, 0x07, 0xD0, 0x7D, 0x07, 0xD0, 0x7D, 0x07, 0xD0, 0x7D, 0x07, 0xD0,
};
#endif
+147
View File
@@ -0,0 +1,147 @@
//
// Created by MightyPork on 2018/02/03.
//
#include "platform.h"
#include "unit_base.h"
#define DAC_INTERNAL
#include "_dac_internal.h"
/** Allocate data structure and set defaults */
error_t UDAC_preInit(Unit *unit)
{
struct priv *priv = unit->data = calloc_ck(1, sizeof(struct priv));
if (priv == NULL) return E_OUT_OF_MEM;
for (int i = 0; i < 2; i++) {
priv->cfg.ch[i].buffered = true;
priv->cfg.ch[i].enable = true;
priv->cfg.ch[i].noise_level = 2;
priv->cfg.ch[i].noise_type = NOISE_NONE;
priv->ch[i].waveform = UDAC_WAVE_DC;
priv->ch[i].dc_level = 2047;
priv->ch[i].rectangle_ontime = 4096; // half
priv->ch[i].rectangle_high = 4095;
priv->ch[i].rectangle_low = 0;
priv->ch[i].counter = 0;
priv->ch[i].increment = 0; // stopped
priv->ch[i].phase = 0;
}
UDAC_SetFreq(unit, 0, 1000);
UDAC_SetFreq(unit, 1, 1000);
return E_SUCCESS;
}
/** Finalize unit set-up */
error_t UDAC_init(Unit *unit)
{
bool suc = true;
struct priv *priv = unit->data;
// copy noise config
priv->ch[0].noise_type = priv->cfg.ch[0].noise_type;
priv->ch[0].noise_level = priv->cfg.ch[0].noise_level;
priv->ch[1].noise_type = priv->cfg.ch[1].noise_type;
priv->ch[1].noise_level = priv->cfg.ch[1].noise_level;
// this may change for different devices
const Resource r_ch1 = R_PA4;
const Resource r_ch2 = R_PA5;
TRY(rsc_claim(unit, R_TIM6));
priv->TIMx = TIM6;
const bool e1 = priv->cfg.ch[0].enable;
const bool e2 = priv->cfg.ch[1].enable;
if (e1) {
TRY(rsc_claim(unit, r_ch1));
}
if (e2) {
TRY(rsc_claim(unit, r_ch2));
}
TRY(rsc_claim(unit, R_DAC1));
// ensure the peripheral is clean (this may be redundant)
__HAL_RCC_DAC1_FORCE_RESET();
__HAL_RCC_DAC1_RELEASE_RESET();
hw_periph_clock_enable(DAC1);
hw_periph_clock_enable(priv->TIMx);
GPIO_TypeDef *port;
uint32_t ll;
if (e1) {
assert_param(hw_pinrsc2ll(r_ch1, &port, &ll));
LL_GPIO_SetPinMode(port, ll, LL_GPIO_MODE_ANALOG);
}
if (e2) {
assert_param(hw_pinrsc2ll(r_ch1, &port, &ll));
LL_GPIO_SetPinMode(port, ll, LL_GPIO_MODE_ANALOG);
}
uint16_t presc = 1;
// presets... TODO pick the highest useable one (or find a new one)
#if UDAC_TIM_FREQ_DIVIDER == 1
uint32_t count = PLAT_AHB_MHZ;
#elif UDAC_TIM_FREQ_DIVIDER == 2
uint32_t count = PLAT_AHB_MHZ * 2;
#elif UDAC_TIM_FREQ_DIVIDER == 4
uint32_t count = PLAT_AHB_MHZ * 4;
#elif UDAC_TIM_FREQ_DIVIDER == 8
uint32_t count = PLAT_AHB_MHZ * 8;
#else
#error "bad freq"
#endif
// dbg("Presc %d, count %d", (int)presc, (int)count);
LL_TIM_SetPrescaler(priv->TIMx, (uint32_t) (presc - 1));
LL_TIM_SetAutoReload(priv->TIMx, count - 1);
LL_TIM_EnableARRPreload(priv->TIMx);
LL_TIM_GenerateEvent_UPDATE(priv->TIMx);
irqd_attach(priv->TIMx, UDAC_HandleIT, unit);
LL_TIM_EnableIT_UPDATE(priv->TIMx);
UDAC_Reconfigure(unit); // works with the timer - it should be inited already
// do not enbale counter initially - no need
// LL_TIM_EnableCounter(priv->TIMx);
return E_SUCCESS;
}
/** Tear down the unit */
void UDAC_deInit(Unit *unit)
{
struct priv *priv = unit->data;
// de-init peripherals
if (unit->status == E_SUCCESS ) {
LL_DAC_DeInit(DAC);
LL_TIM_DisableCounter(priv->TIMx);
hw_periph_clock_disable(DAC1);
hw_periph_clock_disable(priv->TIMx);
irqd_detach(priv->TIMx, UDAC_HandleIT);
}
// Release all resources, deinit pins
rsc_teardown(unit);
// Free memory
free_ck(unit->data);
}
+111
View File
@@ -0,0 +1,111 @@
//
// Created by MightyPork on 2018/02/03.
//
#ifndef GEX_F072_DAC_INTERNAL_H
#define GEX_F072_DAC_INTERNAL_H
#ifndef DAC_INTERNAL
#error bad include!
#endif
#include "unit_base.h"
enum UDAC_Noise {
NOISE_NONE = 0b00, // 0
NOISE_WHITE = 0b01, // 1
NOISE_TRIANGLE = 0b10, // 2
};
enum UDAC_Waveform {
UDAC_WAVE_DC,
UDAC_WAVE_SINE,
UDAC_WAVE_TRIANGLE,
UDAC_WAVE_SAWTOOTH_UP,
UDAC_WAVE_SAWTOOTH_DOWN,
UDAC_WAVE_RECTANGLE,
};
struct udac_channel_cfg {
bool enable;
bool buffered;
enum UDAC_Noise noise_type;
uint8_t noise_level; // 0-11
};
// 0 - 1 MHz, 2-500k, 4-250k, 8-125k
#define UDAC_TIM_FREQ_DIVIDER 8
#define UDAC_INDEX_WIDTH 13 // corresponds to 8192 places
#define UDAC_INDEX_SHIFT (32 - UDAC_INDEX_WIDTH)
#define UDAC_MAX_INDEX ((1 << UDAC_INDEX_WIDTH) - 1)
#define UDAC_VALUE_COUNT (1 << UDAC_INDEX_WIDTH)
extern const uint8_t LUT_sine_8192_quad_packed[];
struct udac_channel_live {
enum UDAC_Noise noise_type;
uint8_t noise_level; // 0-11
enum UDAC_Waveform waveform;
uint16_t rectangle_ontime; // for rectangle wave, 0-8191
uint16_t rectangle_high;
uint16_t rectangle_low;
uint16_t dc_level; // for DC wave
uint32_t counter;
uint32_t increment;
// last set phase if the frequencies are the same
// - can be used for live frequency changes without reset (meaningful only with matching increment values)
uint16_t phase;
uint16_t last_index;
uint16_t last_value;
};
/** Private data structure */
struct priv {
// settings
struct {
struct udac_channel_cfg ch[2];
} cfg;
// internal state
struct udac_channel_live ch[2];
TIM_TypeDef *TIMx; // timer used for the DDS function
};
/** Allocate data structure and set defaults */
error_t UDAC_preInit(Unit *unit);
/** Load from a binary buffer stored in Flash */
void UDAC_loadBinary(Unit *unit, PayloadParser *pp);
/** Write to a binary buffer for storing in Flash */
void UDAC_writeBinary(Unit *unit, PayloadBuilder *pb);
// ------------------------------------------------------------------------
/** Parse a key-value pair from the INI file */
error_t UDAC_loadIni(Unit *unit, const char *key, const char *value);
/** Generate INI file section for the unit */
void UDAC_writeIni(Unit *unit, IniWriter *iw);
// ------------------------------------------------------------------------
/** Finalize unit set-up */
error_t UDAC_init(Unit *unit);
/** Tear down the unit */
void UDAC_deInit(Unit *unit);
void UDAC_Reconfigure(Unit *unit);
void UDAC_HandleIT(void *arg);
error_t UDAC_SetFreq(Unit *unit, int channel, float freq);
void UDAC_ToggleTimerIfNeeded(Unit *unit);
#endif //GEX_F072_DAC_INTERNAL_H
+131
View File
@@ -0,0 +1,131 @@
//
// Created by MightyPork on 2018/02/03.
//
#include "platform.h"
#include "unit_base.h"
#define DAC_INTERNAL
#include "_dac_internal.h"
/** Load from a binary buffer stored in Flash */
void UDAC_loadBinary(Unit *unit, PayloadParser *pp)
{
struct priv *priv = unit->data;
uint8_t version = pp_u8(pp);
(void)version;
priv->cfg.ch[0].enable = pp_bool(pp);
priv->cfg.ch[0].buffered = pp_bool(pp);
priv->cfg.ch[0].noise_type = (enum UDAC_Noise) pp_u8(pp);
priv->cfg.ch[0].noise_level = pp_u8(pp);
priv->cfg.ch[1].enable = pp_bool(pp);
priv->cfg.ch[1].buffered = pp_bool(pp);
priv->cfg.ch[1].noise_type = (enum UDAC_Noise) pp_u8(pp);
priv->cfg.ch[1].noise_level = pp_u8(pp);
}
/** Write to a binary buffer for storing in Flash */
void UDAC_writeBinary(Unit *unit, PayloadBuilder *pb)
{
struct priv *priv = unit->data;
pb_u8(pb, 0); // version
pb_bool(pb, priv->cfg.ch[0].enable);
pb_bool(pb, priv->cfg.ch[0].buffered);
pb_u8(pb, priv->cfg.ch[0].noise_type);
pb_u8(pb, priv->cfg.ch[0].noise_level);
pb_bool(pb, priv->cfg.ch[1].enable);
pb_bool(pb, priv->cfg.ch[1].buffered);
pb_u8(pb, priv->cfg.ch[1].noise_type);
pb_u8(pb, priv->cfg.ch[1].noise_level);
}
// ------------------------------------------------------------------------
/** Parse a key-value pair from the INI file */
error_t UDAC_loadIni(Unit *unit, const char *key, const char *value)
{
bool suc = true;
struct priv *priv = unit->data;
// Ch1
if (streq(key, "ch1_enable")) {
priv->cfg.ch[0].enable = cfg_bool_parse(value, &suc);
}
else if (streq(key, "ch1_buff")) {
priv->cfg.ch[0].buffered = cfg_bool_parse(value, &suc);
}
else if (streq(key, "ch1_noise")) {
priv->cfg.ch[0].noise_type =
(enum UDAC_Noise) cfg_enum3_parse(value,
"NONE", NOISE_NONE,
"WHITE", NOISE_WHITE,
"TRIANGLE", NOISE_TRIANGLE, &suc);
}
else if (streq(key, "ch1_noise-level")) {
uint8_t x = cfg_u8_parse(value, &suc);
if (x == 0) x = 1;
if (x > 12) x = 12;
priv->cfg.ch[0].noise_level = (uint8_t) (x - 1);
}
// Ch2
else if (streq(key, "ch2_enable")) {
priv->cfg.ch[1].enable = cfg_bool_parse(value, &suc);
}
else if (streq(key, "ch2_buff")) {
priv->cfg.ch[1].buffered = cfg_bool_parse(value, &suc);
}
else if (streq(key, "ch2_noise")) {
priv->cfg.ch[1].noise_type =
(enum UDAC_Noise) cfg_enum3_parse(value,
"NONE", NOISE_NONE,
"WHITE", NOISE_WHITE,
"TRIANGLE", NOISE_TRIANGLE, &suc);
}
else if (streq(key, "ch2_noise-level")) {
uint8_t x = cfg_u8_parse(value, &suc);
if (x == 0) x = 1;
if (x > 12) x = 12;
priv->cfg.ch[1].noise_level = (uint8_t) (x - 1);
}
// end
else {
return E_BAD_KEY;
}
if (!suc) return E_BAD_VALUE;
return E_SUCCESS;
}
/** Generate INI file section for the unit */
void UDAC_writeIni(Unit *unit, IniWriter *iw)
{
struct priv *priv = unit->data;
iw_comment(iw, "Enabled channels (1:A4, 2:A5)");
iw_entry_s(iw, "ch1_enable", str_yn(priv->cfg.ch[0].enable));
iw_entry_s(iw, "ch2_enable", str_yn(priv->cfg.ch[1].enable));
iw_comment(iw, "Enable output buffer");
iw_entry_s(iw, "ch1_buff", str_yn(priv->cfg.ch[0].buffered));
iw_entry_s(iw, "ch2_buff", str_yn(priv->cfg.ch[1].buffered));
iw_comment(iw, "Superimposed noise type (NONE,WHITE,TRIANGLE) and nbr. of bits (1-12)");
iw_entry_s(iw, "ch1_noise", cfg_enum3_encode(priv->cfg.ch[0].noise_type,
NOISE_NONE, "NONE",
NOISE_WHITE, "WHITE",
NOISE_TRIANGLE, "TRIANGLE"));
iw_entry_d(iw, "ch1_noise-level", priv->cfg.ch[0].noise_level + 1);
iw_entry_s(iw, "ch2_noise", cfg_enum3_encode(priv->cfg.ch[1].noise_type,
NOISE_NONE, "NONE",
NOISE_WHITE, "WHITE",
NOISE_TRIANGLE, "TRIANGLE"));
iw_entry_d(iw, "ch2_noise-level", priv->cfg.ch[1].noise_level + 1);
}
+166
View File
@@ -0,0 +1,166 @@
//
// Created by MightyPork on 2017/11/25.
//
#include "unit_base.h"
#include "unit_dac.h"
#define DAC_INTERNAL
#include "_dac_internal.h"
// ------------------------------------------------------------------------
// Works OK up to about 20 kHz, could work faster with a faster interrupt
// (may be possible with some optimizations / adjusting priorities...)
enum DacCmd_ {
CMD_WAVE_DC = 0,
CMD_WAVE_SINE = 1,
CMD_WAVE_TRIANGLE = 2,
CMD_WAVE_SAWTOOTH_UP = 3,
CMD_WAVE_SAWTOOTH_DOWN = 4,
CMD_WAVE_RECTANGLE = 5,
CMD_SYNC = 10,
CMD_SET_FREQUENCY = 20,
CMD_SET_PHASE = 21,
CMD_SET_DITHER = 22,
};
/** Handle a request message */
static error_t UDAC_handleRequest(Unit *unit, TF_ID frame_id, uint8_t command, PayloadParser *pp)
{
struct priv *priv = unit->data;
// Exceptions that aren't per-channel
switch (command) {
case CMD_SYNC:
dbg("Sync");
priv->ch[0].counter = priv->ch[0].phase << UDAC_INDEX_SHIFT;
priv->ch[1].counter = priv->ch[1].phase << UDAC_INDEX_SHIFT;
return E_SUCCESS;
}
uint8_t channels = pp_u8(pp);
bool want_reinit = false;
bool want_tog_timer = false;
// TODO move this stuff to the api file
for (int i = 0; i < 2; i++) {
if (channels & (1<<i)) {
switch (command) {
case CMD_SET_FREQUENCY:;
float freq = pp_float(pp);
TRY(UDAC_SetFreq(unit, i, freq));
break;
case CMD_WAVE_DC:
priv->ch[i].dc_level = pp_u16(pp);
priv->ch[i].waveform = UDAC_WAVE_DC;
want_tog_timer = true;
break;
case CMD_WAVE_SINE:
priv->ch[i].waveform = UDAC_WAVE_SINE;
want_tog_timer = true;
break;
case CMD_WAVE_TRIANGLE:
priv->ch[i].waveform = UDAC_WAVE_TRIANGLE;
want_tog_timer = true;
break;
case CMD_WAVE_SAWTOOTH_UP:
priv->ch[i].waveform = UDAC_WAVE_SAWTOOTH_UP;
want_tog_timer = true;
break;
case CMD_WAVE_SAWTOOTH_DOWN:
priv->ch[i].waveform = UDAC_WAVE_SAWTOOTH_DOWN;
want_tog_timer = true;
break;
case CMD_WAVE_RECTANGLE:;
uint16_t ontime = pp_u16(pp);
uint16_t high = pp_u16(pp);
uint16_t low = pp_u16(pp);
// use 0xFFFF to skip setting the value
if (high < 4096) priv->ch[i].rectangle_high = high;
if (low < 4096) priv->ch[i].rectangle_low = low;
if (ontime <= UDAC_VALUE_COUNT) priv->ch[i].rectangle_ontime = ontime;
// dbg("Set rect hi %d, low %d", (int)priv->ch[i].rectangle_high, (int)priv->ch[i].rectangle_low);
priv->ch[i].waveform = UDAC_WAVE_RECTANGLE;
want_tog_timer = true;
break;
case CMD_SET_PHASE:;
uint16_t ph = pp_u16(pp);
uint32_t newphase = ph << UDAC_INDEX_SHIFT;
uint32_t oldphase = priv->ch[i].phase << UDAC_INDEX_SHIFT;
int32_t diff = newphase - oldphase;
priv->ch[i].counter += diff;
priv->ch[i].phase = ph;
break;
case CMD_SET_DITHER:;
uint8_t noisetype = pp_u8(pp); // 0-none, 1-random, 2-triangle
uint8_t noisebits = pp_u8(pp);
// type 0xFF = not set
if (noisetype <= 2) {
priv->ch[i].noise_type = (enum UDAC_Noise) noisetype;
}
// bits 0xFF = not set
if (noisebits >= 1 && noisebits <= 12) {
priv->ch[i].noise_level = (uint8_t) (noisebits - 1);
}
// dbg("Ch %d: Dither type %d, level %d", i,
// (int)priv->ch[i].noise_type,
// (int)priv->ch[i].noise_level);
want_reinit = true;
break;
default:
return E_UNKNOWN_COMMAND;
}
}
}
if (want_reinit) {
UDAC_Reconfigure(unit);
}
if (want_tog_timer) {
UDAC_ToggleTimerIfNeeded(unit);
}
return E_SUCCESS;
}
// ------------------------------------------------------------------------
/** Unit template */
const UnitDriver UNIT_DAC = {
.name = "DAC",
.description = "Two-channel analog output with waveforms",
// Settings
.preInit = UDAC_preInit,
.cfgLoadBinary = UDAC_loadBinary,
.cfgWriteBinary = UDAC_writeBinary,
.cfgLoadIni = UDAC_loadIni,
.cfgWriteIni = UDAC_writeIni,
// Init
.init = UDAC_init,
.deInit = UDAC_deInit,
// Function
.handleRequest = UDAC_handleRequest,
};
+16
View File
@@ -0,0 +1,16 @@
//
// Created by MightyPork on 2017/11/25.
//
// Digital input unit; single or multiple pin read access on one port (A-F)
//
#ifndef U_DAC_H
#define U_DAC_H
#include "unit.h"
extern const UnitDriver UNIT_DAC;
// UU_ prototypes
#endif //U_DAC_H
+16 -21
View File
@@ -20,23 +20,18 @@ void DIn_loadBinary(Unit *unit, PayloadParser *pp)
priv->pins = pp_u16(pp); priv->pins = pp_u16(pp);
priv->pulldown = pp_u16(pp); priv->pulldown = pp_u16(pp);
priv->pullup = pp_u16(pp); priv->pullup = pp_u16(pp);
if (version >= 1) {
priv->trig_rise = pp_u16(pp); priv->trig_rise = pp_u16(pp);
priv->trig_fall = pp_u16(pp); priv->trig_fall = pp_u16(pp);
priv->trig_holdoff = pp_u16(pp); priv->trig_holdoff = pp_u16(pp);
}
if (version >= 2) {
priv->def_auto = pp_u16(pp); priv->def_auto = pp_u16(pp);
} }
}
/** Write to a binary buffer for storing in Flash */ /** Write to a binary buffer for storing in Flash */
void DIn_writeBinary(Unit *unit, PayloadBuilder *pb) void DIn_writeBinary(Unit *unit, PayloadBuilder *pb)
{ {
struct priv *priv = unit->data; struct priv *priv = unit->data;
pb_u8(pb, 2); // version pb_u8(pb, 0); // version
pb_char(pb, priv->port_name); pb_char(pb, priv->port_name);
pb_u16(pb, priv->pins); pb_u16(pb, priv->pins);
@@ -57,28 +52,28 @@ error_t DIn_loadIni(Unit *unit, const char *key, const char *value)
struct priv *priv = unit->data; struct priv *priv = unit->data;
if (streq(key, "port")) { if (streq(key, "port")) {
suc = parse_port_name(value, &priv->port_name); suc = cfg_port_parse(value, &priv->port_name);
} }
else if (streq(key, "pins")) { else if (streq(key, "pins")) {
priv->pins = parse_pinmask(value, &suc); priv->pins = cfg_pinmask_parse(value, &suc);
} }
else if (streq(key, "pull-up")) { else if (streq(key, "pull-up")) {
priv->pullup = parse_pinmask(value, &suc); priv->pullup = cfg_pinmask_parse(value, &suc);
} }
else if (streq(key, "pull-down")) { else if (streq(key, "pull-down")) {
priv->pulldown = parse_pinmask(value, &suc); priv->pulldown = cfg_pinmask_parse(value, &suc);
} }
else if (streq(key, "trig-rise")) { else if (streq(key, "trig-rise")) {
priv->trig_rise = parse_pinmask(value, &suc); priv->trig_rise = cfg_pinmask_parse(value, &suc);
} }
else if (streq(key, "trig-fall")) { else if (streq(key, "trig-fall")) {
priv->trig_fall = parse_pinmask(value, &suc); priv->trig_fall = cfg_pinmask_parse(value, &suc);
} }
else if (streq(key, "auto-trigger")) { else if (streq(key, "auto-trigger")) {
priv->def_auto = parse_pinmask(value, &suc); priv->def_auto = cfg_pinmask_parse(value, &suc);
} }
else if (streq(key, "hold-off")) { else if (streq(key, "hold-off")) {
priv->trig_holdoff = (uint16_t) avr_atoi(value); priv->trig_holdoff = cfg_u16_parse(value, &suc);
} }
else { else {
return E_BAD_KEY; return E_BAD_KEY;
@@ -97,24 +92,24 @@ void DIn_writeIni(Unit *unit, IniWriter *iw)
iw_entry(iw, "port", "%c", priv->port_name); iw_entry(iw, "port", "%c", priv->port_name);
iw_comment(iw, "Pins (comma separated, supports ranges)"); iw_comment(iw, "Pins (comma separated, supports ranges)");
iw_entry(iw, "pins", "%s", pinmask2str(priv->pins, unit_tmp512)); iw_entry_s(iw, "pins", cfg_pinmask_encode(priv->pins, unit_tmp512, 0));
iw_comment(iw, "Pins with pull-up"); iw_comment(iw, "Pins with pull-up");
iw_entry(iw, "pull-up", "%s", pinmask2str(priv->pullup, unit_tmp512)); iw_entry_s(iw, "pull-up", cfg_pinmask_encode(priv->pullup, unit_tmp512, 0));
iw_comment(iw, "Pins with pull-down"); iw_comment(iw, "Pins with pull-down");
iw_entry(iw, "pull-down", "%s", pinmask2str(priv->pulldown, unit_tmp512)); iw_entry_s(iw, "pull-down", cfg_pinmask_encode(priv->pulldown, unit_tmp512, 0));
iw_cmt_newline(iw); iw_cmt_newline(iw);
iw_comment(iw, "Trigger pins activated by rising/falling edge"); iw_comment(iw, "Trigger pins activated by rising/falling edge");
iw_entry(iw, "trig-rise", "%s", pinmask2str(priv->trig_rise, unit_tmp512)); iw_entry_s(iw, "trig-rise", cfg_pinmask_encode(priv->trig_rise, unit_tmp512, 0));
iw_entry(iw, "trig-fall", "%s", pinmask2str(priv->trig_fall, unit_tmp512)); iw_entry_s(iw, "trig-fall", cfg_pinmask_encode(priv->trig_fall, unit_tmp512, 0));
iw_comment(iw, "Trigger pins auto-armed by default"); iw_comment(iw, "Trigger pins auto-armed by default");
iw_entry(iw, "auto-trigger", "%s", pinmask2str(priv->def_auto, unit_tmp512)); iw_entry_s(iw, "auto-trigger", cfg_pinmask_encode(priv->def_auto, unit_tmp512, 0));
iw_comment(iw, "Triggers hold-off time (ms)"); iw_comment(iw, "Triggers hold-off time (ms)");
iw_entry(iw, "hold-off", "%d", (int)priv->trig_holdoff); iw_entry_d(iw, "hold-off", priv->trig_holdoff);
#if PLAT_NO_FLOATING_INPUTS #if PLAT_NO_FLOATING_INPUTS
iw_comment(iw, "NOTE: Pins use pull-up by default.\r\n"); iw_comment(iw, "NOTE: Pins use pull-up by default.\r\n");
+100
View File
@@ -7,8 +7,20 @@
#include "unit_dout.h" #include "unit_dout.h"
#define DOUT_INTERNAL #define DOUT_INTERNAL
#include "_dout_internal.h" #include "_dout_internal.h"
static void clear_pulse_by_mask(struct priv *priv, uint16_t spread)
{
assert_param(priv);
for (int i = 0; i < 16; i++) {
if (spread & (1 << i)) {
priv->msec_pulse_cnt[i] = 0;
}
}
}
error_t UU_DOut_Write(Unit *unit, uint16_t packed) error_t UU_DOut_Write(Unit *unit, uint16_t packed)
{ {
CHECK_TYPE(unit, &UNIT_DOUT); CHECK_TYPE(unit, &UNIT_DOUT);
@@ -16,6 +28,7 @@ error_t UU_DOut_Write(Unit *unit, uint16_t packed)
struct priv *priv = unit->data; struct priv *priv = unit->data;
uint16_t mask = priv->pins; uint16_t mask = priv->pins;
uint16_t spread = pinmask_spread(packed, mask); uint16_t spread = pinmask_spread(packed, mask);
clear_pulse_by_mask(priv, spread);
uint16_t set = spread; uint16_t set = spread;
uint16_t reset = ((~spread) & mask); uint16_t reset = ((~spread) & mask);
@@ -30,6 +43,7 @@ error_t UU_DOut_Set(Unit *unit, uint16_t packed)
struct priv *priv = unit->data; struct priv *priv = unit->data;
uint16_t mask = priv->pins; uint16_t mask = priv->pins;
uint16_t spread = pinmask_spread(packed, mask); uint16_t spread = pinmask_spread(packed, mask);
clear_pulse_by_mask(priv, spread);
priv->port->BSRR = spread; priv->port->BSRR = spread;
return E_SUCCESS; return E_SUCCESS;
@@ -42,6 +56,7 @@ error_t UU_DOut_Clear(Unit *unit, uint16_t packed)
struct priv *priv = unit->data; struct priv *priv = unit->data;
uint16_t mask = priv->pins; uint16_t mask = priv->pins;
uint16_t spread = pinmask_spread(packed, mask); uint16_t spread = pinmask_spread(packed, mask);
clear_pulse_by_mask(priv, spread);
priv->port->BSRR = (spread << 16); priv->port->BSRR = (spread << 16);
return E_SUCCESS; return E_SUCCESS;
@@ -54,6 +69,7 @@ error_t UU_DOut_Toggle(Unit *unit, uint16_t packed)
struct priv *priv = unit->data; struct priv *priv = unit->data;
uint16_t mask = priv->pins; uint16_t mask = priv->pins;
uint16_t spread = pinmask_spread(packed, mask); uint16_t spread = pinmask_spread(packed, mask);
clear_pulse_by_mask(priv, spread);
uint16_t flipped = (uint16_t) (~priv->port->ODR) & mask; uint16_t flipped = (uint16_t) (~priv->port->ODR) & mask;
uint16_t set = flipped & spread; uint16_t set = flipped & spread;
@@ -71,3 +87,87 @@ error_t UU_DOut_GetPinCount(Unit *unit, uint8_t *count)
*count = (uint8_t) (32 - __CLZ(packed)); *count = (uint8_t) (32 - __CLZ(packed));
return E_SUCCESS; return E_SUCCESS;
} }
error_t UU_DOut_Pulse(Unit *unit, uint16_t packed, bool polarity, bool is_usec, uint16_t count)
{
CHECK_TYPE(unit, &UNIT_DOUT);
struct priv *priv = unit->data;
assert_param(priv);
uint16_t mask = priv->pins;
uint16_t spread = pinmask_spread(packed, mask);
clear_pulse_by_mask(priv, spread);
vPortEnterCritical();
if (is_usec) {
// we're gonna do this right here as a delay loop.
if (count >= 1000) {
// too long, fall back to msec
count /= 1000;
is_usec = false;
}
else {
const uint32_t bsrr1 = spread << (polarity ? 0 : 16);
const uint32_t bsrr0 = spread << (polarity ? 16 : 0);
const uint32_t start = PTIM_MicroDelayAlign();
priv->port->BSRR = bsrr1;
PTIM_MicroDelayAligned(count, start);
priv->port->BSRR = bsrr0;
}
}
if (!is_usec) {
// Load the counters
for (int i = 0; i < 16; i++) {
if (spread & (1 << i)) {
priv->msec_pulse_cnt[i] = (uint16_t) (count + 1);
}
}
if (polarity) {
priv->msec_pulse_scheduled_1 |= spread;
} else {
priv->msec_pulse_scheduled_0 |= spread;
}
unit->_tick_cnt = 0;
unit->tick_interval = 1;
}
vPortExitCritical();
return E_SUCCESS;
}
void DOut_Tick(Unit *unit)
{
struct priv *priv = unit->data;
uint16_t odr = (uint16_t) priv->port->ODR;
int live_cnt = 0;
for (int i = 0; i < 16; i++) {
if (priv->msec_pulse_scheduled_1 & (1<<i)) {
odr |= (1<<i);
} else if (priv->msec_pulse_scheduled_0 & (1<<i)) {
odr &= ~(1<<i);
}
if (priv->msec_pulse_cnt[i] > 0) {
live_cnt++;
priv->msec_pulse_cnt[i]--;
if (priv->msec_pulse_cnt[i] == 0) {
odr ^= 1 << i;
}
}
}
priv->port->ODR = odr;
priv->msec_pulse_scheduled_1 = 0;
priv->msec_pulse_scheduled_0 = 0;
if (live_cnt == 0) {
unit->_tick_cnt = 0;
unit->tick_interval = 0;
}
}
+5
View File
@@ -19,6 +19,9 @@ struct priv {
uint16_t open_drain; // open drain pins uint16_t open_drain; // open drain pins
GPIO_TypeDef *port; GPIO_TypeDef *port;
uint16_t msec_pulse_cnt[16];
uint16_t msec_pulse_scheduled_1;
uint16_t msec_pulse_scheduled_0;
}; };
/** Allocate data structure and set defaults */ /** Allocate data structure and set defaults */
@@ -46,4 +49,6 @@ error_t DOut_init(Unit *unit);
/** Tear down the unit */ /** Tear down the unit */
void DOut_deInit(Unit *unit); void DOut_deInit(Unit *unit);
void DOut_Tick(Unit *unit);
#endif //GEX_F072_DOUT_INTERNAL_H #endif //GEX_F072_DOUT_INTERNAL_H
+7 -7
View File
@@ -44,16 +44,16 @@ error_t DOut_loadIni(Unit *unit, const char *key, const char *value)
struct priv *priv = unit->data; struct priv *priv = unit->data;
if (streq(key, "port")) { if (streq(key, "port")) {
suc = parse_port_name(value, &priv->port_name); suc = cfg_port_parse(value, &priv->port_name);
} }
else if (streq(key, "pins")) { else if (streq(key, "pins")) {
priv->pins = (uint16_t) parse_pinmask(value, &suc); priv->pins = cfg_pinmask_parse(value, &suc);
} }
else if (streq(key, "initial")) { else if (streq(key, "initial")) {
priv->initial = (uint16_t) parse_pinmask(value, &suc); priv->initial = cfg_pinmask_parse(value, &suc);
} }
else if (streq(key, "open-drain")) { else if (streq(key, "open-drain")) {
priv->open_drain = (uint16_t) parse_pinmask(value, &suc); priv->open_drain = cfg_pinmask_parse(value, &suc);
} }
else { else {
return E_BAD_KEY; return E_BAD_KEY;
@@ -72,11 +72,11 @@ void DOut_writeIni(Unit *unit, IniWriter *iw)
iw_entry(iw, "port", "%c", priv->port_name); iw_entry(iw, "port", "%c", priv->port_name);
iw_comment(iw, "Pins (comma separated, supports ranges)"); iw_comment(iw, "Pins (comma separated, supports ranges)");
iw_entry(iw, "pins", "%s", pinmask2str(priv->pins, unit_tmp512)); iw_entry_s(iw, "pins", cfg_pinmask_encode(priv->pins, unit_tmp512, 0));
iw_comment(iw, "Initially high pins"); iw_comment(iw, "Initially high pins");
iw_entry(iw, "initial", "%s", pinmask2str(priv->initial, unit_tmp512)); iw_entry_s(iw, "initial", cfg_pinmask_encode(priv->initial, unit_tmp512, 0));
iw_comment(iw, "Open-drain pins"); iw_comment(iw, "Open-drain pins");
iw_entry(iw, "open-drain", "%s", pinmask2str(priv->open_drain, unit_tmp512)); iw_entry_s(iw, "open-drain", cfg_pinmask_encode(priv->open_drain, unit_tmp512, 0));
} }
+10 -2
View File
@@ -9,10 +9,11 @@
#include "_dout_internal.h" #include "_dout_internal.h"
enum PinCmd_ { enum PinCmd_ {
CMD_TEST = 0, CMD_QUERY = 0,
CMD_SET = 1, CMD_SET = 1,
CMD_CLEAR = 2, CMD_CLEAR = 2,
CMD_TOGGLE = 3, CMD_TOGGLE = 3,
CMD_PULSE = 4,
}; };
/** Handle a request message */ /** Handle a request message */
@@ -21,7 +22,7 @@ static error_t DOut_handleRequest(Unit *unit, TF_ID frame_id, uint8_t command, P
uint16_t packed = pp_u16(pp); uint16_t packed = pp_u16(pp);
switch (command) { switch (command) {
case CMD_TEST: case CMD_QUERY:
return UU_DOut_Write(unit, packed); return UU_DOut_Write(unit, packed);
case CMD_SET: case CMD_SET:
@@ -33,6 +34,12 @@ static error_t DOut_handleRequest(Unit *unit, TF_ID frame_id, uint8_t command, P
case CMD_TOGGLE: case CMD_TOGGLE:
return UU_DOut_Toggle(unit, packed); return UU_DOut_Toggle(unit, packed);
case CMD_PULSE:;
bool polarity = pp_bool(pp);
bool is_usec = pp_bool(pp);
uint16_t count = pp_u16(pp);
return UU_DOut_Pulse(unit, packed, polarity, is_usec, count);
default: default:
return E_UNKNOWN_COMMAND; return E_UNKNOWN_COMMAND;
} }
@@ -55,4 +62,5 @@ const UnitDriver UNIT_DOUT = {
.deInit = DOut_deInit, .deInit = DOut_deInit,
// Function // Function
.handleRequest = DOut_handleRequest, .handleRequest = DOut_handleRequest,
.updateTick = DOut_Tick,
}; };
+12
View File
@@ -56,4 +56,16 @@ error_t UU_DOut_Toggle(Unit *unit, uint16_t packed);
*/ */
error_t UU_DOut_GetPinCount(Unit *unit, uint8_t *count); error_t UU_DOut_GetPinCount(Unit *unit, uint8_t *count);
/**
* Send a pulse
*
* @param unit
* @param packed - pins to pulse
* @param polarity - pulse active level
* @param is_usec - use usec precision (for < 1 ms)
* @param count - number of units (msec or usec)
* @return success
*/
error_t UU_DOut_Pulse(Unit *unit, uint16_t packed, bool polarity, bool is_usec, uint16_t count);
#endif //U_DOUT_H #endif //U_DOUT_H
-1
View File
@@ -2,7 +2,6 @@
// Created by MightyPork on 2018/02/20. // Created by MightyPork on 2018/02/20.
// //
#include <stm32f072xb.h>
#include "platform.h" #include "platform.h"
#define FCAP_INTERNAL #define FCAP_INTERNAL
+12 -17
View File
@@ -18,27 +18,22 @@ void UFCAP_loadBinary(Unit *unit, PayloadParser *pp)
priv->conf.signal_pname = pp_char(pp); priv->conf.signal_pname = pp_char(pp);
priv->conf.signal_pnum = pp_u8(pp); priv->conf.signal_pnum = pp_u8(pp);
if (version >= 1) {
priv->conf.active_level = pp_bool(pp); priv->conf.active_level = pp_bool(pp);
priv->conf.dfilter = pp_u8(pp); priv->conf.dfilter = pp_u8(pp);
priv->conf.direct_presc = pp_u8(pp); priv->conf.direct_presc = pp_u8(pp);
priv->conf.direct_msec = pp_u16(pp); priv->conf.direct_msec = pp_u16(pp);
priv->conf.startmode = (enum fcap_opmode) pp_u8(pp); priv->conf.startmode = (enum fcap_opmode) pp_u8(pp);
} }
}
/** Write to a binary buffer for storing in Flash */ /** Write to a binary buffer for storing in Flash */
void UFCAP_writeBinary(Unit *unit, PayloadBuilder *pb) void UFCAP_writeBinary(Unit *unit, PayloadBuilder *pb)
{ {
struct priv *priv = unit->data; struct priv *priv = unit->data;
pb_u8(pb, 1); // version pb_u8(pb, 0); // version
pb_char(pb, priv->conf.signal_pname); pb_char(pb, priv->conf.signal_pname);
pb_u8(pb, priv->conf.signal_pnum); pb_u8(pb, priv->conf.signal_pnum);
// V1
pb_bool(pb, priv->conf.active_level); pb_bool(pb, priv->conf.active_level);
pb_u8(pb, priv->conf.dfilter); pb_u8(pb, priv->conf.dfilter);
pb_u8(pb, priv->conf.direct_presc); pb_u8(pb, priv->conf.direct_presc);
@@ -55,22 +50,22 @@ error_t UFCAP_loadIni(Unit *unit, const char *key, const char *value)
struct priv *priv = unit->data; struct priv *priv = unit->data;
if (streq(key, "pin")) { if (streq(key, "pin")) {
suc = parse_pin(value, &priv->conf.signal_pname, &priv->conf.signal_pnum); suc = cfg_portpin_parse(value, &priv->conf.signal_pname, &priv->conf.signal_pnum);
} }
else if (streq(key, "active-level")) { else if (streq(key, "active-level")) {
priv->conf.active_level = (bool) avr_atoi(value); priv->conf.active_level = cfg_bool_parse(value, &suc);
} }
else if (streq(key, "input-filter")) { else if (streq(key, "input-filter")) {
priv->conf.dfilter = (uint8_t) avr_atoi(value); priv->conf.dfilter = cfg_u8_parse(value, &suc);
} }
else if (streq(key, "direct-presc")) { else if (streq(key, "direct-presc")) {
priv->conf.direct_presc = (uint8_t) avr_atoi(value); priv->conf.direct_presc = cfg_u8_parse(value, &suc);
} }
else if (streq(key, "direct-time")) { else if (streq(key, "direct-time")) {
priv->conf.direct_msec = (uint16_t) avr_atoi(value); priv->conf.direct_msec = cfg_u16_parse(value, &suc);
} }
else if (streq(key, "initial-mode")) { else if (streq(key, "initial-mode")) {
priv->conf.startmode = (enum fcap_opmode) str_parse_4(value, priv->conf.startmode = (enum fcap_opmode) cfg_enum4_parse(value,
"N", OPMODE_IDLE, "N", OPMODE_IDLE,
"I", OPMODE_INDIRECT_CONT, "I", OPMODE_INDIRECT_CONT,
"D", OPMODE_DIRECT_CONT, "D", OPMODE_DIRECT_CONT,
@@ -97,20 +92,20 @@ void UFCAP_writeIni(Unit *unit, IniWriter *iw)
iw_cmt_newline(iw); iw_cmt_newline(iw);
iw_comment(iw, "Active level or edge (0-low,falling; 1-high,rising)"); iw_comment(iw, "Active level or edge (0-low,falling; 1-high,rising)");
iw_entry(iw, "active-level", "%d", (int)priv->conf.active_level); iw_entry_d(iw, "active-level", priv->conf.active_level);
iw_comment(iw, "Input filtering (0-15)"); iw_comment(iw, "Input filtering (0-15)");
iw_entry(iw, "input-filter", "%d", (int)priv->conf.dfilter); iw_entry_d(iw, "input-filter", priv->conf.dfilter);
iw_comment(iw, "Pulse counter pre-divider (1,2,4,8)"); iw_comment(iw, "Pulse counter pre-divider (1,2,4,8)");
iw_entry(iw, "direct-presc", "%d", (int)priv->conf.direct_presc); iw_entry_d(iw, "direct-presc", priv->conf.direct_presc);
iw_comment(iw, "Pulse counting interval (ms)"); iw_comment(iw, "Pulse counting interval (ms)");
iw_entry(iw, "direct-time", "%d", (int)priv->conf.direct_msec); iw_entry_d(iw, "direct-time", priv->conf.direct_msec);
iw_cmt_newline(iw); iw_cmt_newline(iw);
iw_comment(iw, "Mode on startup: N-none, I-indirect, D-direct, F-free count"); iw_comment(iw, "Mode on startup: N-none, I-indirect, D-direct, F-free count");
iw_entry(iw, "initial-mode", "%s", str_4(priv->conf.startmode, iw_entry_s(iw, "initial-mode", cfg_enum4_encode(priv->conf.startmode,
OPMODE_IDLE, "N", OPMODE_IDLE, "N",
OPMODE_INDIRECT_CONT, "I", OPMODE_INDIRECT_CONT, "I",
OPMODE_DIRECT_CONT, "D", OPMODE_DIRECT_CONT, "D",
+1 -1
View File
@@ -62,7 +62,7 @@ error_t UI2C_init(Unit *unit)
uint32_t af_i2c; uint32_t af_i2c;
uint32_t timing; // magic constant from CubeMX uint32_t timing; // magic constant from CubeMX
#if GEX_PLAT_F072_DISCOVERY #if STM32F072xB
// scl - 6 or 8 for I2C1, 10 for I2C2 // scl - 6 or 8 for I2C1, 10 for I2C2
// sda - 7 or 9 for I2C1, 11 for I2C2 // sda - 7 or 9 for I2C1, 11 for I2C2
if (priv->periph_num == 1) { if (priv->periph_num == 1) {
+12 -15
View File
@@ -20,18 +20,15 @@ void UI2C_loadBinary(Unit *unit, PayloadParser *pp)
priv->anf = pp_bool(pp); priv->anf = pp_bool(pp);
priv->dnf = pp_u8(pp); priv->dnf = pp_u8(pp);
priv->speed = pp_u8(pp); priv->speed = pp_u8(pp);
if (version >= 1) {
priv->remap = pp_u8(pp); priv->remap = pp_u8(pp);
} }
}
/** Write to a binary buffer for storing in Flash */ /** Write to a binary buffer for storing in Flash */
void UI2C_writeBinary(Unit *unit, PayloadBuilder *pb) void UI2C_writeBinary(Unit *unit, PayloadBuilder *pb)
{ {
struct priv *priv = unit->data; struct priv *priv = unit->data;
pb_u8(pb, 1); // version pb_u8(pb, 0); // version
pb_u8(pb, priv->periph_num); pb_u8(pb, priv->periph_num);
pb_bool(pb, priv->anf); pb_bool(pb, priv->anf);
@@ -49,19 +46,19 @@ error_t UI2C_loadIni(Unit *unit, const char *key, const char *value)
struct priv *priv = unit->data; struct priv *priv = unit->data;
if (streq(key, "device")) { if (streq(key, "device")) {
priv->periph_num = (uint8_t) avr_atoi(value); priv->periph_num = cfg_u8_parse(value, &suc);
} }
else if (streq(key, "remap")) { else if (streq(key, "remap")) {
priv->remap = (uint8_t) avr_atoi(value); priv->remap = cfg_u8_parse(value, &suc);
} }
else if (streq(key, "analog-filter")) { else if (streq(key, "analog-filter")) {
priv->anf = str_parse_yn(value, &suc); priv->anf = cfg_bool_parse(value, &suc);
} }
else if (streq(key, "digital-filter")) { else if (streq(key, "digital-filter")) {
priv->dnf = (uint8_t) avr_atoi(value); priv->dnf = cfg_u8_parse(value, &suc);
} }
else if (streq(key, "speed")) { else if (streq(key, "speed")) {
priv->speed = (uint8_t) avr_atoi(value); priv->speed = cfg_u8_parse(value, &suc);
} }
else { else {
return E_BAD_KEY; return E_BAD_KEY;
@@ -77,10 +74,10 @@ void UI2C_writeIni(Unit *unit, IniWriter *iw)
struct priv *priv = unit->data; struct priv *priv = unit->data;
iw_comment(iw, "Peripheral number (I2Cx)"); iw_comment(iw, "Peripheral number (I2Cx)");
iw_entry(iw, "device", "%d", (int)priv->periph_num); iw_entry_d(iw, "device", priv->periph_num);
iw_comment(iw, "Pin mappings (SCL,SDA)"); iw_comment(iw, "Pin mappings (SCL,SDA)");
#if GEX_PLAT_F072_DISCOVERY #if STM32F072xB
iw_comment(iw, " I2C1: (0) B6,B7 (1) B8,B9"); iw_comment(iw, " I2C1: (0) B6,B7 (1) B8,B9");
iw_comment(iw, " I2C2: (0) B10,B11 (1) B13,B14"); iw_comment(iw, " I2C2: (0) B10,B11 (1) B13,B14");
#elif GEX_PLAT_F103_BLUEPILL #elif GEX_PLAT_F103_BLUEPILL
@@ -92,15 +89,15 @@ void UI2C_writeIni(Unit *unit, IniWriter *iw)
#else #else
#error "BAD PLATFORM!" #error "BAD PLATFORM!"
#endif #endif
iw_entry(iw, "remap", "%d", (int)priv->remap); iw_entry_d(iw, "remap", priv->remap);
iw_cmt_newline(iw); iw_cmt_newline(iw);
iw_comment(iw, "Speed: 1-Standard, 2-Fast, 3-Fast+"); iw_comment(iw, "Speed: 1-Standard, 2-Fast, 3-Fast+");
iw_entry(iw, "speed", "%d", (int)priv->speed); iw_entry_d(iw, "speed", priv->speed);
iw_comment(iw, "Analog noise filter enable (Y,N)"); iw_comment(iw, "Analog noise filter enable (Y,N)");
iw_entry(iw, "analog-filter", "%s", str_yn(priv->anf)); iw_entry_s(iw, "analog-filter", str_yn(priv->anf));
iw_comment(iw, "Digital noise filter bandwidth (0-15)"); iw_comment(iw, "Digital noise filter bandwidth (0-15)");
iw_entry(iw, "digital-filter", "%d", (int)priv->dnf); iw_entry_d(iw, "digital-filter", priv->dnf);
} }
+2 -2
View File
@@ -12,7 +12,7 @@
#include "_i2c_internal.h" #include "_i2c_internal.h"
enum PinCmd_ { enum PinCmd_ {
CMD_TEST = 0, CMD_QUERY = 0,
CMD_READ = 1, CMD_READ = 1,
CMD_WRITE_REG = 2, CMD_WRITE_REG = 2,
CMD_READ_REG = 3, CMD_READ_REG = 3,
@@ -30,7 +30,7 @@ static error_t UI2C_handleRequest(Unit *unit, TF_ID frame_id, uint8_t command, P
switch (command) { switch (command) {
/** Write byte(s) - addr:u16, byte(s) */ /** Write byte(s) - addr:u16, byte(s) */
case CMD_TEST: case CMD_QUERY:
addr = pp_u16(pp); addr = pp_u16(pp);
const uint8_t *bb = pp_tail(pp, &len); const uint8_t *bb = pp_tail(pp, &len);
+6 -6
View File
@@ -16,7 +16,7 @@ error_t UU_Npx_Clear(Unit *unit)
CHECK_TYPE(unit, &UNIT_NEOPIXEL); CHECK_TYPE(unit, &UNIT_NEOPIXEL);
struct priv *priv = unit->data; struct priv *priv = unit->data;
ws2812_clear(priv->port, priv->ll_pin, priv->pixels); ws2812_clear(priv->port, priv->ll_pin, priv->cfg.pixels);
return E_SUCCESS; return E_SUCCESS;
} }
@@ -26,8 +26,8 @@ error_t UU_Npx_Load(Unit *unit, const uint8_t *packed_rgb, uint32_t nbytes)
CHECK_TYPE(unit, &UNIT_NEOPIXEL); CHECK_TYPE(unit, &UNIT_NEOPIXEL);
struct priv *priv = unit->data; struct priv *priv = unit->data;
if (nbytes != 3*priv->pixels) return E_BAD_COUNT; if (nbytes != 3*priv->cfg.pixels) return E_BAD_COUNT;
ws2812_load_raw(priv->port, priv->ll_pin, packed_rgb, priv->pixels); ws2812_load_raw(priv->port, priv->ll_pin, packed_rgb, priv->cfg.pixels);
return E_SUCCESS; return E_SUCCESS;
} }
@@ -37,8 +37,8 @@ static error_t load_u32(Unit *unit, const uint8_t *bytes, uint32_t nbytes, bool
CHECK_TYPE(unit, &UNIT_NEOPIXEL); CHECK_TYPE(unit, &UNIT_NEOPIXEL);
struct priv *priv = unit->data; struct priv *priv = unit->data;
if (nbytes != 4*priv->pixels) return E_BAD_COUNT; if (nbytes != 4*priv->cfg.pixels) return E_BAD_COUNT;
ws2812_load_sparse(priv->port, priv->ll_pin, bytes, priv->pixels, bige); ws2812_load_sparse(priv->port, priv->ll_pin, bytes, priv->cfg.pixels, bige);
return E_SUCCESS; return E_SUCCESS;
} }
@@ -60,6 +60,6 @@ error_t UU_Npx_GetCount(Unit *unit, uint16_t *count)
CHECK_TYPE(unit, &UNIT_NEOPIXEL); CHECK_TYPE(unit, &UNIT_NEOPIXEL);
struct priv *priv = unit->data; struct priv *priv = unit->data;
*count = priv->pixels; *count = priv->cfg.pixels;
return E_SUCCESS; return E_SUCCESS;
} }
+5 -10
View File
@@ -16,9 +16,8 @@ error_t Npx_preInit(Unit *unit)
if (priv == NULL) return E_OUT_OF_MEM; if (priv == NULL) return E_OUT_OF_MEM;
// some defaults // some defaults
priv->pin_number = 0; priv->cfg.pin = R_PA0;
priv->port_name = 'A'; priv->cfg.pixels = 1;
priv->pixels = 1;
return E_SUCCESS; return E_SUCCESS;
} }
@@ -30,13 +29,9 @@ error_t Npx_init(Unit *unit)
struct priv *priv = unit->data; struct priv *priv = unit->data;
// --- Parse config --- // --- Parse config ---
priv->ll_pin = hw_pin2ll(priv->pin_number, &suc); suc = hw_pinrsc2ll(priv->cfg.pin, &priv->port, &priv->ll_pin);
priv->port = hw_port2periph(priv->port_name, &suc);
Resource rsc = hw_pin2resource(priv->port_name, priv->pin_number, &suc);
if (!suc) return E_BAD_CONFIG; if (!suc) return E_BAD_CONFIG;
TRY(rsc_claim(unit, priv->cfg.pin));
// --- Claim resources ---
TRY(rsc_claim(unit, rsc));
// --- Init hardware --- // --- Init hardware ---
LL_GPIO_SetPinMode(priv->port, priv->ll_pin, LL_GPIO_MODE_OUTPUT); LL_GPIO_SetPinMode(priv->port, priv->ll_pin, LL_GPIO_MODE_OUTPUT);
@@ -45,7 +40,7 @@ error_t Npx_init(Unit *unit)
// clear strip // clear strip
ws2812_clear(priv->port, priv->ll_pin, priv->pixels); ws2812_clear(priv->port, priv->ll_pin, priv->cfg.pixels);
return E_SUCCESS; return E_SUCCESS;
} }
+3 -2
View File
@@ -13,9 +13,10 @@
/** Private data structure */ /** Private data structure */
struct priv { struct priv {
char port_name; struct {
uint8_t pin_number; Resource pin;
uint16_t pixels; uint16_t pixels;
} cfg;
uint32_t ll_pin; uint32_t ll_pin;
GPIO_TypeDef *port; GPIO_TypeDef *port;
+8 -10
View File
@@ -13,9 +13,8 @@ void Npx_loadBinary(Unit *unit, PayloadParser *pp)
{ {
struct priv *priv = unit->data; struct priv *priv = unit->data;
priv->port_name = pp_char(pp); priv->cfg.pin = (Resource) pp_u8(pp);
priv->pin_number = pp_u8(pp); priv->cfg.pixels = pp_u16(pp);
priv->pixels = pp_u16(pp);
} }
/** Write to a binary buffer for storing in Flash */ /** Write to a binary buffer for storing in Flash */
@@ -23,9 +22,8 @@ void Npx_writeBinary(Unit *unit, PayloadBuilder *pb)
{ {
struct priv *priv = unit->data; struct priv *priv = unit->data;
pb_char(pb, priv->port_name); pb_u8(pb, priv->cfg.pin);
pb_u8(pb, priv->pin_number); pb_u16(pb, priv->cfg.pixels);
pb_u16(pb, priv->pixels);
} }
// ------------------------------------------------------------------------ // ------------------------------------------------------------------------
@@ -37,10 +35,10 @@ error_t Npx_loadIni(Unit *unit, const char *key, const char *value)
struct priv *priv = unit->data; struct priv *priv = unit->data;
if (streq(key, "pin")) { if (streq(key, "pin")) {
suc = parse_pin(value, &priv->port_name, &priv->pin_number); priv->cfg.pin = cfg_pinrsc_parse(value, &suc);
} }
else if (streq(key, "pixels")) { else if (streq(key, "pixels")) {
priv->pixels = (uint16_t) avr_atoi(value); priv->cfg.pixels = cfg_u16_parse(value, &suc);
} }
else { else {
return E_BAD_KEY; return E_BAD_KEY;
@@ -56,8 +54,8 @@ void Npx_writeIni(Unit *unit, IniWriter *iw)
struct priv *priv = unit->data; struct priv *priv = unit->data;
iw_comment(iw, "Data pin"); iw_comment(iw, "Data pin");
iw_entry(iw, "pin", "%c%d", priv->port_name, priv->pin_number); iw_entry_s(iw, "pin", cfg_pinrsc_encode(priv->cfg.pin));
iw_comment(iw, "Number of pixels"); iw_comment(iw, "Number of pixels");
iw_entry(iw, "pixels", "%d", priv->pixels); iw_entry_d(iw, "pixels", priv->cfg.pixels);
} }
+64
View File
@@ -0,0 +1,64 @@
//
// Created by MightyPork on 2018/02/03.
//
#include "platform.h"
#include "unit_base.h"
#include "unit_pwmdim.h"
#define PWMDIM_INTERNAL
#include "_pwmdim_internal.h"
error_t UPWMDIM_SetFreq(Unit *unit, uint32_t freq)
{
struct priv *priv = unit->data;
uint16_t presc;
uint32_t count;
float real_freq;
if (!hw_solve_timer(PLAT_APB1_HZ, freq, true, &presc, &count, &real_freq)) {
dbg("Failed to resolve timer params.");
return E_BAD_VALUE;
}
LL_TIM_SetPrescaler(priv->TIMx, (uint32_t) (presc - 1));
LL_TIM_SetAutoReload(priv->TIMx, count - 1);
// we must re-calculate duty cycles because they are absolute related to the ARR which we just changed
UPWMDIM_SetDuty(unit, 0, priv->duty1);
UPWMDIM_SetDuty(unit, 1, priv->duty2);
UPWMDIM_SetDuty(unit, 2, priv->duty3);
UPWMDIM_SetDuty(unit, 3, priv->duty4);
// LL_TIM_GenerateEvent_UPDATE(priv->TIMx); // - this appears to cause jumpiness
priv->freq = freq;
return E_SUCCESS;
}
error_t UPWMDIM_SetDuty(Unit *unit, uint8_t ch, uint16_t duty1000)
{
struct priv *priv = unit->data;
uint32_t cnt = (LL_TIM_GetAutoReload(priv->TIMx) + 1)*duty1000 / 1000;
if (ch == 0) {
priv->duty1 = duty1000;
LL_TIM_OC_SetCompareCH1(priv->TIMx, cnt);
}
else if (ch == 1) {
priv->duty2 = duty1000;
LL_TIM_OC_SetCompareCH2(priv->TIMx, cnt);
}
else if (ch == 2) {
priv->duty3 = duty1000;
LL_TIM_OC_SetCompareCH3(priv->TIMx, cnt);
}
else if (ch == 3) {
priv->duty4 = duty1000;
LL_TIM_OC_SetCompareCH4(priv->TIMx, cnt);
} else {
return E_BAD_VALUE;
}
return E_SUCCESS;
}
+170
View File
@@ -0,0 +1,170 @@
//
// Created by MightyPork on 2018/02/03.
//
#include "platform.h"
#include "unit_base.h"
#define PWMDIM_INTERNAL
#include "_pwmdim_internal.h"
/** Allocate data structure and set defaults */
error_t UPWMDIM_preInit(Unit *unit)
{
struct priv *priv = unit->data = calloc_ck(1, sizeof(struct priv));
if (priv == NULL) return E_OUT_OF_MEM;
priv->cfg.freq = 1000;
priv->cfg.ch1_choice = 1;
priv->cfg.ch2_choice = 0;
priv->cfg.ch3_choice = 0;
priv->cfg.ch4_choice = 0;
priv->duty1 = 500;
priv->duty2 = 500;
priv->duty3 = 500;
priv->duty4 = 500;
return E_SUCCESS;
}
/** Finalize unit set-up */
error_t UPWMDIM_init(Unit *unit)
{
bool suc = true;
struct priv *priv = unit->data;
TRY(rsc_claim(unit, R_TIM3));
priv->TIMx = TIM3;
hw_periph_clock_enable(priv->TIMx);
// copy the default frequency
priv->freq = priv->cfg.freq;
const Resource ch1_pins[] = { R_PA6, R_PB4, R_PC6 };
const uint32_t ch1_af[] = { LL_GPIO_AF_1, LL_GPIO_AF_1, LL_GPIO_AF_0 };
const Resource ch2_pins[] = { R_PA7, R_PB5, R_PC7 };
const uint32_t ch2_af[] = { LL_GPIO_AF_1, LL_GPIO_AF_1, LL_GPIO_AF_0 };
const Resource ch3_pins[] = { R_PB0, R_PC8 };
const uint32_t ch3_af[] = { LL_GPIO_AF_1, LL_GPIO_AF_0 };
const Resource ch4_pins[] = { R_PB1, R_PC9 };
const uint32_t ch4_af[] = { LL_GPIO_AF_1, LL_GPIO_AF_0 };
Resource r[4] = {};
uint32_t af[4] = {};
// --- resolve pins and AFs ---
if (priv->cfg.ch1_choice > 0) {
if (priv->cfg.ch1_choice > 3) return E_BAD_CONFIG;
r[0] = ch1_pins[priv->cfg.ch1_choice - 1];
af[0] = ch1_af[priv->cfg.ch1_choice - 1];
TRY(rsc_claim(unit, r[0]));
}
if (priv->cfg.ch2_choice > 0) {
if (priv->cfg.ch2_choice > 3) return E_BAD_CONFIG;
r[1] = ch2_pins[priv->cfg.ch2_choice - 1];
af[1] = ch2_af[priv->cfg.ch2_choice - 1];
TRY(rsc_claim(unit, r[1]));
}
if (priv->cfg.ch3_choice > 0) {
if (priv->cfg.ch3_choice > 2) return E_BAD_CONFIG;
r[2] = ch3_pins[priv->cfg.ch3_choice - 1];
af[2] = ch3_af[priv->cfg.ch3_choice - 1];
TRY(rsc_claim(unit, r[2]));
}
if (priv->cfg.ch4_choice > 0) {
if (priv->cfg.ch4_choice > 2) return E_BAD_CONFIG;
r[3] = ch4_pins[priv->cfg.ch4_choice - 1];
af[3] = ch4_af[priv->cfg.ch4_choice - 1];
TRY(rsc_claim(unit, r[3]));
}
// --- configure AF + timer ---
LL_TIM_DeInit(priv->TIMx); // force a reset
uint16_t presc;
uint32_t count;
float real_freq;
if (!hw_solve_timer(PLAT_APB1_HZ, priv->freq, true, &presc, &count, &real_freq)) {
dbg("Failed to resolve timer params.");
return E_BAD_VALUE;
}
LL_TIM_SetPrescaler(priv->TIMx, (uint32_t) (presc - 1));
LL_TIM_SetAutoReload(priv->TIMx, count - 1);
LL_TIM_EnableARRPreload(priv->TIMx);
dbg("Presc %d, cnt %d", (int)presc, (int)count);
// TODO this can probably be turned into a loop over an array of structs
if (priv->cfg.ch1_choice > 0) {
TRY(hw_configure_gpiorsc_af(r[0], af[0]));
LL_TIM_OC_EnablePreload(priv->TIMx, LL_TIM_CHANNEL_CH1);
LL_TIM_OC_SetMode(priv->TIMx, LL_TIM_CHANNEL_CH1, LL_TIM_OCMODE_PWM1);
LL_TIM_OC_SetCompareCH1(priv->TIMx, count/2);
LL_TIM_CC_EnablePreload(priv->TIMx);
LL_TIM_CC_EnableChannel(priv->TIMx, LL_TIM_CHANNEL_CH1);
}
if (priv->cfg.ch2_choice > 0) {
TRY(hw_configure_gpiorsc_af(r[1], af[1]));
LL_TIM_OC_EnablePreload(priv->TIMx, LL_TIM_CHANNEL_CH2);
LL_TIM_OC_SetMode(priv->TIMx, LL_TIM_CHANNEL_CH2, LL_TIM_OCMODE_PWM1);
LL_TIM_OC_SetCompareCH2(priv->TIMx, count/2);
LL_TIM_CC_EnableChannel(priv->TIMx, LL_TIM_CHANNEL_CH2);
}
if (priv->cfg.ch3_choice > 0) {
TRY(hw_configure_gpiorsc_af(r[2], af[2]));
LL_TIM_OC_EnablePreload(priv->TIMx, LL_TIM_CHANNEL_CH3);
LL_TIM_OC_SetMode(priv->TIMx, LL_TIM_CHANNEL_CH3, LL_TIM_OCMODE_PWM1);
LL_TIM_OC_SetCompareCH3(priv->TIMx, count/2);
LL_TIM_CC_EnableChannel(priv->TIMx, LL_TIM_CHANNEL_CH3);
}
if (priv->cfg.ch4_choice > 0) {
TRY(hw_configure_gpiorsc_af(r[3], af[3]));
LL_TIM_OC_EnablePreload(priv->TIMx, LL_TIM_CHANNEL_CH4);
LL_TIM_OC_SetMode(priv->TIMx, LL_TIM_CHANNEL_CH4, LL_TIM_OCMODE_PWM1);
LL_TIM_OC_SetCompareCH4(priv->TIMx, count/2);
LL_TIM_CC_EnableChannel(priv->TIMx, LL_TIM_CHANNEL_CH4);
}
LL_TIM_GenerateEvent_UPDATE(priv->TIMx);
LL_TIM_EnableAllOutputs(priv->TIMx);
// postpone this for later - when user uses the start command.
// prevents beeping right after restart if used for audio.
// LL_TIM_EnableCounter(priv->TIMx);
return E_SUCCESS;
}
/** Tear down the unit */
void UPWMDIM_deInit(Unit *unit)
{
struct priv *priv = unit->data;
// de-init peripherals
if (unit->status == E_SUCCESS ) {
LL_TIM_DeInit(priv->TIMx);
}
// Release all resources, deinit pins
rsc_teardown(unit);
// Free memory
free_ck(unit->data);
}
+65
View File
@@ -0,0 +1,65 @@
//
// Created by MightyPork on 2018/02/03.
//
#ifndef GEX_F072_PWMDIM_INTERNAL_H
#define GEX_F072_PWMDIM_INTERNAL_H
#ifndef PWMDIM_INTERNAL
#error bad include!
#endif
#include "unit_base.h"
/** Private data structure */
struct priv {
// settings
struct {
uint32_t freq;
uint8_t ch1_choice;
uint8_t ch2_choice;
uint8_t ch3_choice;
uint8_t ch4_choice;
} cfg;
// internal state
uint32_t freq;
uint16_t duty1;
uint16_t duty2;
uint16_t duty3;
uint16_t duty4;
TIM_TypeDef *TIMx;
};
/** Allocate data structure and set defaults */
error_t UPWMDIM_preInit(Unit *unit);
/** Load from a binary buffer stored in Flash */
void UPWMDIM_loadBinary(Unit *unit, PayloadParser *pp);
/** Write to a binary buffer for storing in Flash */
void UPWMDIM_writeBinary(Unit *unit, PayloadBuilder *pb);
// ------------------------------------------------------------------------
/** Parse a key-value pair from the INI file */
error_t UPWMDIM_loadIni(Unit *unit, const char *key, const char *value);
/** Generate INI file section for the unit */
void UPWMDIM_writeIni(Unit *unit, IniWriter *iw);
// ------------------------------------------------------------------------
/** Finalize unit set-up */
error_t UPWMDIM_init(Unit *unit);
/** Tear down the unit */
void UPWMDIM_deInit(Unit *unit);
error_t UPWMDIM_SetFreq(Unit *unit, uint32_t freq);
error_t UPWMDIM_SetDuty(Unit *unit, uint8_t ch, uint16_t duty1000);
#endif //GEX_F072_PWMDIM_INTERNAL_H
+89
View File
@@ -0,0 +1,89 @@
//
// Created by MightyPork on 2018/02/03.
//
#include "platform.h"
#include "unit_base.h"
#define PWMDIM_INTERNAL
#include "_pwmdim_internal.h"
/** Load from a binary buffer stored in Flash */
void UPWMDIM_loadBinary(Unit *unit, PayloadParser *pp)
{
struct priv *priv = unit->data;
uint8_t version = pp_u8(pp);
(void)version;
priv->cfg.freq = pp_u32(pp);
priv->cfg.ch1_choice = pp_u8(pp);
priv->cfg.ch2_choice = pp_u8(pp);
priv->cfg.ch3_choice = pp_u8(pp);
priv->cfg.ch4_choice = pp_u8(pp);
}
/** Write to a binary buffer for storing in Flash */
void UPWMDIM_writeBinary(Unit *unit, PayloadBuilder *pb)
{
struct priv *priv = unit->data;
pb_u8(pb, 0); // version
pb_u32(pb, priv->cfg.freq);
pb_u8(pb, priv->cfg.ch1_choice);
pb_u8(pb, priv->cfg.ch2_choice);
pb_u8(pb, priv->cfg.ch3_choice);
pb_u8(pb, priv->cfg.ch4_choice);
}
// ------------------------------------------------------------------------
/** Parse a key-value pair from the INI file */
error_t UPWMDIM_loadIni(Unit *unit, const char *key, const char *value)
{
bool suc = true;
struct priv *priv = unit->data;
if (streq(key, "frequency")) {
priv->cfg.freq = cfg_u32_parse(value, &suc);
}
else if (streq(key, "ch1_pin")) {
priv->cfg.ch1_choice = cfg_u8_parse(value, &suc);
}
else if (streq(key, "ch2_pin")) {
priv->cfg.ch2_choice = cfg_u8_parse(value, &suc);
}
else if (streq(key, "ch3_pin")) {
priv->cfg.ch3_choice = cfg_u8_parse(value, &suc);
}
else if (streq(key, "ch4_pin")) {
priv->cfg.ch4_choice = cfg_u8_parse(value, &suc);
}
else {
return E_BAD_KEY;
}
if (!suc) return E_BAD_VALUE;
return E_SUCCESS;
}
/** Generate INI file section for the unit */
void UPWMDIM_writeIni(Unit *unit, IniWriter *iw)
{
struct priv *priv = unit->data;
iw_comment(iw, "Default pulse frequency (Hz)");
iw_entry_d(iw, "frequency", priv->cfg.freq);
iw_comment(iw, "Pin mapping - 0=disabled");
iw_comment(iw, "Channel1 - 1:PA6, 2:PB4, 3:PC6");
iw_entry_d(iw, "ch1_pin", priv->cfg.ch1_choice);
iw_comment(iw, "Channel2 - 1:PA7, 2:PB5, 3:PC7");
iw_entry_d(iw, "ch2_pin", priv->cfg.ch2_choice);
iw_comment(iw, "Channel3 - 1:PB0, 2:PC8");
iw_entry_d(iw, "ch3_pin", priv->cfg.ch3_choice);
iw_comment(iw, "Channel4 - 1:PB1, 2:PC9");
iw_entry_d(iw, "ch4_pin", priv->cfg.ch4_choice);
}
+69
View File
@@ -0,0 +1,69 @@
//
// Created by MightyPork on 2017/11/25.
//
#include "unit_base.h"
#include "unit_pwmdim.h"
#define PWMDIM_INTERNAL
#include "_pwmdim_internal.h"
// ------------------------------------------------------------------------
enum PwmSimpleCmd_ {
CMD_SET_FREQUENCY = 0,
CMD_SET_DUTY = 1,
CMD_STOP = 2,
CMD_START = 3,
};
/** Handle a request message */
static error_t UPWMDIM_handleRequest(Unit *unit, TF_ID frame_id, uint8_t command, PayloadParser *pp)
{
struct priv *priv = unit->data;
switch (command) {
case CMD_SET_FREQUENCY:
TRY(UPWMDIM_SetFreq(unit, pp_u32(pp)));
return E_SUCCESS;
case CMD_SET_DUTY:
for (; pp_length(pp) > 0;) {
uint8_t ch = pp_u8(pp);
uint16_t duty = pp_u16(pp);
TRY(UPWMDIM_SetDuty(unit, ch, duty));
}
return E_SUCCESS;
case CMD_STOP:
LL_TIM_DisableCounter(priv->TIMx);
LL_TIM_SetCounter(priv->TIMx, 0);
return E_SUCCESS;
case CMD_START:
LL_TIM_EnableCounter(priv->TIMx);
return E_SUCCESS;
default:
return E_UNKNOWN_COMMAND;
}
}
// ------------------------------------------------------------------------
/** Simple PWM dimming output */
const UnitDriver UNIT_PWMDIM = {
.name = "PWMDIM",
.description = "Simple PWM output",
// Settings
.preInit = UPWMDIM_preInit,
.cfgLoadBinary = UPWMDIM_loadBinary,
.cfgWriteBinary = UPWMDIM_writeBinary,
.cfgLoadIni = UPWMDIM_loadIni,
.cfgWriteIni = UPWMDIM_writeIni,
// Init
.init = UPWMDIM_init,
.deInit = UPWMDIM_deInit,
// Function
.handleRequest = UPWMDIM_handleRequest,
};
+16
View File
@@ -0,0 +1,16 @@
//
// Created by MightyPork on 2017/11/25.
//
// Digital input unit; single or multiple pin read access on one port (A-F)
//
#ifndef U_PWMDIM_H
#define U_PWMDIM_H
#include "unit.h"
extern const UnitDriver UNIT_PWMDIM;
// UU_ prototypes
#endif //U_PWMDIM_H
+8 -8
View File
@@ -43,7 +43,7 @@ error_t UU_SIPO_Write(Unit *unit, const uint8_t *buffer, uint16_t buflen, uint16
// buffer contains data for the individual data pins, back to back as AAA BBB CCC (whole bytes) // buffer contains data for the individual data pins, back to back as AAA BBB CCC (whole bytes)
const uint8_t data_width = priv->data_width; const uint8_t data_width = priv->data_width;
const uint16_t bytelen = buflen / data_width; const uint16_t bytelen = buflen / data_width;
const uint16_t mask = priv->data_pins; const uint16_t mask = priv->cfg.data_pins;
uint8_t offsets[16]; uint8_t offsets[16];
for (int i=0; i<16; i++) offsets[i] = (uint8_t) (bytelen * i); for (int i=0; i<16; i++) offsets[i] = (uint8_t) (bytelen * i);
@@ -61,7 +61,7 @@ error_t UU_SIPO_Write(Unit *unit, const uint8_t *buffer, uint16_t buflen, uint16
priv->data_port->BSRR = spread | (((~spread) & mask) << 16); priv->data_port->BSRR = spread | (((~spread) & mask) << 16);
// Shift clock pulse // Shift clock pulse
send_pulse(priv->shift_pol, priv->shift_port, priv->shift_ll); send_pulse(priv->cfg.shift_pol, priv->shift_port, priv->shift_ll);
} }
} }
@@ -70,7 +70,7 @@ error_t UU_SIPO_Write(Unit *unit, const uint8_t *buffer, uint16_t buflen, uint16
uint16_t spread = pinmask_spread(terminal_data, mask); uint16_t spread = pinmask_spread(terminal_data, mask);
priv->data_port->BSRR = spread | (((~spread) & mask) << 16); priv->data_port->BSRR = spread | (((~spread) & mask) << 16);
send_pulse(priv->store_pol, priv->store_port, priv->store_ll); send_pulse(priv->cfg.store_pol, priv->store_port, priv->store_ll);
return E_SUCCESS; return E_SUCCESS;
} }
#pragma GCC pop_options #pragma GCC pop_options
@@ -80,8 +80,8 @@ error_t UU_SIPO_DirectData(Unit *unit, uint16_t data_packed)
CHECK_TYPE(unit, &UNIT_SIPO); CHECK_TYPE(unit, &UNIT_SIPO);
struct priv *priv = unit->data; struct priv *priv = unit->data;
uint16_t spread = pinmask_spread(data_packed, priv->data_pins); uint16_t spread = pinmask_spread(data_packed, priv->cfg.data_pins);
priv->data_port->BSRR = spread | (((~spread) & priv->data_pins) << 16); priv->data_port->BSRR = spread | (((~spread) & priv->cfg.data_pins) << 16);
return E_SUCCESS; return E_SUCCESS;
} }
@@ -89,7 +89,7 @@ error_t UU_SIPO_DirectClear(Unit *unit)
{ {
CHECK_TYPE(unit, &UNIT_SIPO); CHECK_TYPE(unit, &UNIT_SIPO);
struct priv *priv = unit->data; struct priv *priv = unit->data;
send_pulse(priv->clear_pol, priv->clear_port, priv->clear_ll); send_pulse(priv->cfg.clear_pol, priv->clear_port, priv->clear_ll);
return E_SUCCESS; return E_SUCCESS;
} }
@@ -97,7 +97,7 @@ error_t UU_SIPO_DirectShift(Unit *unit)
{ {
CHECK_TYPE(unit, &UNIT_SIPO); CHECK_TYPE(unit, &UNIT_SIPO);
struct priv *priv = unit->data; struct priv *priv = unit->data;
send_pulse(priv->shift_pol, priv->shift_port, priv->shift_ll); send_pulse(priv->cfg.shift_pol, priv->shift_port, priv->shift_ll);
return E_SUCCESS; return E_SUCCESS;
} }
@@ -105,6 +105,6 @@ error_t UU_SIPO_DirectStore(Unit *unit)
{ {
CHECK_TYPE(unit, &UNIT_SIPO); CHECK_TYPE(unit, &UNIT_SIPO);
struct priv *priv = unit->data; struct priv *priv = unit->data;
send_pulse(priv->store_pol, priv->store_port, priv->store_ll); send_pulse(priv->cfg.store_pol, priv->store_port, priv->store_ll);
return E_SUCCESS; return E_SUCCESS;
} }
+21 -34
View File
@@ -14,20 +14,17 @@ error_t USIPO_preInit(Unit *unit)
struct priv *priv = unit->data = calloc_ck(1, sizeof(struct priv)); struct priv *priv = unit->data = calloc_ck(1, sizeof(struct priv));
if (priv == NULL) return E_OUT_OF_MEM; if (priv == NULL) return E_OUT_OF_MEM;
priv->store_pname = 'A'; priv->cfg.pin_store = R_PA0;
priv->store_pnum = 0; priv->cfg.store_pol = true;
priv->store_pol = true;
priv->shift_pname = 'A'; priv->cfg.pin_shift = R_PA1;
priv->shift_pnum = 1; priv->cfg.shift_pol = true;
priv->shift_pol = true;
priv->clear_pname = 'A'; priv->cfg.pin_clear = R_PA2;
priv->clear_pnum = 2; priv->cfg.clear_pol = false;
priv->clear_pol = false;
priv->data_pname = 'A'; priv->cfg.data_pname = 'A';
priv->data_pins = (1<<3); priv->cfg.data_pins = (1<<3);
return E_SUCCESS; return E_SUCCESS;
} }
@@ -39,33 +36,23 @@ error_t USIPO_init(Unit *unit)
struct priv *priv = unit->data; struct priv *priv = unit->data;
// --- Parse config --- // --- Parse config ---
priv->store_ll = hw_pin2ll(priv->store_pnum, &suc); suc &= hw_pinrsc2ll(priv->cfg.pin_store, &priv->store_port, &priv->store_ll);
priv->store_port = hw_port2periph(priv->store_pname, &suc); suc &= hw_pinrsc2ll(priv->cfg.pin_shift, &priv->shift_port, &priv->shift_ll);
Resource store_rsc = hw_pin2resource(priv->store_pname, priv->store_pnum, &suc); suc &= hw_pinrsc2ll(priv->cfg.pin_clear, &priv->clear_port, &priv->clear_ll);
if (!suc) return E_BAD_CONFIG; if (!suc) return E_BAD_CONFIG;
TRY(rsc_claim(unit, store_rsc)); TRY(rsc_claim(unit, priv->cfg.pin_store));
TRY(rsc_claim(unit, priv->cfg.pin_shift));
priv->shift_ll = hw_pin2ll(priv->shift_pnum, &suc); TRY(rsc_claim(unit, priv->cfg.pin_clear));
priv->shift_port = hw_port2periph(priv->shift_pname, &suc);
Resource shift_rsc = hw_pin2resource(priv->shift_pname, priv->shift_pnum, &suc);
if (!suc) return E_BAD_CONFIG;
TRY(rsc_claim(unit, shift_rsc));
priv->clear_ll = hw_pin2ll(priv->clear_pnum, &suc);
priv->clear_port = hw_port2periph(priv->clear_pname, &suc);
Resource clear_rsc = hw_pin2resource(priv->clear_pname, priv->clear_pnum, &suc);
if (!suc) return E_BAD_CONFIG;
TRY(rsc_claim(unit, clear_rsc));
// Claim all needed pins // Claim all needed pins
TRY(rsc_claim_gpios(unit, priv->data_pname, priv->data_pins)); TRY(rsc_claim_gpios(unit, priv->cfg.data_pname, priv->cfg.data_pins));
priv->data_port = hw_port2periph(priv->data_pname, &suc); priv->data_port = hw_port2periph(priv->cfg.data_pname, &suc);
// --- Init hardware --- // --- Init hardware ---
priv->data_width = 0; priv->data_width = 0;
for (int i = 0; i < 16; i++) { for (int i = 0; i < 16; i++) {
if (priv->data_pins & (1 << i)) { if (priv->cfg.data_pins & (1 << i)) {
uint32_t ll_pin = hw_pin2ll((uint8_t) i, &suc); uint32_t ll_pin = hw_pin2ll((uint8_t) i, &suc);
LL_GPIO_SetPinMode(priv->data_port, ll_pin, LL_GPIO_MODE_OUTPUT); LL_GPIO_SetPinMode(priv->data_port, ll_pin, LL_GPIO_MODE_OUTPUT);
LL_GPIO_SetPinOutputType(priv->data_port, ll_pin, LL_GPIO_OUTPUT_PUSHPULL); LL_GPIO_SetPinOutputType(priv->data_port, ll_pin, LL_GPIO_OUTPUT_PUSHPULL);
@@ -75,7 +62,7 @@ error_t USIPO_init(Unit *unit)
} }
// Set the initial state - zeros // Set the initial state - zeros
priv->data_port->ODR &= ~priv->data_pins; priv->data_port->ODR &= ~priv->cfg.data_pins;
// STORE // STORE
@@ -83,7 +70,7 @@ error_t USIPO_init(Unit *unit)
LL_GPIO_SetPinOutputType(priv->store_port, priv->store_ll, LL_GPIO_OUTPUT_PUSHPULL); LL_GPIO_SetPinOutputType(priv->store_port, priv->store_ll, LL_GPIO_OUTPUT_PUSHPULL);
LL_GPIO_SetPinSpeed(priv->store_port, priv->store_ll, LL_GPIO_SPEED_FREQ_HIGH); LL_GPIO_SetPinSpeed(priv->store_port, priv->store_ll, LL_GPIO_SPEED_FREQ_HIGH);
if (priv->store_pol) if (priv->cfg.store_pol)
LL_GPIO_ResetOutputPin(priv->store_port, priv->store_ll); LL_GPIO_ResetOutputPin(priv->store_port, priv->store_ll);
else else
LL_GPIO_SetOutputPin(priv->store_port, priv->store_ll); LL_GPIO_SetOutputPin(priv->store_port, priv->store_ll);
@@ -93,7 +80,7 @@ error_t USIPO_init(Unit *unit)
LL_GPIO_SetPinOutputType(priv->shift_port, priv->shift_ll, LL_GPIO_OUTPUT_PUSHPULL); LL_GPIO_SetPinOutputType(priv->shift_port, priv->shift_ll, LL_GPIO_OUTPUT_PUSHPULL);
LL_GPIO_SetPinSpeed(priv->shift_port, priv->shift_ll, LL_GPIO_SPEED_FREQ_HIGH); LL_GPIO_SetPinSpeed(priv->shift_port, priv->shift_ll, LL_GPIO_SPEED_FREQ_HIGH);
if (priv->shift_pol) if (priv->cfg.shift_pol)
LL_GPIO_ResetOutputPin(priv->shift_port, priv->shift_ll); LL_GPIO_ResetOutputPin(priv->shift_port, priv->shift_ll);
else else
LL_GPIO_SetOutputPin(priv->shift_port, priv->shift_ll); LL_GPIO_SetOutputPin(priv->shift_port, priv->shift_ll);
@@ -103,7 +90,7 @@ error_t USIPO_init(Unit *unit)
LL_GPIO_SetPinOutputType(priv->clear_port, priv->clear_ll, LL_GPIO_OUTPUT_PUSHPULL); LL_GPIO_SetPinOutputType(priv->clear_port, priv->clear_ll, LL_GPIO_OUTPUT_PUSHPULL);
LL_GPIO_SetPinSpeed(priv->clear_port, priv->clear_ll, LL_GPIO_SPEED_FREQ_HIGH); LL_GPIO_SetPinSpeed(priv->clear_port, priv->clear_ll, LL_GPIO_SPEED_FREQ_HIGH);
if (priv->clear_pol) if (priv->cfg.clear_pol)
LL_GPIO_ResetOutputPin(priv->clear_port, priv->clear_ll); LL_GPIO_ResetOutputPin(priv->clear_port, priv->clear_ll);
else else
LL_GPIO_SetOutputPin(priv->clear_port, priv->clear_ll); LL_GPIO_SetOutputPin(priv->clear_port, priv->clear_ll);
+5 -6
View File
@@ -13,21 +13,20 @@
/** Private data structure */ /** Private data structure */
struct priv { struct priv {
struct {
// settings // settings
char store_pname; Resource pin_store;
uint8_t store_pnum;
bool store_pol; //!< Store pulse active edge bool store_pol; //!< Store pulse active edge
char shift_pname; Resource pin_shift;
uint8_t shift_pnum;
bool shift_pol; //!< Shift clock active edge bool shift_pol; //!< Shift clock active edge
char clear_pname; Resource pin_clear;
uint8_t clear_pnum;
bool clear_pol; //!< Clear signal active level bool clear_pol; //!< Clear signal active level
char data_pname; char data_pname;
uint16_t data_pins; uint16_t data_pins;
} cfg;
// live fields // live fields
uint32_t store_ll; uint32_t store_ll;
+32 -38
View File
@@ -16,20 +16,17 @@ void USIPO_loadBinary(Unit *unit, PayloadParser *pp)
uint8_t version = pp_u8(pp); uint8_t version = pp_u8(pp);
(void)version; (void)version;
priv->store_pname = pp_char(pp); priv->cfg.pin_store = (Resource) pp_u8(pp);
priv->store_pnum = pp_u8(pp); priv->cfg.store_pol = pp_bool(pp);
priv->store_pol = pp_bool(pp);
priv->shift_pname = pp_char(pp); priv->cfg.pin_shift = (Resource) pp_u8(pp);
priv->shift_pnum = pp_u8(pp); priv->cfg.shift_pol = pp_bool(pp);
priv->shift_pol = pp_bool(pp);
priv->clear_pname = pp_char(pp); priv->cfg.pin_clear = (Resource) pp_u8(pp);
priv->clear_pnum = pp_u8(pp); priv->cfg.clear_pol = pp_bool(pp);
priv->clear_pol = pp_bool(pp);
priv->data_pname = pp_char(pp); priv->cfg.data_pname = pp_char(pp);
priv->data_pins = pp_u16(pp); priv->cfg.data_pins = pp_u16(pp);
} }
/** Write to a binary buffer for storing in Flash */ /** Write to a binary buffer for storing in Flash */
@@ -39,20 +36,17 @@ void USIPO_writeBinary(Unit *unit, PayloadBuilder *pb)
pb_u8(pb, 0); // version pb_u8(pb, 0); // version
pb_char(pb, priv->store_pname); pb_u8(pb, priv->cfg.pin_store);
pb_u8(pb, priv->store_pnum); pb_bool(pb, priv->cfg.store_pol);
pb_bool(pb, priv->store_pol);
pb_char(pb, priv->shift_pname); pb_u8(pb, priv->cfg.pin_shift);
pb_u8(pb, priv->shift_pnum); pb_bool(pb, priv->cfg.shift_pol);
pb_bool(pb, priv->shift_pol);
pb_char(pb, priv->clear_pname); pb_u8(pb, priv->cfg.pin_clear);
pb_u8(pb, priv->clear_pnum); pb_bool(pb, priv->cfg.clear_pol);
pb_bool(pb, priv->clear_pol);
pb_char(pb, priv->data_pname); pb_char(pb, priv->cfg.data_pname);
pb_u16(pb, priv->data_pins); pb_u16(pb, priv->cfg.data_pins);
} }
// ------------------------------------------------------------------------ // ------------------------------------------------------------------------
@@ -64,30 +58,30 @@ error_t USIPO_loadIni(Unit *unit, const char *key, const char *value)
struct priv *priv = unit->data; struct priv *priv = unit->data;
if (streq(key, "store-pin")) { if (streq(key, "store-pin")) {
suc = parse_pin(value, &priv->store_pname, &priv->store_pnum); priv->cfg.pin_store = cfg_pinrsc_parse(value, &suc);
} }
else if (streq(key, "shift-pin")) { else if (streq(key, "shift-pin")) {
suc = parse_pin(value, &priv->shift_pname, &priv->shift_pnum); priv->cfg.pin_shift = cfg_pinrsc_parse(value, &suc);
} }
else if (streq(key, "clear-pin")) { else if (streq(key, "clear-pin")) {
suc = parse_pin(value, &priv->clear_pname, &priv->clear_pnum); priv->cfg.pin_clear = cfg_pinrsc_parse(value, &suc);
} }
else if (streq(key, "store-pol")) { else if (streq(key, "store-pol")) {
priv->store_pol = (bool) avr_atoi(value); priv->cfg.store_pol = cfg_bool_parse(value, &suc);
} }
else if (streq(key, "shift-pol")) { else if (streq(key, "shift-pol")) {
priv->shift_pol = (bool) avr_atoi(value); priv->cfg.shift_pol = cfg_bool_parse(value, &suc);
} }
else if (streq(key, "clear-pol")) { else if (streq(key, "clear-pol")) {
priv->clear_pol = (bool) avr_atoi(value); priv->cfg.clear_pol = cfg_bool_parse(value, &suc);
} }
else if (streq(key, "data-port")) { else if (streq(key, "data-port")) {
suc = parse_port_name(value, &priv->data_pname); suc = cfg_port_parse(value, &priv->cfg.data_pname);
} }
else if (streq(key, "data-pins")) { else if (streq(key, "data-pins")) {
priv->data_pins = (uint16_t) parse_pinmask(value, &suc); priv->cfg.data_pins = cfg_pinmask_parse(value, &suc);
} }
else { else {
@@ -104,19 +98,19 @@ void USIPO_writeIni(Unit *unit, IniWriter *iw)
struct priv *priv = unit->data; struct priv *priv = unit->data;
iw_comment(iw, "Shift pin & its active edge (1-rising,0-falling)"); iw_comment(iw, "Shift pin & its active edge (1-rising,0-falling)");
iw_entry(iw, "shift-pin", "%c%d", priv->shift_pname, priv->shift_pnum); iw_entry_s(iw, "shift-pin", cfg_pinrsc_encode(priv->cfg.pin_shift));
iw_entry(iw, "shift-pol", "%d", priv->shift_pol); iw_entry_d(iw, "shift-pol", priv->cfg.shift_pol);
iw_comment(iw, "Store pin & its active edge"); iw_comment(iw, "Store pin & its active edge");
iw_entry(iw, "store-pin", "%c%d", priv->store_pname, priv->store_pnum); iw_entry_s(iw, "store-pin", cfg_pinrsc_encode(priv->cfg.pin_store));
iw_entry(iw, "store-pol", "%d", priv->store_pol); iw_entry_d(iw, "store-pol", priv->cfg.store_pol);
iw_comment(iw, "Clear pin & its active level"); iw_comment(iw, "Clear pin & its active level");
iw_entry(iw, "clear-pin", "%c%d", priv->clear_pname, priv->clear_pnum); iw_entry_s(iw, "clear-pin", cfg_pinrsc_encode(priv->cfg.pin_clear));
iw_entry(iw, "clear-pol", "%d", priv->clear_pol); iw_entry_d(iw, "clear-pol", priv->cfg.clear_pol);
iw_comment(iw, "Data port and pins"); iw_comment(iw, "Data port and pins");
iw_entry(iw, "data-port", "%c", priv->data_pname); iw_entry(iw, "data-port", "%c", priv->cfg.data_pname);
iw_entry(iw, "data-pins", "%s", pinmask2str_up(priv->data_pins, unit_tmp512)); iw_entry_s(iw, "data-pins", cfg_pinmask_encode(priv->cfg.data_pins, unit_tmp512, true));
} }
+2 -2
View File
@@ -12,7 +12,7 @@
// ------------------------------------------------------------------------ // ------------------------------------------------------------------------
enum SipoCmd_ { enum SipoCmd_ {
CMD_WRITE = 0, CMD_QUERY = 0,
CMD_DIRECT_DATA = 1, CMD_DIRECT_DATA = 1,
CMD_DIRECT_SHIFT = 2, CMD_DIRECT_SHIFT = 2,
CMD_DIRECT_CLEAR = 3, CMD_DIRECT_CLEAR = 3,
@@ -23,7 +23,7 @@ enum SipoCmd_ {
static error_t USIPO_handleRequest(Unit *unit, TF_ID frame_id, uint8_t command, PayloadParser *pp) static error_t USIPO_handleRequest(Unit *unit, TF_ID frame_id, uint8_t command, PayloadParser *pp)
{ {
switch (command) { switch (command) {
case CMD_WRITE: case CMD_QUERY:
{ {
uint32_t len; uint32_t len;
uint16_t terminal_packed = pp_u16(pp); uint16_t terminal_packed = pp_u16(pp);
+17 -17
View File
@@ -63,7 +63,7 @@ error_t USPI_init(Unit *unit)
uint32_t af_spi; uint32_t af_spi;
// TODO // TODO
#if GEX_PLAT_F072_DISCOVERY #if STM32F072xB
// SPI1 - many options // SPI1 - many options
// sck, miso, mosi, af // sck, miso, mosi, af
@@ -83,14 +83,14 @@ error_t USPI_init(Unit *unit)
pin_miso = 4; pin_miso = 4;
pin_mosi = 5; pin_mosi = 5;
} }
else if (priv->remap == 2) { // else if (priv->remap == 2) {
// large packages only // // large packages only
spi_portname = 'E'; // spi_portname = 'E';
af_spi = LL_GPIO_AF_1; // af_spi = LL_GPIO_AF_1;
pin_sck = 13; // pin_sck = 13;
pin_miso = 14; // pin_miso = 14;
pin_mosi = 15; // pin_mosi = 15;
} // }
else { else {
return E_BAD_CONFIG; return E_BAD_CONFIG;
} }
@@ -104,14 +104,14 @@ error_t USPI_init(Unit *unit)
pin_miso = 14; pin_miso = 14;
pin_mosi = 15; pin_mosi = 15;
} }
else if (priv->remap == 1) { // else if (priv->remap == 1) {
// NOTE: the's also a incomplete remap in PB and PC // // NOTE: there's also an incomplete remap in PB and PC
spi_portname = 'D'; // spi_portname = 'D';
af_spi = LL_GPIO_AF_0; // af_spi = LL_GPIO_AF_0;
pin_sck = 1; // pin_sck = 1;
pin_miso = 3; // pin_miso = 3;
pin_mosi = 4; // pin_mosi = 4;
} // }
else { else {
return E_BAD_CONFIG; return E_BAD_CONFIG;
} }
+20 -22
View File
@@ -58,31 +58,31 @@ error_t USPI_loadIni(Unit *unit, const char *key, const char *value)
struct priv *priv = unit->data; struct priv *priv = unit->data;
if (streq(key, "device")) { if (streq(key, "device")) {
priv->periph_num = (uint8_t) avr_atoi(value); priv->periph_num = cfg_u8_parse(value, &suc);
} }
else if (streq(key, "remap")) { else if (streq(key, "remap")) {
priv->remap = (uint8_t) avr_atoi(value); priv->remap = cfg_u8_parse(value, &suc);
} }
else if (streq(key, "prescaller")) { else if (streq(key, "prescaller")) {
priv->prescaller = (uint16_t ) avr_atoi(value); priv->prescaller = cfg_u16_parse(value, &suc);
} }
else if (streq(key, "cpol")) { else if (streq(key, "cpol")) {
priv->cpol = (bool) avr_atoi(value); priv->cpol = cfg_bool_parse(value, &suc);
} }
else if (streq(key, "cpha")) { else if (streq(key, "cpha")) {
priv->cpha = (bool) avr_atoi(value); priv->cpha = cfg_bool_parse(value, &suc);
} }
else if (streq(key, "tx-only")) { else if (streq(key, "tx-only")) {
priv->tx_only = str_parse_yn(value, &suc); priv->tx_only = cfg_bool_parse(value, &suc);
} }
else if (streq(key, "first-bit")) { else if (streq(key, "first-bit")) {
priv->lsb_first = (bool)str_parse_2(value, "MSB", 0, "LSB", 1, &suc); priv->lsb_first = (bool) cfg_enum2_parse(value, "MSB", 0, "LSB", 1, &suc);
} }
else if (streq(key, "port")) { else if (streq(key, "port")) {
suc = parse_port_name(value, &priv->ssn_port_name); suc = cfg_port_parse(value, &priv->ssn_port_name);
} }
else if (streq(key, "pins")) { else if (streq(key, "pins")) {
priv->ssn_pins = parse_pinmask(value, &suc); priv->ssn_pins = cfg_pinmask_parse(value, &suc);
} }
else { else {
return E_BAD_KEY; return E_BAD_KEY;
@@ -98,13 +98,13 @@ void USPI_writeIni(Unit *unit, IniWriter *iw)
struct priv *priv = unit->data; struct priv *priv = unit->data;
iw_comment(iw, "Peripheral number (SPIx)"); iw_comment(iw, "Peripheral number (SPIx)");
iw_entry(iw, "device", "%d", (int)priv->periph_num); iw_entry_d(iw, "device", priv->periph_num);
// TODO show a legend for peripherals and remaps // TODO show a legend for peripherals and remaps
iw_comment(iw, "Pin mappings (SCK,MISO,MOSI)"); iw_comment(iw, "Pin mappings (SCK,MISO,MOSI)");
#if GEX_PLAT_F072_DISCOVERY #if STM32F072xB
iw_comment(iw, " SPI1: (0) A5,A6,A7 (1) B3,B4,B5 (2) E13,E14,E15"); iw_comment(iw, " SPI1: (0) A5,A6,A7 (1) B3,B4,B5"); // (2) E13,E14,E15
iw_comment(iw, " SPI2: (0) B13,B14,B15 (1) D1,D3,D4"); iw_comment(iw, " SPI2: (0) B13,B14,B15"); // (1) D1,D3,D4
#elif GEX_PLAT_F103_BLUEPILL #elif GEX_PLAT_F103_BLUEPILL
#error "NO IMPL" #error "NO IMPL"
#elif GEX_PLAT_F303_DISCOVERY #elif GEX_PLAT_F303_DISCOVERY
@@ -114,30 +114,28 @@ void USPI_writeIni(Unit *unit, IniWriter *iw)
#else #else
#error "BAD PLATFORM!" #error "BAD PLATFORM!"
#endif #endif
iw_entry(iw, "remap", "%d", (int)priv->remap); iw_entry_d(iw, "remap", priv->remap);
iw_cmt_newline(iw); iw_cmt_newline(iw);
iw_comment(iw, "Prescaller: 2,4,8,...,256"); iw_comment(iw, "Prescaller: 2,4,8,...,256");
iw_entry(iw, "prescaller", "%d", (int)priv->prescaller); iw_entry_d(iw, "prescaller", priv->prescaller);
iw_comment(iw, "Clock polarity: 0,1 (clock idle level)"); iw_comment(iw, "Clock polarity: 0,1 (clock idle level)");
iw_entry(iw, "cpol", "%d", (int)priv->cpol); iw_entry_d(iw, "cpol", priv->cpol);
iw_comment(iw, "Clock phase: 0,1 (active edge, 0-first, 1-second)"); iw_comment(iw, "Clock phase: 0,1 (active edge, 0-first, 1-second)");
iw_entry(iw, "cpha", "%d", (int)priv->cpha); iw_entry_d(iw, "cpha", priv->cpha);
iw_comment(iw, "Transmit only, disable MISO"); iw_comment(iw, "Transmit only, disable MISO");
iw_entry(iw, "tx-only", str_yn(priv->tx_only)); iw_entry_s(iw, "tx-only", str_yn(priv->tx_only));
iw_comment(iw, "Bit order (LSB or MSB first)"); iw_comment(iw, "Bit order (LSB or MSB first)");
iw_entry(iw, "first-bit", str_2((uint32_t)priv->lsb_first, iw_entry_s(iw, "first-bit", cfg_enum2_encode((uint32_t) priv->lsb_first, 0, "MSB", 1, "LSB"));
0, "MSB",
1, "LSB"));
iw_cmt_newline(iw); iw_cmt_newline(iw);
iw_comment(iw, "SS port name"); iw_comment(iw, "SS port name");
iw_entry(iw, "port", "%c", priv->ssn_port_name); iw_entry(iw, "port", "%c", priv->ssn_port_name);
iw_comment(iw, "SS pins (comma separated, supports ranges)"); iw_comment(iw, "SS pins (comma separated, supports ranges)");
iw_entry(iw, "pins", "%s", pinmask2str(priv->ssn_pins, unit_tmp512)); iw_entry_s(iw, "pins", cfg_pinmask_encode(priv->ssn_pins, unit_tmp512, 0));
} }
+2 -2
View File
@@ -15,7 +15,7 @@
// SPI master // SPI master
enum PinCmd_ { enum PinCmd_ {
CMD_TEST = 0, CMD_QUERY = 0,
CMD_MULTICAST = 1, CMD_MULTICAST = 1,
}; };
@@ -33,7 +33,7 @@ static error_t USPI_handleRequest(Unit *unit, TF_ID frame_id, uint8_t command, P
switch (command) { switch (command) {
/** Write and read byte(s) - slave_num:u8, req_len:u16, resp_skip:u16, resp_len:u16, byte(s) */ /** Write and read byte(s) - slave_num:u8, req_len:u16, resp_skip:u16, resp_len:u16, byte(s) */
case CMD_TEST: case CMD_QUERY:
slave = pp_u8(pp); slave = pp_u8(pp);
resp_skip = pp_u16(pp); resp_skip = pp_u16(pp);
resp_len = pp_u16(pp); resp_len = pp_u16(pp);
+23
View File
@@ -0,0 +1,23 @@
#!/bin/bash
echo "Enter unit type identifier (empty to cancel):"
read x
if [ -e $x ]; then
exit;
fi
xl="${x,,}"
xu="${x^^}"
for f in *.h; do mv -- "$f" "${f//tpl/$xl}"; done
for f in *.c; do mv -- "$f" "${f//tpl/$xl}"; done
sed "s/tpl/$xl/" -i *.h
sed "s/TPL/$xu/" -i *.h
sed "s/tpl/$xl/" -i *.c
sed "s/TPL/$xu/" -i *.c
echo "Unit $xu set up completed. Removing installer.."
rm '!README.TXT'
rm $0
+11
View File
@@ -0,0 +1,11 @@
//
// Created by MightyPork on 2018/02/03.
//
#include "platform.h"
#include "unit_base.h"
#include "unit_touch.h"
#define TOUCH_INTERNAL
#include "_touch_internal.h"
+217
View File
@@ -0,0 +1,217 @@
//
// Created by MightyPork on 2018/02/25.
//
#include "platform.h"
#include "unit_base.h"
#include "unit_touch.h"
#define TOUCH_INTERNAL
#include "_touch_internal.h"
// discharge time in ms
#define DIS_TIME 1
static void startNextPhase(Unit *unit);
static void UTOUCH_EventReportJob(Job *job)
{
Unit *unit = job->unit;
struct priv *priv = unit->data;
uint8_t buf[8];
PayloadBuilder pb = pb_start(buf, 8, NULL);
pb_u32(&pb, pinmask_pack_32(~job->data1, priv->all_channels_mask)); // inverted and packed - all pins (pressed state)
pb_u32(&pb, pinmask_pack_32(job->data2, priv->all_channels_mask)); // trigger generating pins
assert_param(pb.ok);
EventReport er = {
.unit = unit,
.type = 0x00,
.length = 8,
.data = buf,
.timestamp = job->timestamp,
};
EventReport_Send(&er);
}
static void UTOUCH_CheckForBinaryEvents(Unit *const unit)
{
struct priv *priv = unit->data;
const uint32_t time_ms = PTIM_GetTime();
if (priv->last_done_ms == 0) {
// avoid bug with trigger on first capture
priv->last_done_ms = time_ms;
}
const uint64_t ts = PTIM_GetMicrotime();
uint32_t eventpins = 0;
const uint16_t ms_elapsed = (uint16_t) (time_ms - priv->last_done_ms);
for (uint16_t i = 0; i < 32; i++) {
const uint32_t poke = (uint32_t) (1 << i);
if (0 == (priv->all_channels_mask & poke)) continue;
if (priv->binary_thr[i] == 0) continue; // skip disabled channels
const bool isactive = (bool) (priv->binary_active_bits & poke);
const bool can_go_up = !isactive && (priv->readouts[i] > (priv->binary_thr[i] + priv->binary_hysteresis));
const bool can_go_down = isactive && (priv->readouts[i] < priv->binary_thr[i]);
if (can_go_up) {
priv->bin_trig_cnt[i] += ms_elapsed;
if (priv->bin_trig_cnt[i] >= priv->binary_debounce_ms) {
priv->binary_active_bits |= poke;
priv->bin_trig_cnt[i] = 0; // reset for the other direction of the switch
eventpins |= poke;
}
}
else if (priv->bin_trig_cnt[i] > 0) {
priv->bin_trig_cnt[i] = 0;
}
if (can_go_down) {
priv->bin_trig_cnt[i] -= ms_elapsed;
if (priv->bin_trig_cnt[i] <= -priv->binary_debounce_ms) {
priv->binary_active_bits &= ~poke;
priv->bin_trig_cnt[i] = 0; // reset for the other direction of the switch
eventpins |= poke;
}
}
else if (priv->bin_trig_cnt[i] < 0) {
priv->bin_trig_cnt[i] = 0;
}
}
if (eventpins != 0) {
Job j = {
.timestamp = ts,
.data1 = priv->binary_active_bits,
.data2 = eventpins,
.unit = unit,
.cb = UTOUCH_EventReportJob,
};
scheduleJob(&j);
}
priv->last_done_ms = time_ms;
}
void UTOUCH_HandleIrq(void *arg)
{
Unit *unit = arg;
struct priv *priv = unit->data;
if (TSC->ISR & TSC_ISR_MCEF) {
priv->status = UTSC_STATUS_FAIL;
dbg_touch("TSC Failure.");
TSC->ICR = TSC_ICR_EOAIC | TSC_ICR_MCEIC;
}
if (TSC->ISR & TSC_ISR_EOAF) {
TSC->ICR = TSC_ICR_EOAIC;
// assert_param((TSC->IOGCSR>>16) == priv->groups_phase[priv->next_phase]);
// Store captured data
const uint32_t chmask = TSC->IOCCR;
for (int i = 0; i < 32; i++) {
if (chmask & (1<<i)) {
priv->readouts[i] = (uint16_t) (TSC->IOGXCR[i >> 2] & 0x3FFF);
}
}
priv->next_phase++;
if (!priv->cfg.interlaced) {
// check if we've run out of existing or populated groups
if (priv->next_phase == 3 || priv->groups_phase[priv->next_phase] == 0) {
priv->next_phase = 0;
priv->status = UTSC_STATUS_READY;
UTOUCH_CheckForBinaryEvents(unit);
}
}
TSC->CR &= ~TSC_CR_IODEF; // pull low - discharge
}
priv->ongoing = false;
priv->discharge_delay = DIS_TIME;
}
#if TSC_DEBUG
static volatile uint32_t xcnt=0;
#endif
void UTOUCH_updateTick(Unit *unit)
{
#if TSC_DEBUG
xcnt++;
#endif
struct priv *priv = unit->data;
if (priv->ongoing) {
return;
}
if (priv->discharge_delay > 0) {
priv->discharge_delay--;
} else {
startNextPhase(unit);
}
#if TSC_DEBUG
if(xcnt >= 250) {
xcnt=0;
PRINTF("> ");
for (int i = 0; i < 32; i++) {
if (priv->all_channels_mask & (1<<i)) {
PRINTF("%d ", (int)priv->readouts[i]);
}
}
PRINTF("\r\n");
}
#endif
}
static void startNextPhase(Unit *unit)
{
struct priv *priv = unit->data;
if (priv->all_channels_mask == 0) return;
if (priv->cfg.interlaced) {
// Find the next non-zero bit, wrap around if needed
while ((priv->all_channels_mask & (1<<priv->next_phase))==0) {
priv->next_phase++;
if (priv->next_phase == 32) {
priv->next_phase = 0;
priv->status = UTSC_STATUS_READY;
UTOUCH_CheckForBinaryEvents(unit);
}
}
TSC->IOGCSR = (uint32_t) (1 << (priv->next_phase >> 2)); // phase divided by 4
TSC->IOCCR = (uint32_t) (1 << priv->next_phase);
// interlaced - float neighbouring electrodes
TSC->CR |= TSC_CR_IODEF;
} else {
TSC->IOGCSR = priv->groups_phase[priv->next_phase];
TSC->IOCCR = priv->channels_phase[priv->next_phase];
// separate - keep neighbouring electrodes at GND
}
TSC->ICR = TSC_ICR_EOAIC | TSC_ICR_MCEIC;
// Go!
priv->ongoing = true;
TSC->CR |= TSC_CR_START;
}
+221
View File
@@ -0,0 +1,221 @@
//
// Created by MightyPork on 2018/02/03.
//
#include "platform.h"
#include "unit_base.h"
#define TOUCH_INTERNAL
#include "_touch_internal.h"
/** Allocate data structure and set defaults */
error_t UTOUCH_preInit(Unit *unit)
{
struct priv *priv = unit->data = calloc_ck(1, sizeof(struct priv));
if (priv == NULL) return E_OUT_OF_MEM;
priv->cfg.charge_time = 2;
priv->cfg.drain_time = 2;
priv->cfg.spread_deviation = 0;
priv->cfg.ss_presc = 1;
priv->cfg.pg_presc = 32;
priv->cfg.sense_timeout = 7;
memset(priv->cfg.group_scaps, 0, 8);
memset(priv->cfg.group_channels, 0, 8);
priv->cfg.binary_hysteresis = 10;
priv->cfg.binary_debounce_ms = 20;
return E_SUCCESS;
}
/** Finalize unit set-up */
error_t UTOUCH_init(Unit *unit)
{
bool suc = true;
struct priv *priv = unit->data;
unit->tick_interval = 1; // sample every 1 ms
// copy from conf
priv->binary_debounce_ms = priv->cfg.binary_debounce_ms;
priv->binary_hysteresis = priv->cfg.binary_hysteresis;
TRY(rsc_claim(unit, R_TSC));
// simple bound checks, just clamp without error
if (priv->cfg.charge_time > 16) priv->cfg.charge_time = 16;
if (priv->cfg.charge_time < 1) priv->cfg.charge_time = 1;
if (priv->cfg.drain_time > 16) priv->cfg.drain_time = 16;
if (priv->cfg.drain_time < 1) priv->cfg.drain_time = 1;
if (priv->cfg.spread_deviation > 128) priv->cfg.drain_time = 128;
if (priv->cfg.ss_presc > 2) priv->cfg.ss_presc = 2;
if (priv->cfg.ss_presc < 1) priv->cfg.ss_presc = 1;
if (priv->cfg.sense_timeout > 7) priv->cfg.sense_timeout = 7;
if (priv->cfg.sense_timeout < 1) priv->cfg.sense_timeout = 1;
uint8_t tmppgpresc = priv->cfg.pg_presc;
if (tmppgpresc == 0) return E_BAD_CONFIG;
uint8_t pgpresc_reg = 0;
while ((tmppgpresc & 1) == 0 && tmppgpresc != 0) {
pgpresc_reg++;
tmppgpresc >>= 1;
}
if (tmppgpresc != 1 || pgpresc_reg > 7) {
dbg("Bad pgpresc");
return E_BAD_CONFIG; // TODO better reporting
}
if ((pgpresc_reg==0 && priv->cfg.drain_time<=2) || (pgpresc_reg==1 && priv->cfg.drain_time==0)) {
dbg("Illegal PGPSC vs CTPL");
return E_BAD_CONFIG;
}
// enable clock
hw_periph_clock_enable(TSC);
// reset
__HAL_RCC_TSC_FORCE_RESET();
__HAL_RCC_TSC_RELEASE_RESET();
priv->all_channels_mask = 0;
for (int gi = 0; gi < 8; gi++) {
const uint8_t cap = priv->cfg.group_scaps[gi];
const uint8_t ch = priv->cfg.group_channels[gi];
if (cap == 0) {
if (ch != 0) {
dbg_touch("TSC group %d has no cap!", (int) (gi + 1));
return E_BAD_CONFIG;
}
continue;
}
if (ch == 0) continue; // if no channels, don't bother setting up anything
if (cap != 2 && cap != 4 && cap != 8 && cap != 16) {
dbg_touch("TSC group %d has more than 1 cap!", (int) (gi + 1));
return E_BAD_CONFIG;
}
if (cap & ch) {
dbg_touch("TSC pin can't be both channel and cap! (gpr %d)", (int) (gi + 1));
return E_BAD_CONFIG;
}
// This is a loop through the pins in a group gi
int phasenum = 0;
for (int pi = 0; pi < 4; pi++) {
// pin numbers are 1-based in the config
const bool iscap = 0 != (cap & (2 << pi));
const bool isch = 0 != (ch & (2 << pi));
if (!iscap && !isch) continue;
Resource r = utouch_group_rscs[gi][pi];
TRY(rsc_claim(unit, r));
GPIO_TypeDef *port;
uint32_t ll;
assert_param(hw_pinrsc2ll(r, &port, &ll));
LL_GPIO_SetPinOutputType(port, ll, isch ? LL_GPIO_OUTPUT_PUSHPULL : LL_GPIO_OUTPUT_OPENDRAIN);
// 7 and 8 (1-based) use AF1, else AF3
TRY(hw_configure_gpiorsc_af(r, gi >= 6 ? LL_GPIO_AF_1 : LL_GPIO_AF_3));
uint32_t bit = (uint32_t) (1 << (gi * 4 + pi));
if (iscap) {
dbg_touch("TSC cap @ %s", rsc_get_name(r));
// Sampling cap
TSC->IOSCR |= bit;
// Disable pin hysteresis (causes noise)
TSC->IOHCR ^= bit;
}
else {
dbg_touch("TSC ch @ %s", rsc_get_name(r));
if (priv->cfg.interlaced) {
// interlaced - only update the mask beforehand
priv->all_channels_mask |= bit;
} else {
// channels are configured individually when read.
// we prepare bitmaps to use for the read groups (all can be read in at most 3 steps)
priv->channels_phase[phasenum] |= bit; // this is used for the channel selection register
priv->groups_phase[phasenum] |= 1 << gi; // this will be used for the group enable register, if all 0, this and any following phases are unused.
phasenum++;
}
}
}
}
// common TSC config
TSC->CR =
((priv->cfg.charge_time - 1) << TSC_CR_CTPH_Pos) |
((priv->cfg.drain_time - 1) << TSC_CR_CTPL_Pos) |
((priv->cfg.ss_presc - 1) << TSC_CR_SSPSC_Pos) |
(pgpresc_reg << TSC_CR_PGPSC_Pos) |
((priv->cfg.sense_timeout - 1) << TSC_CR_MCV_Pos) |
TSC_CR_TSCE;
if (priv->cfg.spread_deviation > 0) {
TSC->CR |= ((priv->cfg.spread_deviation - 1) << TSC_CR_SSD_Pos) | TSC_CR_SSE;
}
dbg_touch("CR = %08x, ht is %d, lt is %d", (int)TSC->CR,
(int)priv->cfg.charge_time,
(int)priv->cfg.drain_time);
// iofloat is used for discharging
// Enable the interrupts
TSC->IER = TSC_IER_EOAIE | TSC_IER_MCEIE;
irqd_attach(TSC, UTOUCH_HandleIrq, unit);
if (!priv->cfg.interlaced) {
dbg_touch("TSC phases:");
for (int i = 0; i < 3; i++) {
priv->all_channels_mask |= priv->channels_phase[i];
dbg_touch(" %d: ch %08"PRIx32", g %02"PRIx32,
i + 1,
priv->channels_phase[i],
(uint32_t) priv->groups_phase[i]);
}
}
priv->status = UTSC_STATUS_BUSY; // first loop ...
priv->next_phase = 0;
// starts in the tick callback
return E_SUCCESS;
}
/** Tear down the unit */
void UTOUCH_deInit(Unit *unit)
{
struct priv *priv = unit->data;
// de-init peripherals
if (unit->status == E_SUCCESS) {
hw_periph_clock_disable(TSC);
// clear all registers to their default values
__HAL_RCC_TSC_FORCE_RESET();
__HAL_RCC_TSC_RELEASE_RESET();
irqd_detach(TSC, UTOUCH_HandleIrq);
}
// Release all resources, deinit pins
rsc_teardown(unit);
// Free memory
free_ck(unit->data);
}
+95
View File
@@ -0,0 +1,95 @@
//
// Created by MightyPork on 2018/02/03.
//
#ifndef GEX_F072_TOUCH_INTERNAL_H
#define GEX_F072_TOUCH_INTERNAL_H
#ifndef TOUCH_INTERNAL
#error bad include!
#endif
#include "unit_base.h"
#define TSC_DEBUG 0
#if TSC_DEBUG
#define dbg_touch(f,...) dbg(f,##__VA_ARGS__)
#else
#define dbg_touch(f,...) do{}while(0)
#endif
enum utsc_status {
UTSC_STATUS_BUSY = 0,
UTSC_STATUS_READY = 1,
UTSC_STATUS_FAIL = 2
};
/** Private data structure */
struct priv {
// settings
struct {
uint8_t charge_time; // 1-16 -> 0..15
uint8_t drain_time; // 1-16 -> 0..15
uint8_t spread_deviation; // 1-128, 0=off ... 0-127, 0 sets 0 to SSE
uint8_t ss_presc; // 1-2 -> 0..1
uint8_t pg_presc; // 1,2,4,8,16,32,64,128 -> 0..7 when writing to the periph
uint8_t sense_timeout; // 1-7 -> 0..6 hex when writing to the periph
// the schmitts must be disabled on all used channels, restored to 0xFFFF on deinit
uint8_t group_scaps[8];
uint8_t group_channels[8];
bool interlaced;
uint16_t binary_debounce_ms;
uint16_t binary_hysteresis;
} cfg;
uint8_t next_phase;
uint8_t discharge_delay;
uint32_t channels_phase[3];
uint8_t groups_phase[3];
uint16_t readouts[32];
int16_t bin_trig_cnt[32];
uint16_t binary_debounce_ms;
uint16_t binary_hysteresis;
uint16_t binary_thr[32];
uint32_t binary_active_bits;
uint32_t all_channels_mask;
uint32_t last_done_ms;
bool ongoing;
enum utsc_status status;
} __attribute__((packed));
extern const char *utouch_group_labels[8];
extern const Resource utouch_group_rscs[8][4];
/** Allocate data structure and set defaults */
error_t UTOUCH_preInit(Unit *unit);
/** Load from a binary buffer stored in Flash */
void UTOUCH_loadBinary(Unit *unit, PayloadParser *pp);
/** Write to a binary buffer for storing in Flash */
void UTOUCH_writeBinary(Unit *unit, PayloadBuilder *pb);
// ------------------------------------------------------------------------
/** Parse a key-value pair from the INI file */
error_t UTOUCH_loadIni(Unit *unit, const char *key, const char *value);
/** Generate INI file section for the unit */
void UTOUCH_writeIni(Unit *unit, IniWriter *iw);
// ------------------------------------------------------------------------
/** Finalize unit set-up */
error_t UTOUCH_init(Unit *unit);
/** Tear down the unit */
void UTOUCH_deInit(Unit *unit);
void UTOUCH_updateTick(Unit *unit);
void UTOUCH_HandleIrq(void *arg);
#endif //GEX_F072_TOUCH_INTERNAL_H
+187
View File
@@ -0,0 +1,187 @@
//
// Created by MightyPork on 2018/02/03.
//
#include "platform.h"
#include "unit_base.h"
#define TOUCH_INTERNAL
#include "_touch_internal.h"
const char *utouch_group_labels[8] = {
"1:A0, 2:A1, 3:A2, 4:A3",
"1:A4, 2:A5, 3:A6, 4:A7",
"1:C5, 2:B0, 3:B1, 4:B2",
"1:A9, 2:A10, 3:A11, 4:A12",
"1:B3, 2:B4, 3:B6, 4:B7",
"1:B11, 2:B12, 3:B13, 4:B14",
"1:E2, 2:E3, 3:E4, 4:E5",
"1:D12, 2:D13, 3:D14, 4:D15",
};
const Resource utouch_group_rscs[8][4] = {
{R_PA0, R_PA1, R_PA2, R_PA3},
{R_PA4, R_PA5, R_PA6, R_PA7},
{R_PC5, R_PB0, R_PB1, R_PB2},
{R_PA9, R_PA10, R_PA11, R_PA12},
{R_PB3, R_PB4, R_PB6, R_PB7},
{R_PB11, R_PB12, R_PB13, R_PB14},
{R_PE2, R_PE3, R_PE4, R_PE5},
{R_PD12, R_PD13, R_PD14, R_PD15},
};
/** Load from a binary buffer stored in Flash */
void UTOUCH_loadBinary(Unit *unit, PayloadParser *pp)
{
struct priv *priv = unit->data;
uint8_t version = pp_u8(pp);
(void)version;
priv->cfg.charge_time = pp_u8(pp);
priv->cfg.drain_time = pp_u8(pp);
priv->cfg.spread_deviation = pp_u8(pp);
priv->cfg.ss_presc = pp_u8(pp);
priv->cfg.pg_presc = pp_u8(pp);
priv->cfg.sense_timeout = pp_u8(pp);
pp_buf(pp, priv->cfg.group_scaps, 8);
pp_buf(pp, priv->cfg.group_channels, 8);
if (version >= 1) {
priv->cfg.interlaced = pp_bool(pp);
}
if (version >= 2) {
priv->cfg.binary_debounce_ms = pp_u16(pp);
priv->cfg.binary_hysteresis = pp_u16(pp);
}
}
/** Write to a binary buffer for storing in Flash */
void UTOUCH_writeBinary(Unit *unit, PayloadBuilder *pb)
{
struct priv *priv = unit->data;
pb_u8(pb, 2); // version
pb_u8(pb, priv->cfg.charge_time);
pb_u8(pb, priv->cfg.drain_time);
pb_u8(pb, priv->cfg.spread_deviation);
pb_u8(pb, priv->cfg.ss_presc);
pb_u8(pb, priv->cfg.pg_presc);
pb_u8(pb, priv->cfg.sense_timeout);
pb_buf(pb, priv->cfg.group_scaps, 8);
pb_buf(pb, priv->cfg.group_channels, 8);
pb_bool(pb, priv->cfg.interlaced);
pb_u16(pb, priv->cfg.binary_debounce_ms);
pb_u16(pb, priv->cfg.binary_hysteresis);
}
// ------------------------------------------------------------------------
/** Parse a key-value pair from the INI file */
error_t UTOUCH_loadIni(Unit *unit, const char *key, const char *value)
{
bool suc = true;
struct priv *priv = unit->data;
if (streq(key, "charge-time")) {
priv->cfg.charge_time = cfg_u8_parse(value, &suc);
}
else if (streq(key, "drain-time")) {
priv->cfg.drain_time = cfg_u8_parse(value, &suc);
}
else if (streq(key, "ss-deviation")) {
priv->cfg.spread_deviation = cfg_u8_parse(value, &suc);
}
else if (streq(key, "ss-clock-prediv")) {
priv->cfg.ss_presc = cfg_u8_parse(value, &suc);
}
else if (streq(key, "pg-clock-prediv")) {
priv->cfg.pg_presc = cfg_u8_parse(value, &suc);
}
else if (streq(key, "sense-timeout")) {
priv->cfg.sense_timeout = cfg_u8_parse(value, &suc);
}
else if (streq(key, "interlaced-pads")) {
priv->cfg.interlaced = cfg_bool_parse(value, &suc);
}
else if (streq(key, "btn-debounce")) {
priv->cfg.binary_debounce_ms = cfg_u16_parse(value, &suc);
}
else if (streq(key, "btn-hysteresis")) {
priv->cfg.binary_hysteresis = cfg_u16_parse(value, &suc);
}
else {
volatile char namebuf[10]; // must be volatile or gcc optimizes out the second compare and fucks it up
for (int i = 0; i < 6; i++) { // skip 7,8
SPRINTF(namebuf, "g%d_cap", i+1);
if (streq(key, namebuf)) {
priv->cfg.group_scaps[i] = (uint8_t) cfg_pinmask_parse(value, &suc);
goto matched;
}
SPRINTF(namebuf, "g%d_ch", i+1);
if (streq(key, namebuf)) {
priv->cfg.group_channels[i] = (uint8_t) cfg_pinmask_parse(value, &suc);
goto matched;
}
}
return E_BAD_KEY;
}
matched:
if (!suc) return E_BAD_VALUE;
return E_SUCCESS;
}
/** Generate INI file section for the unit */
void UTOUCH_writeIni(Unit *unit, IniWriter *iw)
{
struct priv *priv = unit->data;
iw_comment(iw, "This unit utilizes the touch sensing controller.");
iw_comment(iw, "See the reference manual for details about its function.");
iw_cmt_newline(iw);
iw_comment(iw, "Pulse generator clock prescaller (1,2,4,...,128)");
iw_entry_d(iw, "pg-clock-prediv", priv->cfg.pg_presc);
iw_comment(iw, "Sense pad charging time (1-16)");
iw_entry_d(iw, "charge-time", priv->cfg.charge_time);
iw_comment(iw, "Charge transfer time (1-16)");
iw_entry_d(iw, "drain-time", priv->cfg.drain_time);
iw_comment(iw, "Measurement timeout (1-7)");
iw_entry_d(iw, "sense-timeout", priv->cfg.sense_timeout);
iw_cmt_newline(iw);
iw_comment(iw, "Spread spectrum max deviation (0-128,0=off)");
iw_entry_d(iw, "ss-deviation", priv->cfg.spread_deviation);
iw_comment(iw, "Spreading clock prescaller (1,2)");
iw_entry_d(iw, "ss-clock-prediv", priv->cfg.ss_presc);
iw_cmt_newline(iw);
iw_comment(iw, "Optimize for interlaced pads (individual sampling with others floating)");
iw_entry_s(iw, "interlaced-pads", str_yn(priv->cfg.interlaced));
iw_cmt_newline(iw);
iw_comment(iw, "Button mode debounce (ms) and release hysteresis (lsb)");
iw_entry_d(iw, "btn-debounce", priv->cfg.binary_debounce_ms);
iw_entry_d(iw, "btn-hysteresis", priv->cfg.binary_hysteresis);
iw_cmt_newline(iw);
iw_comment(iw, "Each used group must have 1 sampling capacitor and 1-3 channels.");
iw_comment(iw, "Channels are numbered 1,2,3,4");
iw_cmt_newline(iw);
char namebuf[10];
for (int i = 0; i < 6; i++) { // skip 7,8
iw_commentf(iw, "Group%d - %s", i+1, utouch_group_labels[i]);
SPRINTF(namebuf, "g%d_cap", i+1);
iw_entry_s(iw, namebuf, cfg_pinmask_encode(priv->cfg.group_scaps[i], unit_tmp512, true));
SPRINTF(namebuf, "g%d_ch", i+1);
iw_entry_s(iw, namebuf, cfg_pinmask_encode(priv->cfg.group_channels[i], unit_tmp512, true));
}
}
+136
View File
@@ -0,0 +1,136 @@
//
// Created by MightyPork on 2017/11/25.
//
#include "unit_base.h"
#include "unit_touch.h"
#define TOUCH_INTERNAL
#include "_touch_internal.h"
// ------------------------------------------------------------------------
enum TouchCmd_ {
CMD_READ=0,
CMD_SET_BIN_THR=1,
CMD_DISABLE_ALL_REPORTS=2,
CMD_SET_DEBOUNCE_TIME=3,
CMD_SET_HYSTERESIS=4,
CMD_GET_CH_COUNT=10,
};
/** Handle a request message */
static error_t UTOUCH_handleRequest(Unit *unit, TF_ID frame_id, uint8_t command, PayloadParser *pp)
{
struct priv* priv = unit->data;
PayloadBuilder pb = pb_start(unit_tmp512, UNIT_TMP_LEN, NULL);
switch (command) {
/**
* read the current touch pad values (smaller = higher capacity)
*
* resp: a list of u16 (order: group and pin, ascending)
*/
case CMD_READ:
if (priv->status == UTSC_STATUS_BUSY) return E_BUSY;
if (priv->status == UTSC_STATUS_FAIL) return E_HW_TIMEOUT;
for (int i = 0; i < 32; i++) {
if (priv->all_channels_mask & (1<<i)) {
pb_u16(&pb, priv->readouts[i]);
}
}
com_respond_pb(frame_id, MSG_SUCCESS, &pb);
return E_SUCCESS;
/**
* Set thresholds for the button mode.
*
* pld: a list of u16 for the enabled channels (order: group and pin, ascending)
*/
case CMD_SET_BIN_THR:
for (int i = 0; i < 32; i++) {
if (priv->all_channels_mask & (1<<i)) {
priv->bin_trig_cnt[i] = 0;
priv->binary_thr[i] = pp_u16(pp);
if (priv->readouts[i] >= (priv->binary_thr[i] + priv->binary_hysteresis)) {
priv->binary_active_bits |= 1<<i;
}
}
}
return E_SUCCESS;
/**
* Set the debounce time in ms (replaces the default value from settings)
*
* pld: ms:u16
*/
case CMD_SET_DEBOUNCE_TIME:
priv->binary_debounce_ms = pp_u16(pp);
return E_SUCCESS;
/**
* Set hysteresis (replaces the default value from settings)
*
* Hysteresis is added to the threshold value for the switch-off level
* (switch-off happens when the measured value is exceeded - capacity of the pad drops)
*
* pld: hyst:u16
*/
case CMD_SET_HYSTERESIS:
priv->binary_hysteresis = pp_u16(pp);
return E_SUCCESS;
/**
* Disable button mode reports. This effectively sets all thresholds to 0, disabling checking.
*/
case CMD_DISABLE_ALL_REPORTS:
for (int i = 0; i < 32; i++) {
if (priv->all_channels_mask & (1<<i)) {
priv->binary_thr[i] = 0;
priv->bin_trig_cnt[i] = 0;
}
}
priv->binary_active_bits = 0;
return E_SUCCESS;
/**
* Get the number of configured touch pad channels
*
* resp: count:u8
*/
case CMD_GET_CH_COUNT:;
uint8_t nb = 0;
for (int i = 0; i < 32; i++) {
if (priv->all_channels_mask & (1<<i)) {
nb++;
}
}
pb_u8(&pb, nb);
com_respond_pb(frame_id, MSG_SUCCESS, &pb);
return E_SUCCESS;
default:
return E_UNKNOWN_COMMAND;
}
}
// ------------------------------------------------------------------------
/** Unit template */
const UnitDriver UNIT_TOUCH = {
.name = "TOUCH",
.description = "Capacitive touch sensing",
// Settings
.preInit = UTOUCH_preInit,
.cfgLoadBinary = UTOUCH_loadBinary,
.cfgWriteBinary = UTOUCH_writeBinary,
.cfgLoadIni = UTOUCH_loadIni,
.cfgWriteIni = UTOUCH_writeIni,
// Init
.init = UTOUCH_init,
.deInit = UTOUCH_deInit,
// Function
.handleRequest = UTOUCH_handleRequest,
.updateTick = UTOUCH_updateTick,
};
+16
View File
@@ -0,0 +1,16 @@
//
// Created by MightyPork on 2017/11/25.
//
// Digital input unit; single or multiple pin read access on one port (A-F)
//
#ifndef U_TOUCH_H
#define U_TOUCH_H
#include "unit.h"
extern const UnitDriver UNIT_TOUCH;
// UU_ prototypes
#endif //U_TOUCH_H
+1 -1
View File
@@ -111,7 +111,7 @@ static inline error_t UUSART_configPins(Unit *unit)
want_rts_pin(priv) want_rts_pin(priv)
}; };
#if GEX_PLAT_F072_DISCOVERY #if STM32F072xB
const struct PinAF *mappings = NULL; const struct PinAF *mappings = NULL;
+36 -36
View File
@@ -81,66 +81,66 @@ error_t UUSART_loadIni(Unit *unit, const char *key, const char *value)
struct priv *priv = unit->data; struct priv *priv = unit->data;
if (streq(key, "device")) { if (streq(key, "device")) {
priv->periph_num = (uint8_t) avr_atoi(value); priv->periph_num = cfg_u8_parse(value, &suc);
} }
else if (streq(key, "remap")) { else if (streq(key, "remap")) {
priv->remap = (uint8_t) avr_atoi(value); priv->remap = cfg_u8_parse(value, &suc);
} }
else if (streq(key, "baud-rate")) { else if (streq(key, "baud-rate")) {
priv->baudrate = (uint32_t ) avr_atoi(value); priv->baudrate = cfg_u32_parse(value, &suc);
} }
else if (streq(key, "parity")) { else if (streq(key, "parity")) {
priv->parity = (uint8_t) str_parse_3(value, priv->parity = (uint8_t) cfg_enum3_parse(value,
"NONE", 0, "NONE", 0,
"ODD", 1, "ODD", 1,
"EVEN", 2, &suc); "EVEN", 2, &suc);
} }
else if (streq(key, "stop-bits")) { else if (streq(key, "stop-bits")) {
priv->stopbits = (uint8_t) str_parse_4(value, priv->stopbits = (uint8_t) cfg_enum4_parse(value,
"0.5", 0, "0.5", 0,
"1", 1, "1", 1,
"1.5", 2, "1.5", 2,
"2", 3, &suc); "2", 3, &suc);
} }
else if (streq(key, "direction")) { else if (streq(key, "direction")) {
priv->direction = (uint8_t) str_parse_3(value, priv->direction = (uint8_t) cfg_enum3_parse(value,
"RX", UUSART_DIRECTION_RX, "RX", UUSART_DIRECTION_RX,
"TX", UUSART_DIRECTION_TX, "TX", UUSART_DIRECTION_TX,
"RXTX", UUSART_DIRECTION_RXTX, &suc); "RXTX", UUSART_DIRECTION_RXTX, &suc);
} }
else if (streq(key, "hw-flow-control")) { else if (streq(key, "hw-flow-control")) {
priv->hw_flow_control = (uint8_t) str_parse_4(value, priv->hw_flow_control = (uint8_t) cfg_enum4_parse(value,
"NONE", 0, "NONE", 0,
"RTS", 1, "RTS", 1,
"CTS", 2, "CTS", 2,
"FULL", 3, &suc); "FULL", 3, &suc);
} }
else if (streq(key, "word-width")) { else if (streq(key, "word-width")) {
priv->width = (uint8_t ) avr_atoi(value); priv->width = cfg_u8_parse(value, &suc);
} }
else if (streq(key, "first-bit")) { else if (streq(key, "first-bit")) {
priv->lsb_first = (bool)str_parse_2(value, "MSB", 0, "LSB", 1, &suc); priv->lsb_first = (bool) cfg_enum2_parse(value, "MSB", 0, "LSB", 1, &suc);
} }
else if (streq(key, "clock-output")) { else if (streq(key, "clock-output")) {
priv->clock_output = str_parse_yn(value, &suc); priv->clock_output = cfg_bool_parse(value, &suc);
} }
else if (streq(key, "cpol")) { else if (streq(key, "cpol")) {
priv->cpol = (bool) avr_atoi(value); priv->cpol = cfg_bool_parse(value, &suc);
} }
else if (streq(key, "cpha")) { else if (streq(key, "cpha")) {
priv->cpha = (bool) avr_atoi(value); priv->cpha = cfg_bool_parse(value, &suc);
} }
else if (streq(key, "de-output")) { else if (streq(key, "de-output")) {
priv->de_output = str_parse_yn(value, &suc); priv->de_output = cfg_bool_parse(value, &suc);
} }
else if (streq(key, "de-polarity")) { else if (streq(key, "de-polarity")) {
priv->de_polarity = (bool) avr_atoi(value); priv->de_polarity = cfg_bool_parse(value, &suc);
} }
else if (streq(key, "de-assert-time")) { else if (streq(key, "de-assert-time")) {
priv->de_assert_time = (uint8_t) avr_atoi(value); priv->de_assert_time = cfg_u8_parse(value, &suc);
} }
else if (streq(key, "de-clear-time")) { else if (streq(key, "de-clear-time")) {
priv->de_clear_time = (uint8_t) avr_atoi(value); priv->de_clear_time = cfg_u8_parse(value, &suc);
} }
else { else {
return E_BAD_KEY; return E_BAD_KEY;
@@ -156,10 +156,10 @@ void UUSART_writeIni(Unit *unit, IniWriter *iw)
struct priv *priv = unit->data; struct priv *priv = unit->data;
iw_comment(iw, "Peripheral number (UARTx 1-4)"); iw_comment(iw, "Peripheral number (UARTx 1-4)");
iw_entry(iw, "device", "%d", (int)priv->periph_num); iw_entry_d(iw, "device", priv->periph_num);
iw_comment(iw, "Pin mappings (TX,RX,CK,CTS,RTS/DE)"); iw_comment(iw, "Pin mappings (TX,RX,CK,CTS,RTS/DE)");
#if GEX_PLAT_F072_DISCOVERY #if STM32F072xB
iw_comment(iw, " USART1: (0) A9,A10,A8,A11,A12 (1) B6,B7,A8,A11,A12"); iw_comment(iw, " USART1: (0) A9,A10,A8,A11,A12 (1) B6,B7,A8,A11,A12");
iw_comment(iw, " USART2: (0) A2,A3,A4,A0,A1 (1) A14,A15,A4,A0,A1"); iw_comment(iw, " USART2: (0) A2,A3,A4,A0,A1 (1) A14,A15,A4,A0,A1");
iw_comment(iw, " USART3: (0) B10,B11,B12,B13,B14"); iw_comment(iw, " USART3: (0) B10,B11,B12,B13,B14");
@@ -173,41 +173,41 @@ void UUSART_writeIni(Unit *unit, IniWriter *iw)
#else #else
#error "BAD PLATFORM!" #error "BAD PLATFORM!"
#endif #endif
iw_entry(iw, "remap", "%d", (int)priv->remap); iw_entry_d(iw, "remap", priv->remap);
iw_cmt_newline(iw); iw_cmt_newline(iw);
iw_comment(iw, "Baud rate in bps (eg. 9600, 115200)"); // TODO examples/range iw_comment(iw, "Baud rate in bps (eg. 9600)");
iw_entry(iw, "baud-rate", "%d", (int)priv->baudrate); iw_entry_d(iw, "baud-rate", priv->baudrate);
iw_comment(iw, "Parity type (NONE, ODD, EVEN)"); iw_comment(iw, "Parity type (NONE, ODD, EVEN)");
iw_entry(iw, "parity", "%s", str_3(priv->parity, iw_entry_s(iw, "parity", cfg_enum3_encode(priv->parity,
0, "NONE", 0, "NONE",
1, "ODD", 1, "ODD",
2, "EVEN")); 2, "EVEN"));
iw_comment(iw, "Number of stop bits (0.5, 1, 1.5, 2)"); iw_comment(iw, "Number of stop bits (0.5, 1, 1.5, 2)");
iw_entry(iw, "stop-bits", "%s", str_4(priv->stopbits, iw_entry_s(iw, "stop-bits", cfg_enum4_encode(priv->stopbits,
0, "0.5", 0, "0.5",
1, "1", 1, "1",
2, "1.5", 2, "1.5",
3, "2")); 3, "2"));
iw_comment(iw, "Bit order (LSB or MSB first)"); iw_comment(iw, "Bit order (LSB or MSB first)");
iw_entry(iw, "first-bit", str_2((uint32_t)priv->lsb_first, iw_entry_s(iw, "first-bit", cfg_enum2_encode((uint32_t) priv->lsb_first,
0, "MSB", 0, "MSB",
1, "LSB")); 1, "LSB"));
iw_comment(iw, "Word width (7,8,9) - including parity bit if used"); iw_comment(iw, "Word width (7,8,9) - including parity bit if used");
iw_entry(iw, "word-width", "%d", (int)priv->width); iw_entry_d(iw, "word-width", (int)priv->width);
iw_comment(iw, "Enabled lines (RX,TX,RXTX)"); iw_comment(iw, "Enabled lines (RX,TX,RXTX)");
iw_entry(iw, "direction", str_3(priv->direction, iw_entry_s(iw, "direction", cfg_enum3_encode(priv->direction,
1, "RX", 1, "RX",
2, "TX", 2, "TX",
3, "RXTX")); 3, "RXTX"));
iw_comment(iw, "Hardware flow control (NONE, RTS, CTS, FULL)"); iw_comment(iw, "Hardware flow control (NONE, RTS, CTS, FULL)");
iw_entry(iw, "hw-flow-control", "%s", str_4(priv->hw_flow_control, iw_entry_s(iw, "hw-flow-control", cfg_enum4_encode(priv->hw_flow_control,
0, "NONE", 0, "NONE",
1, "RTS", 1, "RTS",
2, "CTS", 2, "CTS",
@@ -215,19 +215,19 @@ void UUSART_writeIni(Unit *unit, IniWriter *iw)
iw_cmt_newline(iw); iw_cmt_newline(iw);
iw_comment(iw, "Generate serial clock (Y,N)"); iw_comment(iw, "Generate serial clock (Y,N)");
iw_entry(iw, "clock-output", str_yn(priv->clock_output)); iw_entry_s(iw, "clock-output", str_yn(priv->clock_output));
iw_comment(iw, "Output clock polarity: 0,1 (clock idle level)"); iw_comment(iw, "Clock polarity: 0,1");
iw_entry(iw, "cpol", "%d", (int)priv->cpol); iw_entry_d(iw, "cpol", priv->cpol);
iw_comment(iw, "Output clock phase: 0,1 (active edge, 0-first, 1-second)"); iw_comment(iw, "Clock phase: 0,1");
iw_entry(iw, "cpha", "%d", (int)priv->cpha); iw_entry_d(iw, "cpha", priv->cpha);
iw_cmt_newline(iw); iw_cmt_newline(iw);
iw_comment(iw, "Generate RS485 Driver Enable signal (Y,N) - uses RTS pin"); iw_comment(iw, "Generate RS485 Driver Enable signal (Y,N) - uses RTS pin");
iw_entry(iw, "de-output", str_yn(priv->de_output)); iw_entry_s(iw, "de-output", str_yn(priv->de_output));
iw_comment(iw, "DE active level: 0,1"); iw_comment(iw, "DE active level: 0,1");
iw_entry(iw, "de-polarity", "%d", (int)(priv->de_polarity)); iw_entry_d(iw, "de-polarity", (priv->de_polarity));
iw_comment(iw, "DE assert time (0-31)"); iw_comment(iw, "DE assert time (0-31)");
iw_entry(iw, "de-assert-time", "%d", (int)(priv->de_assert_time)); iw_entry_d(iw, "de-assert-time", (priv->de_assert_time));
iw_comment(iw, "DE clear time (0-31)"); iw_comment(iw, "DE clear time (0-31)");
iw_entry(iw, "de-clear-time", "%d", (int)(priv->de_clear_time)); iw_entry_d(iw, "de-clear-time", (priv->de_clear_time));
} }
+2 -2
View File
@@ -92,7 +92,7 @@ void UUSART_Tick(Unit *unit)
} }
enum PinCmd_ { enum PinCmd_ {
CMD_WRITE = 0, CMD_QUERY = 0,
CMD_WRITE_SYNC = 1, CMD_WRITE_SYNC = 1,
}; };
@@ -103,7 +103,7 @@ static error_t UUSART_handleRequest(Unit *unit, TF_ID frame_id, uint8_t command,
const uint8_t *pld; const uint8_t *pld;
switch (command) { switch (command) {
/** Write bytes to the USART. Payload consists of the data to send. Waits for completion. */ /** Write bytes to the USART. Payload consists of the data to send. Waits for completion. */
case CMD_WRITE: case CMD_QUERY:
pld = pp_tail(pp, &len); pld = pp_tail(pp, &len);
TRY(UU_USART_Write(unit, pld, len)); TRY(UU_USART_Write(unit, pld, len));
return E_SUCCESS; return E_SUCCESS;
-35
View File
@@ -1,35 +0,0 @@
/* Copyright (c) 2002, Marek Michalkiewicz
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
* Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in
the documentation and/or other materials provided with the
distribution.
* Neither the name of the copyright holders nor the names of
contributors may be used to endorse or promote products derived
from this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
POSSIBILITY OF SUCH DAMAGE. */
#include "avrlibc.h"
int
avr_atoi(const char *p)
{
return (int) avr_atol(p);
}
-36
View File
@@ -1,36 +0,0 @@
/* Copyright (c) 2002, Marek Michalkiewicz
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
* Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in
the documentation and/or other materials provided with the
distribution.
* Neither the name of the copyright holders nor the names of
contributors may be used to endorse or promote products derived
from this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
POSSIBILITY OF SUCH DAMAGE. */
#include <stdlib.h>
#include "avrlibc.h"
long
avr_atol(const char *p)
{
return avr_strtol(p, (char **) NULL, 10);
}
+10 -10
View File
@@ -37,10 +37,10 @@
#include <stdint.h> #include <stdint.h>
#include "avrlibc.h" #include "avrlibc.h"
/* Only GCC 4.2 calls the library function to convert an unsigned long /* Only GCC 4.2 calls the library function to convert an uint32_t
to float. Other GCC-es (including 4.3) use a signed long to float to float. Other GCC-es (including 4.3) use a signed long to float
conversion along with a large inline code to correct the result. */ conversion along with a large inline code to correct the result. */
extern double __floatunsisf (unsigned long); extern double __floatunsisf (uint32_t);
static const float pwr_p10 [6] = { static const float pwr_p10 [6] = {
1e+1, 1e+2, 1e+4, 1e+8, 1e+16, 1e+32 1e+1, 1e+2, 1e+4, 1e+8, 1e+16, 1e+32
@@ -84,13 +84,13 @@ double
avr_strtod (const char * nptr, char ** endptr) avr_strtod (const char * nptr, char ** endptr)
{ {
union { union {
unsigned long u32; uint32_t u32;
float flt; float flt;
} x; } x;
unsigned char c; char c;
int exp; int32_t exp;
unsigned char flag; uint8_t flag;
#define FL_MINUS 0x01 /* number is negative */ #define FL_MINUS 0x01 /* number is negative */
#define FL_ANY 0x02 /* any digit was readed */ #define FL_ANY 0x02 /* any digit was readed */
#define FL_OVFL 0x04 /* overflow was */ #define FL_OVFL 0x04 /* overflow was */
@@ -178,7 +178,7 @@ avr_strtod (const char * nptr, char ** endptr)
do { do {
if (i < 3200) if (i < 3200)
i = (((i << 2) + i) << 1) + c; /* i = 10*i + c */ i = (((i << 2) + i) << 1) + c; /* i = 10*i + c */
c = *nptr++ - '0'; c = (char) (*nptr++ - '0');
} while (c <= 9); } while (c <= 9);
if (flag & FL_MEXP) if (flag & FL_MEXP)
i = -i; i = -i;
@@ -189,7 +189,7 @@ avr_strtod (const char * nptr, char ** endptr)
if ((flag & FL_ANY) && endptr) if ((flag & FL_ANY) && endptr)
*endptr = (char *)nptr - 1; *endptr = (char *)nptr - 1;
x.flt = __floatunsisf (x.u32); /* manually */ x.flt = (float) __floatunsisf (x.u32); /* manually */
if ((flag & FL_MINUS) && (flag & FL_ANY)) if ((flag & FL_MINUS) && (flag & FL_ANY))
x.flt = -x.flt; x.flt = -x.flt;
@@ -204,7 +204,7 @@ avr_strtod (const char * nptr, char ** endptr)
for (pwr = 32; pwr; pwr >>= 1) { for (pwr = 32; pwr; pwr >>= 1) {
for (; exp >= pwr; exp -= pwr) { for (; exp >= pwr; exp -= pwr) {
union { union {
unsigned long u32; uint32_t u32;
float flt; float flt;
} y; } y;
y.u32 = (uint32_t) *((float *)nptr); y.u32 = (uint32_t) *((float *)nptr);
@@ -213,7 +213,7 @@ avr_strtod (const char * nptr, char ** endptr)
nptr -= sizeof(float); nptr -= sizeof(float);
} }
if (!isfinite(x.flt) || x.flt == 0) if (!isfinite(x.flt) || x.flt == 0)
errno = ERANGE; avrlibc_errno = ERANGE;
} }
return x.flt; return x.flt;
+19 -18
View File
@@ -32,6 +32,7 @@
#include <limits.h> #include <limits.h>
#include <errno.h> #include <errno.h>
#include "avrlibc.h"
/* /*
* Convert a string to a long integer. * Convert a string to a long integer.
@@ -39,14 +40,14 @@
* Ignores `locale' stuff. Assumes that the upper and lower case * Ignores `locale' stuff. Assumes that the upper and lower case
* alphabets and digits are each contiguous. * alphabets and digits are each contiguous.
*/ */
long int32_t
avr_strtol(const char *nptr, char **endptr, register int base) avr_strtol(const char *nptr, char **endptr, register int32_t base)
{ {
register unsigned long acc; register uint32_t acc;
register unsigned char c; register char c;
register unsigned long cutoff; register uint32_t cutoff;
register signed char any; register int8_t any;
unsigned char flag = 0; uint8_t flag = 0;
#define FL_NEG 0x01 /* number is negative */ #define FL_NEG 0x01 /* number is negative */
#define FL_0X 0x02 /* number has a 0x prefix */ #define FL_0X 0x02 /* number has a 0x prefix */
@@ -105,24 +106,24 @@ avr_strtol(const char *nptr, char **endptr, register int base)
* Set any if any `digits' consumed; make it negative to indicate * Set any if any `digits' consumed; make it negative to indicate
* overflow. * overflow.
*/ */
#if LONG_MIN != -LONG_MAX - 1 #if INT32_MIN != -INT32_MAX - 1
# error "This implementation of strtol() does not work on this platform." # error "This implementation of strtol() does not work on this platform."
#endif #endif
switch (base) { switch (base) {
case 10: case 10:
cutoff = ((unsigned long)LONG_MAX + 1) / 10; cutoff = ((uint32_t)INT32_MAX + 1) / 10;
break; break;
case 16: case 16:
cutoff = ((unsigned long)LONG_MAX + 1) / 16; cutoff = ((uint32_t)INT32_MAX + 1) / 16;
break; break;
case 8: case 8:
cutoff = ((unsigned long)LONG_MAX + 1) / 8; cutoff = ((uint32_t)INT32_MAX + 1) / 8;
break; break;
case 2: case 2:
cutoff = ((unsigned long)LONG_MAX + 1) / 2; cutoff = ((uint32_t)INT32_MAX + 1) / 2;
break; break;
default: default:
cutoff = ((unsigned long)LONG_MAX + 1) / base; cutoff = ((uint32_t)INT32_MAX + 1) / base;
} }
for (acc = 0, any = 0;; c = *nptr++) { for (acc = 0, any = 0;; c = *nptr++) {
@@ -143,7 +144,7 @@ avr_strtol(const char *nptr, char **endptr, register int base)
continue; continue;
} }
acc = acc * base + c; acc = acc * base + c;
if (acc > (unsigned long)LONG_MAX + 1) if (acc > (uint32_t)INT32_MAX + 1)
any = -1; any = -1;
else else
any = 1; any = 1;
@@ -155,13 +156,13 @@ avr_strtol(const char *nptr, char **endptr, register int base)
*endptr = (char *)nptr - 2; *endptr = (char *)nptr - 2;
} }
if (any < 0) { if (any < 0) {
acc = (flag & FL_NEG) ? LONG_MIN : LONG_MAX; acc = (flag & FL_NEG) ? INT32_MIN : INT32_MAX;
errno = ERANGE; avrlibc_errno = ERANGE;
} else if (flag & FL_NEG) { } else if (flag & FL_NEG) {
acc = -acc; acc = -acc;
} else if ((signed long)acc < 0) { } else if ((signed long)acc < 0) {
acc = LONG_MAX; acc = INT32_MAX;
errno = ERANGE; avrlibc_errno = ERANGE;
} }
return (acc); return (acc);
} }
+15 -15
View File
@@ -35,18 +35,18 @@
#include "avrlibc.h" #include "avrlibc.h"
/* /*
* Convert a string to an unsigned long integer. * Convert a string to an uint32_t integer.
* *
* Ignores `locale' stuff. Assumes that the upper and lower case * Ignores `locale' stuff. Assumes that the upper and lower case
* alphabets and digits are each contiguous. * alphabets and digits are each contiguous.
*/ */
unsigned long uint32_t
avr_strtoul(const char *nptr, char **endptr, register int base) avr_strtoul(const char *nptr, char **endptr, register int32_t base)
{ {
register unsigned long acc; register uint32_t acc;
register unsigned char c; register char c;
register unsigned long cutoff; register uint32_t cutoff;
register signed char any; register int8_t any;
unsigned char flag = 0; unsigned char flag = 0;
#define FL_NEG 0x01 /* number is negative */ #define FL_NEG 0x01 /* number is negative */
#define FL_0X 0x02 /* number has a 0x prefix */ #define FL_0X 0x02 /* number has a 0x prefix */
@@ -102,10 +102,10 @@ avr_strtoul(const char *nptr, char **endptr, register int base)
* *
*/ */
switch (base) { switch (base) {
case 16: cutoff = ULONG_MAX / 16; break; case 16: cutoff = UINT32_MAX / 16; break;
case 10: cutoff = ULONG_MAX / 10; break; case 10: cutoff = UINT32_MAX / 10; break;
case 8: cutoff = ULONG_MAX / 8; break; case 8: cutoff = UINT32_MAX / 8; break;
default: cutoff = ULONG_MAX / base; default: cutoff = UINT32_MAX / base;
} }
for (acc = 0, any = 0;; c = *nptr++) { for (acc = 0, any = 0;; c = *nptr++) {
@@ -126,7 +126,7 @@ avr_strtoul(const char *nptr, char **endptr, register int base)
continue; continue;
} }
acc = acc * base + c; acc = acc * base + c;
any = (c > acc) ? -1 : 1; any = (int8_t) ((c > acc) ? -1 : 1);
} }
if (endptr) { if (endptr) {
@@ -138,8 +138,8 @@ avr_strtoul(const char *nptr, char **endptr, register int base)
if (flag & FL_NEG) if (flag & FL_NEG)
acc = -acc; acc = -acc;
if (any < 0) { if (any < 0) {
acc = ULONG_MAX; acc = UINT32_MAX;
errno = ERANGE; avrlibc_errno = ERANGE;
} }
return (acc); return (uint32_t) (acc);
} }

Some files were not shown because too many files have changed in this diff Show More