/* * This is a dummy function, used as demonstration */ SFPResult dummyFunction(SFPFunction *msg) { /* Check for arg count */ if (SFPFunction_getArgumentCount(msg) != 1) return SFP_ERR_ARG_COUNT; /* Check for arg type */ if (SFPFunction_getArgumentType(msg, 0) != SFP_ARG_INT) return SFP_ERR_ARG_TYPE; /* Get the argument */ uint32_t dummyData = SFPFunction_getArgument_int32(msg, 0); /* Do some stupid things */ LPC_GPIO->DIR[1] = 1 << 14; if (dummyData) LPC_GPIO->SET[1] = 1 << 14; else LPC_GPIO->CLR[1] = 1 << 14; /* Start a new frame */ SFPFunction *outFunc = SFPFunction_new(); if (outFunc == NULL) return SFP_ERR_ALLOC_FAILED; /* Then fill the frame */ SFPFunction_setType(outFunc, SFPFunction_getType(msg)); SFPFunction_setID(outFunc, 200); /* Put the Function ID */ SFPFunction_setName(outFunc, "dummy"); /* Put the function name */ SFPFunction_addArgument_int32(outFunc, dummyData); /* Put the values you want to send back */ /* Send it */ SFPFunction_send(outFunc, &stream); /* End finalize */ SFPFunction_delete(outFunc); return SFP_OK; }
SFPResult lpc_pwm0_begin(SFPFunction *msg) { if (SFPFunction_getArgumentCount(msg) != 1) return SFP_ERR_ARG_COUNT; if (SFPFunction_getArgumentType(msg, 0) != SFP_ARG_INT) return SFP_ERR_ARG_TYPE; uint32_t p_cyclePeriod = (SFPFunction_getArgument_int32(msg, 0)-1) & 0xFFFF; // 16 bit value in microseconds LPC_SYSCON->SYSAHBCLKCTRL |= BIT7; // enable clock for CT16B0 // MAT3 is configured as the driving clock for PWM LPC_CT16B0->TCR = BIT0 | BIT1; // Enable timer, but keep in reset state LPC_CT16B0->PR = 48-1; // 48MHz/48 = 1MHz (1us) LPC_CT16B0->MCR = BIT10; // Reset timer on MR3 LPC_CT16B0->MR3 = p_cyclePeriod; // Set PWM cycle period LPC_CT16B0->MR2 = p_cyclePeriod+1; // Set 0% duty cycle (100% off time) LPC_CT16B0->MR1 = p_cyclePeriod+1; // Set 0% duty cycle LPC_CT16B0->MR0 = p_cyclePeriod+1; // Set 0% duty cycle LPC_CT16B0->EMR = 0x02A0; // External outputs enabled: channels 0-2 set high on match LPC_CT16B0->PWMC = 0x7; // PWM channels enabled: set channels 0-2 to PWM control LPC_CT16B0->TCR &= ~BIT1; // disable reset return SFP_OK; }
SFPResult lpc_system_restart(SFPFunction *msg) { if (SFPFunction_getArgumentCount(msg) != 0) return SFP_ERR_ARG_COUNT; Time_delay(1000); // Delay 1s before restarting NVIC_SystemReset(); return SFP_OK; // This code should not be reached }
SFPResult lpc_pwm0_end(SFPFunction *msg) { if (SFPFunction_getArgumentCount(msg) != 0) return SFP_ERR_ARG_COUNT; LPC_CT16B0->EMR = 0; // Disable external outputs LPC_CT16B0->PWMC = 0; // Disable PWM channels LPC_CT16B0->TCR = 0; // Disable timer LPC_SYSCON->SYSAHBCLKCTRL &= ~BIT7; // Disable clock for CT16B0 return SFP_OK; }
SFPResult lpc_1wire_trans(SFPFunction *msg) { if (SFPFunction_getArgumentCount(msg) != 1) return SFP_ERR_ARG_COUNT; if (SFPFunction_getArgumentType(msg, 0) != SFP_ARG_BYTE_ARRAY) return SFP_ERR_ARG_TYPE; uint8_t port = 0; uint8_t pinNum = LPC_PIN_IDS[pin]; if (pinNum > 23) { // if not PIO0_0 to PIO0_23 port = 1; pinNum -= 24; } uint32_t len = 0; uint8_t *buf = SFPFunction_getArgument_barray(msg, 0, &len); int delay_high, delay_low; __disable_irq(); while (len--) { uint8_t b = *buf++; int n; #define BIT0H 4 #define BIT0L 19 #define BIT1H 16 #define BIT1L 4-2 for (n=7; n>=0; n--) { // MSB first if (b & (1 << n)) { delay_high = BIT1H; delay_low = BIT1L; } else { delay_high = BIT0H; delay_low = BIT0L; } LPC_GPIO->SET[port] = (1 << pinNum); while (delay_high--) __asm("nop"); LPC_GPIO->CLR[port] = (1 << pinNum); while (delay_low--) __asm("nop"); } } __enable_irq(); return SFP_OK; }
SFPResult lpc_detachInterrupt(SFPFunction *msg) { if (SFPFunction_getArgumentCount(msg) != 1) return SFP_ERR_ARG_COUNT; if (SFPFunction_getArgumentType(msg, 0) != SFP_ARG_INT) return SFP_ERR_ARG_TYPE; uint8_t p_intID = SFPFunction_getArgument_int32(msg, 0); // interrupt ID NVIC_DisableIRQ(p_intID); // Disable interrupt. XXX: Luckily FLEX_INTx_IRQn == x, so it can be used this way, otherwise BE AWARE! LPC_GPIO_PIN_INT->CIENR = (1 << p_intID); // Disable rising edge or level interrupt LPC_GPIO_PIN_INT->CIENF = (1 << p_intID); // Disable falling edge interrupt LPC_GPIO_PIN_INT->RISE = (1 << p_intID); // Clear rising edge (sort of) flag LPC_GPIO_PIN_INT->FALL = (1 << p_intID); // Clear falling edge (sort of) flag return SFP_OK; }
SFPResult lpc_system_getDeviceInfo(SFPFunction *msg) { if (SFPFunction_getArgumentCount(msg) != 0) return SFP_ERR_ARG_COUNT; SFPFunction *func = SFPFunction_new(); if (func == NULL) return SFP_ERR_ALLOC_FAILED; SFPFunction_setType(func, SFPFunction_getType(msg)); SFPFunction_setID(func, UPER_FID_GETDEVICEINFO); SFPFunction_setName(func, UPER_FNAME_GETDEVICEINFO); SFPFunction_addArgument_int32(func, UPER_FIRMWARE_VERSION); SFPFunction_addArgument_barray(func, (uint8_t*)&GUID[0], 16); SFPFunction_addArgument_int32(func, UPER_PART_NUMBER); SFPFunction_addArgument_int32(func, UPER_BOOT_CODE_VERSION); SFPFunction_send(func, &stream); SFPFunction_delete(func); return SFP_OK; }
SFPResult lpc_pwm0_set(SFPFunction *msg) { if (SFPFunction_getArgumentCount(msg) != 2) return SFP_ERR_ARG_COUNT; if (SFPFunction_getArgumentType(msg, 0) != SFP_ARG_INT || SFPFunction_getArgumentType(msg, 1) != SFP_ARG_INT) return SFP_ERR_ARG_TYPE; uint32_t p_channelID = SFPFunction_getArgument_int32(msg, 0); // PWM channel ID [0-2] uint32_t p_highTime = SFPFunction_getArgument_int32(msg, 1); // PWM signal high time in microseconds if (p_channelID > 2) return SFP_ERR_ARG_VALUE; while (LPC_CT16B0->TC != 0); if (LPC_CT16B0->MR3 < p_highTime) LPC_CT16B0->MR[p_channelID] = 0; // Set full high time (0 low time) else LPC_CT16B0->MR[p_channelID] = LPC_CT16B0->MR3 + 1 - p_highTime; // Set PWM low time return SFP_OK; }
SFPResult lpc_1wire_begin(SFPFunction *msg) { if (SFPFunction_getArgumentCount(msg) != 1) return SFP_ERR_ARG_COUNT; if (SFPFunction_getArgumentType(msg, 0) != SFP_ARG_INT) return SFP_ERR_ARG_TYPE; pin = SFPFunction_getArgument_int32(msg, 0); uint8_t port = 0; uint8_t pinNum = LPC_PIN_IDS[pin]; if (pinNum > 23) { // if not PIO0_0 to PIO0_23 port = 1; pinNum -= 24; } *LPC_PIN_REGISTERS[pin] &= ~LPC_PIN_MODE_MASK; // Remove pull-up/down resistors LPC_GPIO->DIR[port] |= (1 << pinNum); // Set direction bit (output) LPC_GPIO->CLR[port] = (1 << pinNum); return SFP_OK; }
SFPResult lpc_attachInterrupt(SFPFunction *func) { if (SFPFunction_getArgumentCount(func) != 4) return SFP_ERR_ARG_COUNT; if (SFPFunction_getArgumentType(func, 0) != SFP_ARG_INT || SFPFunction_getArgumentType(func, 1) != SFP_ARG_INT || SFPFunction_getArgumentType(func, 2) != SFP_ARG_INT || SFPFunction_getArgumentType(func, 3) != SFP_ARG_INT) return SFP_ERR_ARG_TYPE; uint8_t p_intID = SFPFunction_getArgument_int32(func, 0); // interrupt ID uint8_t p_pin = SFPFunction_getArgument_int32(func, 1); // pin ID uint8_t p_mode = SFPFunction_getArgument_int32(func, 2); // interrupt mode uint32_t p_downtime = SFPFunction_getArgument_int32(func, 3); // down time if (p_pin >= LPC_PIN_COUNT || p_intID >= LPC_INTERRUPT_COUNT || p_mode > 4) return SFP_ERR_ARG_VALUE; NVIC_DisableIRQ(p_intID); // Disable interrupt. XXX: Luckily FLEX_INTx_IRQn == x, so it can be used this way, otherwise BE AWARE! LPC_SYSCON->PINTSEL[p_intID] = LPC_PIN_IDS[p_pin]; // select which pin will cause the interrupts // XXX: using SI/CI ENF and ENR registers could probably save few instructions switch (p_mode) { case 0: { // LOW level mode LPC_GPIO_PIN_INT ->ISEL |= (1 << p_intID); // Set PMODE=level sensitive LPC_GPIO_PIN_INT ->IENR |= (1 << p_intID); // Enable level interrupt. LPC_GPIO_PIN_INT ->IENF &= ~(1 << p_intID); // Set active level LOW. break; } case 1: { // HIGH level mode LPC_GPIO_PIN_INT ->ISEL |= (1 << p_intID); // Set PMODE=level sensitive LPC_GPIO_PIN_INT ->IENR |= (1 << p_intID); // Enable level interrupt. LPC_GPIO_PIN_INT ->IENF |= (1 << p_intID); // Set active level HIGH. break; } case 2: { // Edge CHANGE mode LPC_GPIO_PIN_INT ->ISEL &= ~(1 << p_intID); // Set PMODE=edge sensitive LPC_GPIO_PIN_INT ->IENR |= (1 << p_intID); // Enable rising edge. LPC_GPIO_PIN_INT ->IENF |= (1 << p_intID); // Enable falling edge. break; } case 3: { // RISING edge mode LPC_GPIO_PIN_INT ->ISEL &= ~(1 << p_intID); // Set PMODE=edge sensitive LPC_GPIO_PIN_INT ->IENR |= (1 << p_intID); // Enable rising edge. LPC_GPIO_PIN_INT ->IENF &= ~(1 << p_intID); // Disable falling edge. break; } case 4: { // FALLING edge mode LPC_GPIO_PIN_INT ->ISEL &= ~(1 << p_intID); // Set PMODE=edge sensitive LPC_GPIO_PIN_INT ->IENR &= ~(1 << p_intID); // Disable rising edge. LPC_GPIO_PIN_INT ->IENF |= (1 << p_intID); // Enable falling edge. break; } } LPC_INTERRUPT_FUNCTION_TYPE[p_intID] = SFPFunction_getType(func); LPC_INTERRUPT_DOWNTIME[p_intID] = p_downtime; LPC_GPIO_PIN_INT->RISE = (1 << p_intID); // Clear rising edge (sort of) flag LPC_GPIO_PIN_INT->FALL = (1 << p_intID); // Clear falling edge (sort of) flag NVIC_SetPriority(p_intID, 3); // set lowest priority NVIC_EnableIRQ(p_intID); // Enable interrupt. XXX: Luckily FLEX_INTx_IRQn == x, so it can be used this way, otherwise BE AWARE! return SFP_OK; }
SFPResult hcsr04Read(SFPFunction *msg) { if (SFPFunction_getArgumentCount(msg) != 2) return SFP_ERR_ARG_COUNT; if (SFPFunction_getArgumentType(msg, 0) != SFP_ARG_INT) return SFP_ERR_ARG_TYPE; if (SFPFunction_getArgumentType(msg, 1) != SFP_ARG_INT) return SFP_ERR_ARG_TYPE; uint8_t trigger = SFPFunction_getArgument_int32(msg, 0); uint8_t pulse = SFPFunction_getArgument_int32(msg, 1); uint32_t startTime = 0; uint32_t distance; if (trigger >= LPC_PIN_COUNT) return SFP_ERR_ARG_VALUE; if (pulse >= LPC_PIN_COUNT) return SFP_ERR_ARG_VALUE; uint8_t trigger_port = 0; uint8_t trigger_pinNum = LPC_PIN_IDS[trigger]; if (trigger_pinNum > 23) { // if not PIO0_0 to PIO0_23 trigger_port = 1; trigger_pinNum -= 24; } uint8_t pulse_port = 0; uint8_t pulse_pinNum = LPC_PIN_IDS[pulse]; if (pulse_pinNum > 23) { // if not PIO0_0 to PIO0_23 pulse_port = 1; pulse_pinNum -= 24; } /* Set the trigger as output, LOW */ LPC_GPIO->CLR[trigger_port] = (1 << trigger_pinNum); *LPC_PIN_REGISTERS[trigger] &= ~LPC_PIN_MODE_MASK; // Remove pull-up/down resistors LPC_GPIO->DIR[trigger_port] |= (1 << trigger_pinNum); /* Set the pulse as input, no resistors */ *LPC_PIN_REGISTERS[pulse] &= ~LPC_PIN_MODE_MASK; // Remove pull-up/down resistors *LPC_PIN_REGISTERS[pulse] |= (2 << 2) & LPC_PIN_MODE_MASK;; LPC_GPIO->DIR[pulse_port] &= ~(1 << pulse_pinNum); /* Send the trigger signal for 10us*/ startTime = Time_getSystemTime_us(); LPC_GPIO->SET[trigger_port] = (1 << trigger_pinNum); while ((Time_getSystemTime_us()-startTime) <= 10); LPC_GPIO->CLR[trigger_port] = (1 << trigger_pinNum); /* Wait for an answer */ startTime = Time_getSystemTime_us(); while (!(LPC_GPIO->PIN[pulse_port] & (1 << pulse_pinNum))) { if ((Time_getSystemTime_us()-startTime) >= 25000) { // Timeout : 25ms break; } } /* Measure the pulse */ startTime = Time_getSystemTime_us(); while ((LPC_GPIO->PIN[pulse_port] & (1 << pulse_pinNum))) { if ((Time_getSystemTime_us()-startTime) >= 25000) { // Timeout : 25ms break; } } distance = (Time_getSystemTime_us() - startTime) / 58; SFPFunction *outFunc = SFPFunction_new(); if (outFunc == NULL) return SFP_ERR_ALLOC_FAILED; SFPFunction_setType(outFunc, SFPFunction_getType(msg)); SFPFunction_setID(outFunc, UPER_FID_HCSR04); SFPFunction_setName(outFunc, UPER_FNAME_HCSR04); SFPFunction_addArgument_int32(outFunc, (distance < 25000 ? distance : 0)); SFPFunction_send(outFunc, &stream); SFPFunction_delete(outFunc); return SFP_OK; }