#define BUSVOOFOO_XVCTL_CHANNEL CHANNEL_1 /**< DAC channel to control xV output voltage */
#define BUSVOODOO_XV_DEFAULT (0.8*(1+33.0/10.0)) /**< default (when not driven) xV voltage regulator output voltage based on R1 and R2 */
#define BUSVOODOO_XV_TEST 2.5 /**< target xV output voltage to test if we can set control the xV voltage regulator */
#define BUSVOODOO_XV_SET(x) ((0.8*(1+33.0/10.0)-x)*(10.0/33.0)+0.8) /**< voltage to output for the DAC to set the desired xV output voltage (based on resistor values on the xV adjust pins and xV voltage reference) */
#define BUSVOOFOO_12VCTL_CHANNEL CHANNEL_2 /**< DAC channel to control 12V output voltage */
#define BUSVOODOO_12V_DEFAULT (1.25*(1+100.0/10.0)) /**< default (when not driven) 12V voltage regulator output voltage based on R1 and R2 */
#define BUSVOODOO_12V_TEST 12.0 /**< target 12V output voltage to test if we can set control the 12V voltage regulator */
#define BUSVOODOO_12V_SET(x) ((1.25*(1+100.0/10.0)-x)*(10.0/100.0)+1.25) /**< voltage to output for the DAC to set the desired
staticconstchar*busvoodoo_io_names[13]={"I2C_SMBA/SPI_NSS/I2S_WS","SDIO_CMD","USART_CTS/SPI_SCK/I2S_CK","SDIO_D3/UART_RX","I2C_SDA/USART_RX","SDIO_D0","SPI_MOSI/I2S_SD","SDIO_CK/USART_CK","I2C_SCL/USART_TX","SDIO_D1","I2S_MCK","USART_RTS/SPI_MISO","SDIO_D2/UART_TX"};/**< I/O individual signal names */
staticconstuint32_tbusvoodoo_io_ports[13]={GPIOB,GPIOD,GPIOB,GPIOC,GPIOB,GPIOC,GPIOB,GPIOC,GPIOB,GPIOC,GPIOC,GPIOB,GPIOC};/**< port of individual signals */
staticconstuint32_tbusvoodoo_io_pins[13]={GPIO12,GPIO2,GPIO13,GPIO11,GPIO11,GPIO8,GPIO15,GPIO12,GPIO10,GPIO9,GPIO6,GPIO14,GPIO10};/**< pin of individual signals */
// ideal pinout
//static const uint8_t busvoodoo_io_groups[13] = {1, 1, 3, 3, 5, 5, 2, 2, 4, 4, 6, 6, 6}; /**< which I/O (group) does the signal belong to */
// schematic/layout v0.001 pinout (SDIO_D2/UART_TX landed in group 6 instead of 3)
staticconstuint8_tbusvoodoo_io_groups[13]={1,1,3,3,5,5,2,2,4,4,6,6,3};/**< which I/O (group) does the signal belong to */
printf("press space to continue, or any other key to abort\n");
while(!usart_received&&!usb_cdcacm_received){// wait for user input
__WFI();// go to sleep
}
charc=0;
if(usart_received){
c=usart_getchar();// read user input from UART
}elseif(usb_cdcacm_received){
c=usb_cdcacm_getchar();// read user input from USB
}else{
returnfalse;// this should not happen
}
if(''==c){// space entered
returntrue;
}else{// something else entered
returnfalse;
}
}
/** set safe state by disabling all outputs */
staticvoidsafe_state(void)
{
// disable voltage outputs
gpio_set(GPIO(BUSVOODOO_VOUTEN_PORT),GPIO(BUSVOODOO_VOUTEN_PIN));// disable 5V and 3.3V output on connector
gpio_set_mode(GPIO(BUSVOODOO_VOUTEN_PORT),GPIO_MODE_OUTPUT_2_MHZ,GPIO_CNF_OUTPUT_OPENDRAIN,GPIO(BUSVOODOO_VOUTEN_PIN));// set pin as output (open-drain pulled high to disable the pMOS)
gpio_clear(GPIO(BUSVOODOO_XVEN_PORT),GPIO(BUSVOODOO_XVEN_PIN));// disable xV voltage regulator
gpio_set_mode(GPIO(BUSVOODOO_XVEN_PORT),GPIO_MODE_OUTPUT_2_MHZ,GPIO_CNF_OUTPUT_PUSHPULL,GPIO(BUSVOODOO_XVEN_PIN));// set pin as output (push-pull, pulled low for safety)
gpio_clear(GPIO(BUSVOODOO_12VEN_PORT),GPIO(BUSVOODOO_12VEN_PIN));// disable 12V voltage regulator
gpio_set_mode(GPIO(BUSVOODOO_12VEN_PORT),GPIO_MODE_OUTPUT_2_MHZ,GPIO_CNF_OUTPUT_PUSHPULL,GPIO(BUSVOODOO_12VEN_PIN));// set pin as output (push-pull, pulled low for safety)
// disable embedded pull-ups
gpio_primary_remap(AFIO_MAPR_SWJ_CFG_JTAG_OFF_SW_ON,0);// disable JTAG (but keep SWD) so to use the underlying GPIOs (PA15, PB3, PB4)
gpio_set(GPIO(BUSVOODOO_5VPULLUP_PORT),GPIO(BUSVOODOO_5VPULLUP_PIN));// set pin high to disable 5V embedded pull-up
gpio_set_mode(GPIO(BUSVOODOO_5VPULLUP_PORT),GPIO_MODE_OUTPUT_2_MHZ,GPIO_CNF_OUTPUT_OPENDRAIN,GPIO(BUSVOODOO_5VPULLUP_PIN));// set pin as output (open-drain pulled high to disable the pMOS)
gpio_set(GPIO(BUSVOODOO_XVPULLUP_PORT),GPIO(BUSVOODOO_XVPULLUP_PIN));// set pin high to disable xV embedded pull-up
gpio_set_mode(GPIO(BUSVOODOO_XVPULLUP_PORT),GPIO_MODE_OUTPUT_2_MHZ,GPIO_CNF_OUTPUT_OPENDRAIN,GPIO(BUSVOODOO_XVPULLUP_PIN));// set pin as output (open-drain pulled high to disable the pMOS)
printf("this is not a high-density device: a wrong micro-controller might have been used\n");
#if DEBUG
#else
gotoerror;
#endif
}
// ensure flash size is ok
if(0xffff==DESIG_FLASH_SIZE){
printf("unknown flash size: this is probably a defective micro-controller\n");
#if DEBUG
#else
gotoerror;
#endif
}
// check 5V power rail
floatvoltage=rail_voltage(BUSVOODOO_5V_CHANNEL);// get 5V power rail voltage
if(voltage<4.0){
printf("5V power rail voltage is too low: %d.%02uV, check USB port\n",(int32_t)voltage,(uint32_t)((voltage-(int32_t)voltage)*100));
#if DEBUG
while(true);
#else
gotoerror;
#endif
}elseif(voltage>5.5){
printf("5V power rail voltage is too high: %d.%02uV, check USB port\n",(int32_t)voltage,(uint32_t)((voltage-(int32_t)voltage)*100));
#if DEBUG
while(true);
#else
gotoerror;
#endif
}
// check 3.3V power rail
voltage=rail_voltage(BUSVOODOO_3V3_CHANNEL);// get 3.3V power rail voltage
if(voltage<3.0){
printf("3.3V power rail voltage is too low: %d.%02uV, check OLED connector and voltage regulator\n",(int32_t)voltage,(uint32_t)((voltage-(int32_t)voltage)*100));
#if DEBUG
while(true);
#else
gotoerror;
#endif
}elseif(voltage>3.6){
printf("3.3V power rail voltage is too high: %d.%02uV, check OLED connector and voltage regulator\n",(int32_t)voltage,(uint32_t)((voltage-(int32_t)voltage)*100));
#if DEBUG
while(true);
#else
gotoerror;
#endif
}
// check xV voltage regulator
gpio_set(GPIO(BUSVOODOO_XVEN_PORT),GPIO(BUSVOODOO_XVEN_PIN));// enable xV voltage regulator
sleep_ms(1);// let the voltage regulator start and voltage settle
voltage=rail_voltage(BUSVOODOO_XV_CHANNEL);// get xV voltage
// without being driven it should be around the default voltage
if(voltage<BUSVOODOO_XV_DEFAULT-0.2){
printf("xV voltage is lower than expected: %d.%02uV, check xV voltage regulator\n",(int32_t)voltage,(uint32_t)((voltage-(int32_t)voltage)*100));
#if DEBUG
while(true);
#else
gotoerror;
#endif
}elseif(voltage>BUSVOODOO_XV_DEFAULT+0.2){
printf("xV voltage is too high: %d.%02uV, check xV voltage regulator\n",(int32_t)voltage,(uint32_t)((voltage-(int32_t)voltage)*100));
#if DEBUG
while(true);
#else
gotoerror;
#endif
}
// check if we can control xV
voltage=rail_voltage(BUSVOODOO_3V3_CHANNEL);// get reference voltage
if(isnan(voltage)){
printf("can get 3V3 rail voltage");
gotoerror;
}
uint16_tdac_set=BUSVOODOO_XV_SET(BUSVOODOO_XV_TEST)/voltage*4095;// DAC value corresponding to the voltage
dac_load_data_buffer_single(dac_set,RIGHT12,BUSVOOFOO_XVCTL_CHANNEL);// set output so the voltage regulator is set to 2.5V
dac_software_trigger(BUSVOOFOO_XVCTL_CHANNEL);// transfer the value to the DAC
dac_enable(BUSVOOFOO_XVCTL_CHANNEL);// enable DAC
sleep_ms(5);// let voltage settle
voltage=rail_voltage(BUSVOODOO_XV_CHANNEL);// get xV voltage
// check if it matched desired voltage
if(voltage<-BUSVOODOO_XV_TEST-0.2){
printf("xV voltage is too low: %d.%02uV, check xV voltage regulator\n",(int32_t)voltage,(uint32_t)((voltage-(int32_t)voltage)*100));
#if DEBUG
while(true);
#else
gotoerror;
#endif
}elseif(voltage>BUSVOODOO_XV_TEST+0.2){
printf("xV voltage is too high: %d.%02uV, check xV voltage regulator\n",(int32_t)voltage,(uint32_t)((voltage-(int32_t)voltage)*100));
#if DEBUG
while(true);
#else
gotoerror;
#endif
}
dac_disable(BUSVOOFOO_XVCTL_CHANNEL);// disable xV control
gpio_clear(GPIO(BUSVOODOO_XVEN_PORT),GPIO(BUSVOODOO_XVEN_PIN));// disable xV voltage regulator
sleep_ms(1);// let voltage settle
// check 12V voltage regulator
gpio_set(GPIO(BUSVOODOO_12VEN_PORT),GPIO(BUSVOODOO_12VEN_PIN));// enable 12V voltage regulator
sleep_ms(1);// let the voltage regulator start and voltage settle
voltage=rail_voltage(BUSVOODOO_12V_CHANNEL);// get 12V voltage
// without being driven it should be around the default voltage
if(voltage<BUSVOODOO_12V_DEFAULT-0.3){
printf("12V voltage is lower than expected: %d.%02uV, check 12V voltage regulator\n",(int32_t)voltage,(uint32_t)((voltage-(int32_t)voltage)*100));
#if DEBUG
while(true);
#else
gotoerror;
#endif
}elseif(voltage>BUSVOODOO_12V_DEFAULT+0.3){
printf("12V voltage is too high: %d.%02uV, check 12V voltage regulator\n",(int32_t)voltage,(uint32_t)((voltage-(int32_t)voltage)*100));
#if DEBUG
while(true);
#else
gotoerror;
#endif
}
// check if we can control 12V voltage regulator
voltage=rail_voltage(BUSVOODOO_3V3_CHANNEL);// get reference voltage
if(isnan(voltage)){
printf("can get 3V3 rail voltage");
gotoerror;
}
dac_set=BUSVOODOO_12V_SET(BUSVOODOO_12V_TEST)/voltage*4095;// DAC value corresponding to the voltage
dac_load_data_buffer_single(dac_set,RIGHT12,BUSVOOFOO_12VCTL_CHANNEL);// set output so the voltage regulator is set to desired output voltage
dac_software_trigger(BUSVOOFOO_12VCTL_CHANNEL);// transfer the value to the DAC
printf("signal %s of I/O-%u is low while it should be set high by signal %s of I/O-%u\n",busvoodoo_io_names[pin2],busvoodoo_io_groups[pin2],busvoodoo_io_names[pin1],busvoodoo_io_groups[pin1]);// warn user about the error
// this does not apply to v0.001 because of a design error
// printf("signal %s of I/O-%u is high while it should not be set high by signal %s of I/O-%u\n", busvoodoo_io_names[pin2], busvoodoo_io_groups[pin2], busvoodoo_io_names[pin1], busvoodoo_io_groups[pin1]); // warn user about the error
#if DEBUG
// while (true);
#else
// goto error;
#endif
}
}
gpio_set_mode(busvoodoo_io_ports[pin1],GPIO_MODE_INPUT,GPIO_CNF_INPUT_PULL_UPDOWN,busvoodoo_io_pins[pin1]);// set pin back to input
gpio_clear(busvoodoo_io_ports[pin1],busvoodoo_io_pins[pin1]);// pull pin back down
}
// set individual pin low and ensure only pins in the same group are at the same level
printf("signal %s of I/O-%u is high while it should be set low by signal %s of I/O-%u\n",busvoodoo_io_names[pin2],busvoodoo_io_groups[pin2],busvoodoo_io_names[pin1],busvoodoo_io_groups[pin1]);// warn user about the error
// this does not apply to v0.001 because of a design error
// printf("signal %s of I/O-%u is low while it should not be set low by signal %s of I/O-%u\n", busvoodoo_io_names[pin2], busvoodoo_io_groups[pin2], busvoodoo_io_names[pin1], busvoodoo_io_groups[pin1]); // warn user about the error
#if DEBUG
// while (true);
#else
// goto error;
#endif
}
}
gpio_set_mode(busvoodoo_io_ports[pin1],GPIO_MODE_INPUT,GPIO_CNF_INPUT_PULL_UPDOWN,busvoodoo_io_pins[pin1]);// set pin back to input
gpio_clear(busvoodoo_io_ports[pin1],busvoodoo_io_pins[pin1]);// pull pin back down
printf("check pin 4 on I/O connector to verify xV output, it should be switched off\n");
if(!wait_space()){
gotoend;
}
gpio_set(GPIO(BUSVOODOO_XVEN_PORT),GPIO(BUSVOODOO_XVEN_PIN));// enable xV voltage regulator
printf("check pin 4 on I/O connector to verify xV output, it should be switched at 3.4V\n");
if(!wait_space()){
gotoend;
}
gpio_clear(GPIO(BUSVOODOO_XVEN_PORT),GPIO(BUSVOODOO_XVEN_PIN));// disable xV voltage regulator
// test I/O pins
for(uint8_tio=1;io<=6;io++){// test each I/O pin
for(uint8_tpin=0;pin<LENGTH(busvoodoo_io_ports)&&pin<LENGTH(busvoodoo_io_pins)&&pin<LENGTH(busvoodoo_io_groups);pin++){// look for a pin mapped on this I/O
if(busvoodoo_io_groups[pin]==io){
gpio_set_mode(busvoodoo_io_ports[pin],GPIO_MODE_OUTPUT_2_MHZ,GPIO_CNF_OUTPUT_PUSHPULL,busvoodoo_io_pins[pin]);// set pin to output
gpio_clear(busvoodoo_io_ports[pin],busvoodoo_io_pins[pin]);// set pin low
printf("check pin %u on I/O connector to verify output, it should be low\n",4+io);
if(!wait_space()){
gotoend;
}
gpio_set(busvoodoo_io_ports[pin],busvoodoo_io_pins[pin]);// set pin high
printf("check pin %u on I/O connector to verify output, it should be high\n",4+io);
if(!wait_space()){
gotoend;
}
gpio_set_mode(busvoodoo_io_ports[pin],GPIO_MODE_INPUT,GPIO_CNF_INPUT_FLOAT,busvoodoo_io_pins[pin]);// set pin back to input
// enable all GPIO domains since we use pins on all ports
rcc_periph_clock_enable(RCC_GPIOA);// enable clock for all GPIO domains
rcc_periph_clock_enable(RCC_GPIOB);// enable clock for all GPIO domains
rcc_periph_clock_enable(RCC_GPIOC);// enable clock for all GPIO domains
rcc_periph_clock_enable(RCC_GPIOD);// enable clock for all GPIO domains
safe_state();// switch off all outputs
// setup ADC to measure the 5V, 3.3V, xV, and 12V power rails voltages
rcc_periph_clock_enable(RCC_ADC12_IN(BUSVOODOO_5V_CHANNEL));// enable clock for GPIO domain for 5V channel
gpio_set_mode(ADC12_IN_PORT(BUSVOODOO_5V_CHANNEL),GPIO_MODE_INPUT,GPIO_CNF_INPUT_ANALOG,ADC12_IN_PIN(BUSVOODOO_5V_CHANNEL));// set 5V channel as analogue input for the ADC
rcc_periph_clock_enable(RCC_ADC12_IN(BUSVOODOO_3V3_CHANNEL));// enable clock for GPIO domain for 3.3V channel
gpio_set_mode(ADC12_IN_PORT(BUSVOODOO_3V3_CHANNEL),GPIO_MODE_INPUT,GPIO_CNF_INPUT_ANALOG,ADC12_IN_PIN(BUSVOODOO_3V3_CHANNEL));// set 3.3V channel as analogue input for the ADC
rcc_periph_clock_enable(RCC_ADC12_IN(BUSVOODOO_XV_CHANNEL));// enable clock for GPIO domain for xV channel
gpio_set_mode(ADC12_IN_PORT(BUSVOODOO_XV_CHANNEL),GPIO_MODE_INPUT,GPIO_CNF_INPUT_ANALOG,ADC12_IN_PIN(BUSVOODOO_XV_CHANNEL));// set xV channel as analogue input for the ADC
rcc_periph_clock_enable(RCC_ADC12_IN(BUSVOODOO_12V_CHANNEL));// enable clock for GPIO domain for 12V channel
gpio_set_mode(ADC12_IN_PORT(BUSVOODOO_12V_CHANNEL),GPIO_MODE_INPUT,GPIO_CNF_INPUT_ANALOG,ADC12_IN_PIN(BUSVOODOO_12V_CHANNEL));// set 12V channel as analogue input for the ADC
rcc_periph_clock_enable(RCC_ADC1);// enable clock for ADC domain
adc_off(ADC1);// switch off ADC while configuring it
adc_set_sample_time_on_all_channels(ADC1,ADC_SMPR_SMP_28DOT5CYC);// use 28.5 cycles to sample (long enough to be stable)
adc_enable_temperature_sensor(ADC1);// enable internal voltage reference
adc_enable_external_trigger_regular(ADC1,ADC_CR2_EXTSEL_SWSTART);// use software trigger to start conversion
uint8_tchannels[]={ADC_CHANNEL17,ADC_CHANNEL(BUSVOODOO_5V_CHANNEL),ADC_CHANNEL(BUSVOODOO_3V3_CHANNEL),ADC_CHANNEL(BUSVOODOO_XV_CHANNEL),ADC_CHANNEL(BUSVOODOO_12V_CHANNEL)};// voltages to convert: internal, 5V, 3.3V, xV, 12V
adc_set_regular_sequence(ADC1,LENGTH(channels),channels);// set channels to convert
adc_enable_discontinuous_mode_regular(ADC1,LENGTH(channels));// convert all channels
adc_power_on(ADC1);// switch on ADC
sleep_us(1);// wait t_stab for the ADC to stabilize