/*----------------------------------------------------------------------------*/ static enum Result canInit(void *object, const void *configBase) { const struct CanConfig * const config = configBase; assert(config); const struct CanBaseConfig baseConfig = { .rx = config->rx, .tx = config->tx, .channel = config->channel }; struct Can * const interface = object; enum Result res; /* Call base class constructor */ if ((res = CanBase->init(object, &baseConfig)) != E_OK) return res; interface->base.handler = interruptHandler; interface->callback = 0; interface->timer = config->timer; interface->mode = MODE_LISTENER; interface->sequence = 0; const size_t poolSize = config->rxBuffers + config->txBuffers; if (!pointerArrayInit(&interface->pool, poolSize)) return E_MEMORY; if (!pointerQueueInit(&interface->rxQueue, config->rxBuffers)) return E_MEMORY; if (!pointerQueueInit(&interface->txQueue, config->txBuffers)) return E_MEMORY; interface->poolBuffer = malloc(sizeof(struct CanStandardMessage) * poolSize); struct CanStandardMessage *message = interface->poolBuffer; for (size_t index = 0; index < poolSize; ++index) { pointerArrayPushBack(&interface->pool, message); ++message; } LPC_CAN_Type * const reg = interface->base.reg; reg->MOD = MOD_RM; /* Reset CAN */ reg->IER = 0; /* Disable Receive Interrupt */ reg->GSR = 0; /* Reset error counter */ interface->rate = config->rate; reg->BTR = calcBusTimings(interface, interface->rate); /* Activate Listen Only mode and enable local priority for transmit buffers */ reg->MOD = MOD_LOM | MOD_TPM; LPC_CANAF->AFMR = AFMR_AccBP; //FIXME #ifdef CONFIG_PLATFORM_NXP_CAN_PM if ((res = pmRegister(powerStateHandler, interface)) != E_OK) return res; #endif /* Enable interrupts on message reception and bus error */ reg->IER = IER_RIE | IER_EPIE | IER_BEIE | IER_TIE_MASK; irqSetPriority(interface->base.irq, config->priority); irqEnable(interface->base.irq); return E_OK; } /*----------------------------------------------------------------------------*/ #ifndef CONFIG_PLATFORM_NXP_CAN_NO_DEINIT static void canDeinit(void *object) { struct Can * const interface = object; LPC_CAN_Type * const reg = interface->base.reg; /* Disable all interrupts */ irqDisable(interface->base.irq); reg->IER = 0; #ifdef CONFIG_PLATFORM_NXP_CAN_PM pmUnregister(interface); #endif pointerQueueDeinit(&interface->txQueue); pointerQueueDeinit(&interface->rxQueue); pointerArrayDeinit(&interface->pool); CanBase->deinit(interface); } #endif /*----------------------------------------------------------------------------*/ static enum Result canSetCallback(void *object, void (*callback)(void *), void *argument) { struct Can * const interface = object; interface->callbackArgument = argument; interface->callback = callback; return E_OK; } /*----------------------------------------------------------------------------*/ static enum Result canGetParam(void *object, enum IfParameter parameter, void *data) { struct Can * const interface = object; switch (parameter) { case IF_AVAILABLE: *(size_t *)data = pointerQueueSize(&interface->rxQueue); return E_OK; case IF_PENDING: *(size_t *)data = pointerQueueSize(&interface->txQueue); return E_OK; case IF_RATE: *(uint32_t *)data = interface->rate; return E_OK; default: return E_INVALID; } } /*----------------------------------------------------------------------------*/ static enum Result canSetParam(void *object, enum IfParameter parameter, const void *data) { struct Can * const interface = object; switch ((enum CanParameter)parameter) { case IF_CAN_ACTIVE: changeMode(interface, MODE_ACTIVE); return E_OK; case IF_CAN_LISTENER: changeMode(interface, MODE_LISTENER); return E_OK; case IF_CAN_LOOPBACK: changeMode(interface, MODE_LOOPBACK); return E_OK; default: break; } switch (parameter) { case IF_RATE: { const uint32_t rate = *(const uint32_t *)data; changeRate(interface, rate); interface->rate = rate; return E_OK; } default: return E_INVALID; } } /*----------------------------------------------------------------------------*/ static size_t canRead(void *object, void *buffer, size_t length) { assert(length % sizeof(struct CanStandardMessage) == 0); struct Can * const interface = object; struct CanStandardMessage *current = buffer; const struct CanStandardMessage * const last = (const void *)((uintptr_t)buffer + length); while (!pointerQueueEmpty(&interface->rxQueue) && current < last) { irqDisable(interface->base.irq); struct CanMessage * const input = pointerQueueFront(&interface->rxQueue); pointerQueuePopFront(&interface->rxQueue); memcpy(current, input, sizeof(*current)); pointerArrayPushBack(&interface->pool, input); irqEnable(interface->base.irq); ++current; } return (uintptr_t)current - (uintptr_t)buffer; }
/*----------------------------------------------------------------------------*/ static enum Result unitInit(void *object, const void *configBase) { const struct GpPwmUnitConfig * const config = configBase; assert(config); assert(config->resolution >= 2); const struct GpPwmUnitBaseConfig baseConfig = { .channel = config->channel }; struct GpPwmUnit * const unit = object; enum Result res; /* Call base class constructor */ if ((res = GpPwmUnitBase->init(unit, &baseConfig)) != E_OK) return res; LPC_PWM_Type * const reg = unit->base.reg; reg->TCR = TCR_CRES; reg->IR = reg->IR; /* Clear pending interrupts */ reg->CTCR = 0; reg->CCR = 0; reg->PCR = 0; /* Configure timings */ unit->frequency = config->frequency; unit->resolution = config->resolution; unitSetFrequency(unit, unit->frequency * unit->resolution); unit->matches = 0; reg->MR0 = unit->resolution; reg->MCR = MCR_RESET(0); #ifdef CONFIG_PLATFORM_NXP_GPTIMER_PM if ((res = pmRegister(powerStateHandler, unit)) != E_OK) return res; #endif /* Switch to the PWM mode and enable the timer */ reg->TCR = TCR_CEN | TCR_PWM_ENABLE; return E_OK; } /*----------------------------------------------------------------------------*/ #ifndef CONFIG_PLATFORM_NXP_GPPWM_NO_DEINIT static void unitDeinit(void *object) { struct GpPwmUnit * const unit = object; LPC_PWM_Type * const reg = unit->base.reg; reg->TCR = 0; #ifdef CONFIG_PLATFORM_NXP_GPTIMER_PM pmUnregister(unit); #endif GpPwmUnitBase->deinit(unit); } #endif /*----------------------------------------------------------------------------*/ static enum Result singleEdgeInit(void *object, const void *configBase) { const struct GpPwmConfig * const config = configBase; assert(config); struct GpPwm * const pwm = object; struct GpPwmUnit * const unit = config->parent; /* Initialize output pin */ pwm->channel = configMatchPin(unit->base.channel, config->pin); /* Allocate channel */ if (unitAllocateChannel(unit, pwm->channel)) { LPC_PWM_Type * const reg = unit->base.reg; /* Select single edge mode */ reg->PCR &= ~PCR_DOUBLE_EDGE(pwm->channel); pwm->unit = unit; pwm->latch = LER_ENABLE(pwm->channel); /* Calculate pointer to the match register */ pwm->value = calcMatchChannel(reg, pwm->channel); return E_OK; } else return E_BUSY; } /*----------------------------------------------------------------------------*/ #ifndef CONFIG_PLATFORM_NXP_GPPWM_NO_DEINIT static void singleEdgeDeinit(void *object) { struct GpPwm * const pwm = object; LPC_PWM_Type * const reg = pwm->unit->base.reg; reg->PCR &= ~PCR_OUTPUT_ENABLED(pwm->channel); unitReleaseChannel(pwm->unit, pwm->channel); } #endif /*----------------------------------------------------------------------------*/ static void singleEdgeEnable(void *object) { struct GpPwm * const pwm = object; LPC_PWM_Type * const reg = pwm->unit->base.reg; reg->PCR |= PCR_OUTPUT_ENABLED(pwm->channel); } /*----------------------------------------------------------------------------*/ static void singleEdgeDisable(void *object) { struct GpPwm * const pwm = object; LPC_PWM_Type * const reg = pwm->unit->base.reg; reg->PCR &= ~PCR_OUTPUT_ENABLED(pwm->channel); } /*----------------------------------------------------------------------------*/ static uint32_t singleEdgeGetResolution(const void *object) { return ((const struct GpPwm *)object)->unit->resolution; } /*----------------------------------------------------------------------------*/ static void singleEdgeSetDuration(void *object, uint32_t duration) { struct GpPwm * const pwm = object; LPC_PWM_Type * const reg = pwm->unit->base.reg; /* * If match register is set to a value greater than resolution, * than output stays high during all cycle. */ *pwm->value = duration; reg->LER |= pwm->latch; } /*----------------------------------------------------------------------------*/ static void singleEdgeSetEdges(void *object, uint32_t leading __attribute__((unused)), uint32_t trailing) { assert(leading == 0); /* Leading edge time must be zero */ singleEdgeSetDuration(object, trailing); }
/*----------------------------------------------------------------------------*/ static enum result spiInit(void *object, const void *configBase) { const struct SpiConfig * const config = configBase; const struct SspBaseConfig baseConfig = { .channel = config->channel, .miso = config->miso, .mosi = config->mosi, .sck = config->sck, .cs = 0 }; struct Spi * const interface = object; enum result res; /* Call base class constructor */ if ((res = SspBase->init(object, &baseConfig)) != E_OK) return res; interface->base.handler = interruptHandler; interface->callback = 0; interface->rate = config->rate; interface->blocking = true; LPC_SSP_Type * const reg = interface->base.reg; uint32_t controlValue = 0; /* Set frame size */ controlValue |= CR0_DSS(8); /* Set mode for the interface */ if (config->mode & 0x01) controlValue |= CR0_CPHA; if (config->mode & 0x02) controlValue |= CR0_CPOL; reg->CR0 = controlValue; /* Disable all interrupts */ reg->IMSC = 0; /* Try to set the desired data rate */ sspSetRate(object, interface->rate); #ifdef CONFIG_SSP_PM if ((res = pmRegister(interface, powerStateHandler)) != E_OK) return res; #endif /* Enable the peripheral */ reg->CR1 = CR1_SSE; irqSetPriority(interface->base.irq, config->priority); irqEnable(interface->base.irq); return E_OK; } /*----------------------------------------------------------------------------*/ static void spiDeinit(void *object) { struct Spi * const interface = object; LPC_SSP_Type * const reg = interface->base.reg; /* Disable the peripheral */ irqDisable(interface->base.irq); reg->CR1 = 0; #ifdef CONFIG_SSP_PM pmUnregister(interface); #endif SspBase->deinit(interface); } /*----------------------------------------------------------------------------*/ static enum result spiCallback(void *object, void (*callback)(void *), void *argument) { struct Spi * const interface = object; interface->callbackArgument = argument; interface->callback = callback; return E_OK; } /*----------------------------------------------------------------------------*/ static enum result spiGet(void *object, enum ifOption option, void *data) { struct Spi * const interface = object; LPC_SSP_Type * const reg = interface->base.reg; switch (option) { case IF_RATE: *(uint32_t *)data = interface->rate; return E_OK; case IF_STATUS: return (interface->rxLeft || reg->SR & SR_BSY) ? E_BUSY : E_OK; default: return E_INVALID; } } /*----------------------------------------------------------------------------*/ static enum result spiSet(void *object, enum ifOption option, const void *data) { struct Spi * const interface = object; switch (option) { case IF_BLOCKING: interface->blocking = true; return E_OK; case IF_RATE: interface->rate = *(const uint32_t *)data; sspSetRate(object, interface->rate); return E_OK; case IF_ZEROCOPY: interface->blocking = false; return E_OK; default: return E_INVALID; } } /*----------------------------------------------------------------------------*/ static size_t spiRead(void *object, void *buffer, size_t length) { struct Spi * const interface = object; LPC_SSP_Type * const reg = interface->base.reg; if (!length) return 0; interface->rxBuffer = buffer; interface->txBuffer = 0; interface->rxLeft = interface->txLeft = length; /* Clear interrupt flags and enable interrupts */ reg->ICR = ICR_RORIC | ICR_RTIC; reg->IMSC = IMSC_RXIM | IMSC_RTIM; /* Initiate reception by setting pending interrupt flag */ irqSetPending(interface->base.irq); if (interface->blocking) { while (interface->rxLeft || reg->SR & SR_BSY) barrier(); } return length; } /*----------------------------------------------------------------------------*/ static size_t spiWrite(void *object, const void *buffer, size_t length) { struct Spi * const interface = object; LPC_SSP_Type * const reg = interface->base.reg; if (!length) return 0; interface->rxBuffer = 0; interface->txBuffer = buffer; interface->rxLeft = interface->txLeft = length; /* Clear interrupt flags and enable interrupts */ reg->ICR = ICR_RORIC | ICR_RTIC; reg->IMSC = IMSC_RXIM | IMSC_RTIM; /* Initiate transmission by setting pending interrupt flag */ irqSetPending(interface->base.irq); if (interface->blocking) { while (interface->rxLeft || reg->SR & SR_BSY) barrier(); } return length; }
/*----------------------------------------------------------------------------*/ static enum Result serialInit(void *object, const void *configBase) { const struct SerialConfig * const config = configBase; assert(config); const struct UartBaseConfig baseConfig = { .channel = config->channel, .rx = config->rx, .tx = config->tx }; struct Serial * const interface = object; struct UartRateConfig rateConfig; enum Result res; /* Call base class constructor */ if ((res = UartBase->init(object, &baseConfig)) != E_OK) return res; if ((res = uartCalcRate(object, config->rate, &rateConfig)) != E_OK) return res; interface->base.handler = interruptHandler; interface->callback = 0; interface->rate = config->rate; if (!byteQueueInit(&interface->rxQueue, config->rxLength)) return E_MEMORY; if (!byteQueueInit(&interface->txQueue, config->txLength)) return E_MEMORY; LPC_UART_Type * const reg = interface->base.reg; /* Set 8-bit length */ reg->LCR = LCR_WORD_8BIT; /* Enable FIFO and set RX trigger level */ reg->FCR = (reg->FCR & ~FCR_RX_TRIGGER_MASK) | FCR_ENABLE | FCR_RX_TRIGGER(RX_TRIGGER_LEVEL_8); /* Enable RBR and THRE interrupts */ reg->IER = IER_RBR | IER_THRE; /* Transmitter is enabled by default thus TER register is left untouched */ uartSetParity(object, config->parity); uartSetRate(object, rateConfig); #ifdef CONFIG_PLATFORM_NXP_UART_PM if ((res = pmRegister(powerStateHandler, interface)) != E_OK) return res; #endif irqSetPriority(interface->base.irq, config->priority); irqEnable(interface->base.irq); return E_OK; } /*----------------------------------------------------------------------------*/ #ifndef CONFIG_PLATFORM_NXP_UART_NO_DEINIT static void serialDeinit(void *object) { struct Serial * const interface = object; irqDisable(interface->base.irq); #ifdef CONFIG_PLATFORM_NXP_UART_PM pmUnregister(interface); #endif byteQueueDeinit(&interface->txQueue); byteQueueDeinit(&interface->rxQueue); UartBase->deinit(interface); } #endif /*----------------------------------------------------------------------------*/ static enum Result serialSetCallback(void *object, void (*callback)(void *), void *argument) { struct Serial * const interface = object; interface->callbackArgument = argument; interface->callback = callback; return E_OK; } /*----------------------------------------------------------------------------*/ static enum Result serialGetParam(void *object, enum IfParameter parameter, void *data) { struct Serial * const interface = object; #ifdef CONFIG_PLATFORM_NXP_UART_RC switch ((enum SerialParameter)parameter) { case IF_SERIAL_PARITY: *(uint8_t *)data = (uint8_t)uartGetParity(object); return E_OK; default: break; } #endif switch (parameter) { case IF_AVAILABLE: *(size_t *)data = byteQueueSize(&interface->rxQueue); return E_OK; case IF_PENDING: *(size_t *)data = byteQueueSize(&interface->txQueue); return E_OK; #ifdef CONFIG_PLATFORM_NXP_UART_RC case IF_RATE: *(uint32_t *)data = uartGetRate(object); return E_OK; #endif default: return E_INVALID; } } /*----------------------------------------------------------------------------*/ static enum Result serialSetParam(void *object, enum IfParameter parameter, const void *data) { struct Serial * const interface = object; #ifdef CONFIG_PLATFORM_NXP_UART_RC switch ((enum SerialParameter)parameter) { case IF_SERIAL_PARITY: uartSetParity(object, (enum SerialParity)(*(const uint8_t *)data)); return E_OK; default: break; } switch (parameter) { case IF_RATE: { struct UartRateConfig rateConfig; const enum Result res = uartCalcRate(object, *(const uint32_t *)data, &rateConfig); if (res == E_OK) { interface->rate = *(const uint32_t *)data; uartSetRate(object, rateConfig); } return res; } default: return E_INVALID; } #else (void)interface; (void)parameter; (void)data; return E_INVALID; #endif } /*----------------------------------------------------------------------------*/ static size_t serialRead(void *object, void *buffer, size_t length) { struct Serial * const interface = object; irqDisable(interface->base.irq); const size_t read = byteQueuePopArray(&interface->rxQueue, buffer, length); irqEnable(interface->base.irq); return read; } /*----------------------------------------------------------------------------*/ static size_t serialWrite(void *object, const void *buffer, size_t length) { struct Serial * const interface = object; LPC_UART_Type * const reg = interface->base.reg; const uint8_t *bufferPosition = buffer; size_t written = 0; irqDisable(interface->base.irq); /* Check transmitter state */ if ((reg->LSR & LSR_THRE) && byteQueueEmpty(&interface->txQueue)) { /* Transmitter is idle so fill TX FIFO */ const size_t bytesToWrite = MIN(length, TX_FIFO_SIZE); for (; written < bytesToWrite; ++written) reg->THR = *bufferPosition++; length -= written; } /* Fill TX queue with the rest of data */ if (length) written += byteQueuePushArray(&interface->txQueue, bufferPosition, length); irqEnable(interface->base.irq); return written; }
/*----------------------------------------------------------------------------*/ static enum result tmrInit(void *object, const void *configBase) { const struct GpTimerConfig * const config = configBase; const struct GpTimerBaseConfig baseConfig = { .channel = config->channel }; struct GpTimer * const timer = object; enum result res; assert(config->event < GPTIMER_EVENT_END); timer->event = config->event ? config->event : GPTIMER_MATCH0; --timer->event; /* Call base class constructor */ if ((res = GpTimerBase->init(object, &baseConfig)) != E_OK) return res; timer->base.handler = interruptHandler; timer->callback = 0; /* Initialize peripheral block */ LPC_TIMER_Type * const reg = timer->base.reg; reg->TCR = TCR_CRES; reg->IR = reg->IR; /* Clear pending interrupts */ reg->CCR = 0; reg->CTCR = 0; reg->MCR = 0; updateFrequency(timer, config->frequency); /* Configure prescaler and default match value */ reg->MR[timer->event] = getMaxValue(timer); /* Enable external match to generate signals to other peripherals */ reg->EMR = EMR_CONTROL(timer->event, CONTROL_TOGGLE); #ifdef CONFIG_GPTIMER_PM if ((res = pmRegister(interface, powerStateHandler)) != E_OK) return res; #endif /* Timer is disabled by default */ reg->TCR = 0; irqSetPriority(timer->base.irq, config->priority); irqEnable(timer->base.irq); return E_OK; } /*----------------------------------------------------------------------------*/ static void tmrDeinit(void *object) { struct GpTimer * const timer = object; LPC_TIMER_Type * const reg = timer->base.reg; irqDisable(timer->base.irq); reg->TCR = 0; #ifdef CONFIG_GPTIMER_PM pmUnregister(interface); #endif GpTimerBase->deinit(timer); } /*----------------------------------------------------------------------------*/ static void tmrCallback(void *object, void (*callback)(void *), void *argument) { struct GpTimer * const timer = object; LPC_TIMER_Type * const reg = timer->base.reg; timer->callbackArgument = argument; timer->callback = callback; if (callback) { reg->IR = reg->IR; reg->MCR |= MCR_INTERRUPT(timer->event); } else reg->MCR &= ~MCR_INTERRUPT(timer->event); } /*----------------------------------------------------------------------------*/ static void tmrSetEnabled(void *object, bool state) { struct GpTimer * const timer = object; LPC_TIMER_Type * const reg = timer->base.reg; /* Stop the timer */ reg->TCR = 0; /* Clear pending interrupt flags and direct memory access requests */ reg->IR = IR_MATCH_INTERRUPT(timer->event); if (state) { /* Clear match value to avoid undefined output level */ reg->EMR &= ~EMR_EXTERNAL_MATCH(timer->event); reg->TCR = TCR_CEN; } } /*----------------------------------------------------------------------------*/ static uint32_t tmrGetFrequency(const void *object) { const struct GpTimer * const timer = object; const LPC_TIMER_Type * const reg = timer->base.reg; const uint32_t baseClock = gpTimerGetClock((const struct GpTimerBase *)timer); return baseClock / (reg->PR + 1); } /*----------------------------------------------------------------------------*/ static void tmrSetFrequency(void *object, uint32_t frequency) { updateFrequency(object, frequency); }
/*----------------------------------------------------------------------------*/ static enum Result tmrInit(void *object, const void *configBase) { const struct GpTimerConfig * const config = configBase; assert(config); const struct GpTimerBaseConfig baseConfig = { .channel = config->channel }; struct GpTimer * const timer = object; enum Result res; assert(config->event < GPTIMER_EVENT_END); /* Call base class constructor */ if ((res = GpTimerBase->init(timer, &baseConfig)) != E_OK) return res; timer->base.handler = interruptHandler; timer->callback = 0; timer->event = (config->event ? config->event : GPTIMER_MATCH0) - 1; /* Initialize peripheral block */ LPC_TIMER_Type * const reg = timer->base.reg; reg->TCR = TCR_CRES; reg->IR = reg->IR; /* Clear pending interrupts */ reg->CCR = 0; reg->CTCR = 0; timer->frequency = config->frequency; gpTimerSetFrequency(&timer->base, timer->frequency); /* Configure prescaler and default match value */ reg->MR[timer->event] = getMaxValue(timer); /* Reset the timer after reaching the match register value */ reg->MCR = MCR_RESET(timer->event); /* Enable external match to generate signals to other peripherals */ reg->EMR = EMR_CONTROL(timer->event, CONTROL_TOGGLE); #ifdef CONFIG_PLATFORM_NXP_GPTIMER_PM if ((res = pmRegister(powerStateHandler, timer)) != E_OK) return res; #endif /* Clear timer reset flag, but do not enable */ reg->TCR = 0; irqSetPriority(timer->base.irq, config->priority); irqEnable(timer->base.irq); return E_OK; } /*----------------------------------------------------------------------------*/ #ifndef CONFIG_PLATFORM_NXP_GPTIMER_NO_DEINIT static void tmrDeinit(void *object) { struct GpTimer * const timer = object; LPC_TIMER_Type * const reg = timer->base.reg; irqDisable(timer->base.irq); reg->TCR = 0; #ifdef CONFIG_PLATFORM_NXP_GPTIMER_PM pmUnregister(timer); #endif GpTimerBase->deinit(timer); } #endif /*----------------------------------------------------------------------------*/ static void tmrEnable(void *object) { struct GpTimer * const timer = object; LPC_TIMER_Type * const reg = timer->base.reg; /* Clear pending interrupt flags and direct memory access requests */ reg->IR = IR_MATCH_INTERRUPT(timer->event); /* Clear match value to avoid undefined output level */ reg->EMR &= ~EMR_EXTERNAL_MATCH(timer->event); /* Start the timer */ reg->TCR = TCR_CEN; } /*----------------------------------------------------------------------------*/ static void tmrDisable(void *object) { struct GpTimer * const timer = object; LPC_TIMER_Type * const reg = timer->base.reg; reg->TCR = 0; } /*----------------------------------------------------------------------------*/ static void tmrSetCallback(void *object, void (*callback)(void *), void *argument) { struct GpTimer * const timer = object; LPC_TIMER_Type * const reg = timer->base.reg; timer->callbackArgument = argument; timer->callback = callback; if (callback) { reg->IR = reg->IR; reg->MCR |= MCR_INTERRUPT(timer->event); } else reg->MCR &= ~MCR_INTERRUPT(timer->event); } /*----------------------------------------------------------------------------*/ static uint32_t tmrGetFrequency(const void *object) { const struct GpTimer * const timer = object; const LPC_TIMER_Type * const reg = timer->base.reg; const uint32_t baseClock = gpTimerGetClock(&timer->base); return baseClock / (reg->PR + 1); } /*----------------------------------------------------------------------------*/ static void tmrSetFrequency(void *object, uint32_t frequency) { struct GpTimer * const timer = object; timer->frequency = frequency; gpTimerSetFrequency(&timer->base, timer->frequency); } /*----------------------------------------------------------------------------*/ static uint32_t tmrGetOverflow(const void *object) { const struct GpTimer * const timer = object; const LPC_TIMER_Type * const reg = timer->base.reg; return (reg->MR[timer->event] + 1) & getMaxValue(timer); } /*----------------------------------------------------------------------------*/ static void tmrSetOverflow(void *object, uint32_t overflow) { struct GpTimer * const timer = object; LPC_TIMER_Type * const reg = timer->base.reg; assert(overflow <= getMaxValue(timer)); reg->MR[timer->event] = overflow - 1; } /*----------------------------------------------------------------------------*/ static uint32_t tmrGetValue(const void *object) { const struct GpTimer * const timer = object; const LPC_TIMER_Type * const reg = timer->base.reg; return reg->TC; } /*----------------------------------------------------------------------------*/ static void tmrSetValue(void *object, uint32_t value) { struct GpTimer * const timer = object; LPC_TIMER_Type * const reg = timer->base.reg; assert(value <= reg->MR[timer->event]); reg->PC = 0; reg->TC = value; }
/*----------------------------------------------------------------------------*/ static enum result i2cInit(void *object, const void *configBase) { const struct I2cSlaveConfig * const config = configBase; const struct I2cBaseConfig baseConfig = { .channel = config->channel, .scl = config->scl, .sda = config->sda }; struct I2cSlave * const interface = object; enum result res; /* Call base class constructor */ if ((res = I2cBase->init(object, &baseConfig)) != E_OK) return res; interface->cache = malloc(config->size); if (!interface->cache) return E_MEMORY; memset(interface->cache, 0, config->size); interface->base.handler = interruptHandler; interface->callback = 0; interface->external = 0; interface->internal = 0; interface->size = config->size; interface->state = STATE_IDLE; LPC_I2C_Type * const reg = interface->base.reg; /* Clear all flags */ reg->CONCLR = CONCLR_AAC | CONCLR_SIC | CONCLR_STAC | CONCLR_I2ENC; #ifdef CONFIG_I2C_PM if ((res = pmRegister(interface, powerStateHandler)) != E_OK) return res; #endif irqSetPriority(interface->base.irq, config->priority); irqEnable(interface->base.irq); /* Enable I2C interface */ reg->CONSET = CONSET_AA | CONSET_I2EN; return E_OK; } /*----------------------------------------------------------------------------*/ static void i2cDeinit(void *object) { struct I2cSlave * const interface = object; LPC_I2C_Type * const reg = interface->base.reg; reg->CONCLR = CONCLR_I2ENC; /* Disable I2C interface */ #ifdef CONFIG_I2C_PM pmUnregister(interface); #endif irqDisable(interface->base.irq); free(interface->cache); I2cBase->deinit(interface); } /*----------------------------------------------------------------------------*/ static enum result i2cCallback(void *object, void (*callback)(void *), void *argument) { struct I2cSlave * const interface = object; interface->callbackArgument = argument; interface->callback = callback; return E_OK; } /*----------------------------------------------------------------------------*/ static enum result i2cGet(void *object, enum ifOption option, void *data) { struct I2cSlave * const interface = object; LPC_I2C_Type * const reg = interface->base.reg; switch (option) { case IF_ADDRESS: *(uint16_t *)data = ADR_ADDRESS_VALUE(reg->ADR0); return E_OK; case IF_POSITION: *(uint32_t *)data = interface->internal; return E_OK; case IF_STATUS: return interface->state != STATE_IDLE ? E_BUSY : E_OK; default: return E_INVALID; } } /*----------------------------------------------------------------------------*/ static enum result i2cSet(void *object, enum ifOption option, const void *data) { struct I2cSlave * const interface = object; LPC_I2C_Type * const reg = interface->base.reg; switch (option) { case IF_ADDRESS: if (*(const uint16_t *)data <= 127) { reg->ADR0 = ADR_ADDRESS(*(const uint16_t *)data); return E_OK; } else return E_VALUE; case IF_POSITION: if (*(const uint32_t *)data < interface->size) { interface->internal = *(const uint32_t *)data; return E_OK; } else return E_VALUE; default: return E_INVALID; } } /*----------------------------------------------------------------------------*/ static size_t i2cRead(void *object, void *buffer, size_t length) { struct I2cSlave * const interface = object; const uint8_t * const position = interface->cache + interface->internal; uint16_t left = interface->size - interface->internal; if (!length) return 0; if (length < left) { left = length; interface->internal += length; } else interface->internal = 0; memcpy(buffer, position, left); return left; } /*----------------------------------------------------------------------------*/ static size_t i2cWrite(void *object, const void *buffer, size_t length) { struct I2cSlave * const interface = object; uint8_t * const position = interface->cache + interface->internal; uint16_t left = interface->size - interface->internal; if (!length) return 0; if (length < left) { left = length; interface->internal += length; } else interface->internal = 0; memcpy(position, buffer, left); return left; }
/*----------------------------------------------------------------------------*/ static enum result canInit(void *object, const void *configBase) { const struct CanConfig * const config = configBase; const struct CanBaseConfig baseConfig = { .channel = config->channel, .rx = config->rx, .tx = config->tx }; struct Can * const interface = object; enum result res; /* Call base class constructor */ if ((res = CanBase->init(object, &baseConfig)) != E_OK) return res; interface->base.handler = interruptHandler; interface->callback = 0; interface->timer = config->timer; interface->mode = MODE_LISTENER; const size_t poolSize = config->rxBuffers + config->txBuffers; res = queueInit(&interface->pool, sizeof(struct CanMessage *), poolSize); if (res != E_OK) return res; res = queueInit(&interface->rxQueue, sizeof(struct CanMessage *), config->rxBuffers); if (res != E_OK) return res; res = queueInit(&interface->txQueue, sizeof(struct CanMessage *), config->txBuffers); if (res != E_OK) return res; interface->poolBuffer = malloc(sizeof(struct CanStandardMessage) * poolSize); struct CanStandardMessage *message = interface->poolBuffer; for (size_t index = 0; index < poolSize; ++index) { queuePush(&interface->pool, &message); ++message; } LPC_CAN_Type * const reg = interface->base.reg; reg->MOD = MOD_RM; /* Reset CAN */ reg->IER = 0; /* Disable Receive Interrupt */ reg->GSR = 0; /* Reset error counter */ interface->rate = config->rate; reg->BTR = calcBusTimings(interface, interface->rate); /* Disable Reset mode and activate Listen Only mode */ reg->MOD = MOD_LOM; LPC_CANAF->AFMR = AFMR_AccBP; //FIXME #ifdef CONFIG_CAN_PM if ((res = pmRegister(interface, powerStateHandler)) != E_OK) return res; #endif irqSetPriority(interface->base.irq, config->priority); /* Enable interrupts on message reception and bus error */ reg->IER = IER_RIE | IER_BEIE; return E_OK; } /*----------------------------------------------------------------------------*/ static void canDeinit(void *object) { struct Can * const interface = object; LPC_CAN_Type * const reg = interface->base.reg; /* Disable all interrupts */ reg->IER = 0; #ifdef CONFIG_CAN_PM pmUnregister(interface); #endif queueDeinit(&interface->txQueue); queueDeinit(&interface->rxQueue); CanBase->deinit(interface); } /*----------------------------------------------------------------------------*/ static enum result canCallback(void *object, void (*callback)(void *), void *argument) { struct Can * const interface = object; interface->callbackArgument = argument; interface->callback = callback; return E_OK; } /*----------------------------------------------------------------------------*/ static enum result canGet(void *object, enum ifOption option, void *data) { struct Can * const interface = object; switch (option) { case IF_AVAILABLE: *(size_t *)data = queueSize(&interface->rxQueue); return E_OK; case IF_PENDING: *(size_t *)data = queueSize(&interface->txQueue); return E_OK; case IF_RATE: *(uint32_t *)data = interface->rate; return E_OK; default: return E_INVALID; } } /*----------------------------------------------------------------------------*/ static enum result canSet(void *object, enum ifOption option, const void *data) { struct Can * const interface = object; LPC_CAN_Type * const reg = interface->base.reg; switch ((enum canOption)option) { case IF_CAN_ACTIVE: changeMode(interface, MODE_ACTIVE); return E_OK; case IF_CAN_LISTENER: changeMode(interface, MODE_LISTENER); return E_OK; case IF_CAN_LOOPBACK: changeMode(interface, MODE_LOOPBACK); return E_OK; default: break; } switch (option) { case IF_RATE: { const uint32_t rate = *(const uint32_t *)data; interface->rate = rate; reg->MOD |= MOD_RM; /* Enable Reset mode */ reg->BTR = calcBusTimings(interface, rate); reg->MOD &= ~MOD_RM; return E_OK; } default: return E_INVALID; } } /*----------------------------------------------------------------------------*/ static size_t canRead(void *object, void *buffer, size_t length) { assert(length % sizeof(struct CanStandardMessage) == 0); struct Can * const interface = object; struct CanStandardMessage *output = buffer; size_t read = 0; while (read < length && !queueEmpty(&interface->rxQueue)) { struct CanMessage *input; const irqState state = irqSave(); queuePop(&interface->rxQueue, &input); memcpy(output, input, sizeof(*output)); queuePush(&interface->pool, &input); irqRestore(state); read += sizeof(*output); ++output; } return read; }